msg error 5 getting session names

本指南详细介绍了在另一台PC上使用专业版或终极版操作系统发送消息的方法,包括注册表备份、配置远程RPC、添加Windows凭据等步骤,确保操作顺利进行。

to send a message to another pc, first you must be using professional version or ultimate version.
assuming that you do,
before you do this, back up your system. messing with the registry files is a risky business

First, in the search box in the start menu, type in regedit. double click hkey_local machine, then system, then CurrentControlSet, then Control, then terminal server, and finally in the window on the right, double click AllowRemoteRPC. Change the value data to 1 and then click ok

 Second, in the start menu search box, type credential manager. In credential Manager click on add a Windows Credential. The top box wants the name of the remote computer. the second box wants the username that you will be messaging. the third box wants the password of the username of the remote computer.

Third, restart your computer

Fourth, you should be ready to send a message. Open a command prompt window. type msg /server nameofremotepchere usernamehere messagehere

good luck

ps the error 5 is because of the hkey problem, in case you want to know
 
/** * MIT License * * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui <mohabouje@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "wintoastlib.h" #include <memory> #include <assert.h> #include <unordered_map> #include <array> #include <functional> #pragma comment(lib, "shlwapi") #pragma comment(lib, "user32") #define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\" #define DEFAULT_LINK_FORMAT L".lnk" #define STATUS_SUCCESS (0x00000000) #ifdef NDEBUG static bool DebugOutputEnabled = false; #else static bool DebugOutputEnabled = true; #endif #define DEBUG_MSG(str) \ do { \ if (DebugOutputEnabled) { \ std::wcout << str << std::endl; \ } \ } while (false) // Quickstart: Handling toast activations from Win32 apps in Windows 10 // https://blogs.msdn.microsoft.com/tiles_and_toasts/2015/10/16/quickstart-handling-toast-activations-from-win32-apps-in-windows-10/ using namespace WinToastLib; void WinToastLib::setDebugOutputEnabled(bool enabled) { DebugOutputEnabled = enabled; } namespace DllImporter { // Function load a function from library template <typename Function> HRESULT loadFunctionFromLibrary(HINSTANCE library, LPCSTR name, Function& func) { if (!library) { return E_INVALIDARG; } func = reinterpret_cast<Function>(GetProcAddress(library, name)); return (func != nullptr) ? S_OK : E_FAIL; } typedef HRESULT(FAR STDAPICALLTYPE* f_SetCurrentProcessExplicitAppUserModelID)(__in PCWSTR AppID); typedef HRESULT(FAR STDAPICALLTYPE* f_PropVariantToString)(_In_ REFPROPVARIANT propvar, _Out_writes_(cch) PWSTR psz, _In_ UINT cch); typedef HRESULT(FAR STDAPICALLTYPE* f_RoGetActivationFactory)(_In_ HSTRING activatableClassId, _In_ REFIID iid, _COM_Outptr_ void** factory); typedef HRESULT(FAR STDAPICALLTYPE* f_WindowsCreateStringReference)(_In_reads_opt_(length + 1) PCWSTR sourceString, UINT32 length, _Out_ HSTRING_HEADER* hstringHeader, _Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING* string); typedef PCWSTR(FAR STDAPICALLTYPE* f_WindowsGetStringRawBuffer)(_In_ HSTRING string, _Out_opt_ UINT32* length); typedef HRESULT(FAR STDAPICALLTYPE* f_WindowsDeleteString)(_In_opt_ HSTRING string); static f_SetCurrentProcessExplicitAppUserModelID SetCurrentProcessExplicitAppUserModelID; static f_PropVariantToString PropVariantToString; static f_RoGetActivationFactory RoGetActivationFactory; static f_WindowsCreateStringReference WindowsCreateStringReference; static f_WindowsGetStringRawBuffer WindowsGetStringRawBuffer; static f_WindowsDeleteString WindowsDeleteString; template <class T> __inline _Check_return_ HRESULT _1_GetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ T** factory) { return RoGetActivationFactory(activatableClassId, IID_INS_ARGS(factory)); } template <typename T> inline HRESULT Wrap_GetActivationFactory(_In_ HSTRING activatableClassId, _Inout_ Details::ComPtrRef<T> factory) noexcept { return _1_GetActivationFactory(activatableClassId, factory.ReleaseAndGetAddressOf()); } inline HRESULT initialize() { HINSTANCE LibShell32 = LoadLibraryW(L"SHELL32.DLL"); HRESULT hr = loadFunctionFromLibrary(LibShell32, "SetCurrentProcessExplicitAppUserModelID", SetCurrentProcessExplicitAppUserModelID); if (SUCCEEDED(hr)) { HINSTANCE LibPropSys = LoadLibraryW(L"PROPSYS.DLL"); hr = loadFunctionFromLibrary(LibPropSys, "PropVariantToString", PropVariantToString); if (SUCCEEDED(hr)) { HINSTANCE LibComBase = LoadLibraryW(L"COMBASE.DLL"); bool const succeded = SUCCEEDED(loadFunctionFromLibrary(LibComBase, "RoGetActivationFactory", RoGetActivationFactory)) && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsCreateStringReference", WindowsCreateStringReference)) && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsGetStringRawBuffer", WindowsGetStringRawBuffer)) && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsDeleteString", WindowsDeleteString)); return succeded ? S_OK : E_FAIL; } } return hr; } } // namespace DllImporter class WinToastStringWrapper { public: WinToastStringWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) { HRESULT hr = DllImporter::WindowsCreateStringReference(stringRef, length, &_header, &_hstring); if (!SUCCEEDED(hr)) { RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), 0, 0, nullptr); } } WinToastStringWrapper(_In_ std::wstring const& stringRef) { HRESULT hr = DllImporter::WindowsCreateStringReference(stringRef.c_str(), static_cast<UINT32>(stringRef.length()), &_header, &_hstring); if (FAILED(hr)) { RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), 0, 0, nullptr); } } ~WinToastStringWrapper() { DllImporter::WindowsDeleteString(_hstring); } inline HSTRING Get() const noexcept { return _hstring; } private: HSTRING _hstring; HSTRING_HEADER _header; }; class InternalDateTime : public IReference<DateTime> { public: static INT64 Now() { FILETIME now; GetSystemTimeAsFileTime(&now); return ((((INT64) now.dwHighDateTime) << 32) | now.dwLowDateTime); } InternalDateTime(DateTime dateTime) : _dateTime(dateTime) {} InternalDateTime(INT64 millisecondsFromNow) { _dateTime.UniversalTime = Now() + millisecondsFromNow * 10000; } virtual ~InternalDateTime() = default; operator INT64() { return _dateTime.UniversalTime; } HRESULT STDMETHODCALLTYPE get_Value(DateTime* dateTime) { *dateTime = _dateTime; return S_OK; } HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObject) { if (!ppvObject) { return E_POINTER; } if (riid == __uuidof(IUnknown) || riid == __uuidof(IReference<DateTime>)) { *ppvObject = static_cast<IUnknown*>(static_cast<IReference<DateTime>*>(this)); return S_OK; } return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE Release() { return 1; } ULONG STDMETHODCALLTYPE AddRef() { return 2; } HRESULT STDMETHODCALLTYPE GetIids(ULONG*, IID**) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING*) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel*) { return E_NOTIMPL; } protected: DateTime _dateTime; }; namespace Util { typedef LONG NTSTATUS, *PNTSTATUS; typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); inline RTL_OSVERSIONINFOW getRealOSVersion() { HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); if (hMod) { RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); if (fxPtr != nullptr) { RTL_OSVERSIONINFOW rovi = {0}; rovi.dwOSVersionInfoSize = sizeof(rovi); if (STATUS_SUCCESS == fxPtr(&rovi)) { return rovi; } } } RTL_OSVERSIONINFOW rovi = {0}; return rovi; } inline HRESULT defaultExecutablePath(_In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { DWORD written = GetModuleFileNameExW(GetCurrentProcess(), nullptr, path, nSize); DEBUG_MSG("Default executable path: " << path); return (written > 0) ? S_OK : E_FAIL; } inline HRESULT defaultShellLinksDirectory(_In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { DWORD written = GetEnvironmentVariableW(L"APPDATA", path, nSize); HRESULT hr = written > 0 ? S_OK : E_INVALIDARG; if (SUCCEEDED(hr)) { errno_t result = wcscat_s(path, nSize, DEFAULT_SHELL_LINKS_PATH); hr = (result == 0) ? S_OK : E_INVALIDARG; DEBUG_MSG("Default shell link path: " << path); } return hr; } inline HRESULT defaultShellLinkPath(_In_ std::wstring const& appname, _In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { HRESULT hr = defaultShellLinksDirectory(path, nSize); if (SUCCEEDED(hr)) { std::wstring const appLink(appname + DEFAULT_LINK_FORMAT); errno_t result = wcscat_s(path, nSize, appLink.c_str()); hr = (result == 0) ? S_OK : E_INVALIDARG; DEBUG_MSG("Default shell link file path: " << path); } return hr; } inline std::wstring parentDirectory(WCHAR* path, DWORD size) { size_t lastSeparator = 0; for (size_t i = 0; i < size; i++) { if (path[i] == L'\\' || path[i] == L'/') { lastSeparator = i; } } return {path, lastSeparator}; } inline PCWSTR AsString(_In_ ComPtr<IXmlDocument>& xmlDocument) { HSTRING xml; ComPtr<IXmlNodeSerializer> ser; HRESULT hr = xmlDocument.As<IXmlNodeSerializer>(&ser); hr = ser->GetXml(&xml); if (SUCCEEDED(hr)) { return DllImporter::WindowsGetStringRawBuffer(xml, nullptr); } return nullptr; } inline PCWSTR AsString(_In_ HSTRING hstring) { return DllImporter::WindowsGetStringRawBuffer(hstring, nullptr); } inline HRESULT setNodeStringValue(_In_ std::wstring const& string, _Out_opt_ IXmlNode* node, _Out_ IXmlDocument* xml) { ComPtr<IXmlText> textNode; HRESULT hr = xml->CreateTextNode(WinToastStringWrapper(string).Get(), &textNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> stringNode; hr = textNode.As(&stringNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = node->AppendChild(stringNode.Get(), &appendedChild); } } return hr; } template <typename FunctorT> inline HRESULT setEventHandlers(_In_ IToastNotification* notification, _In_ std::shared_ptr<IWinToastHandler> eventHandler, _In_ INT64 expirationTime, _Out_ EventRegistrationToken& activatedToken, _Out_ EventRegistrationToken& dismissedToken, _Out_ EventRegistrationToken& failedToken, _In_ FunctorT&& markAsReadyForDeletionFunc) { HRESULT hr = notification->add_Activated( Callback<Implements<RuntimeClassFlags<ClassicCom>, ITypedEventHandler<ToastNotification*, IInspectable*>>>( [eventHandler, markAsReadyForDeletionFunc](IToastNotification* notify, IInspectable* inspectable) { ComPtr<IToastActivatedEventArgs> activatedEventArgs; HRESULT hr = inspectable->QueryInterface(activatedEventArgs.GetAddressOf()); if (SUCCEEDED(hr)) { HSTRING argumentsHandle; hr = activatedEventArgs->get_Arguments(&argumentsHandle); if (SUCCEEDED(hr)) { PCWSTR arguments = Util::AsString(argumentsHandle); if (wcscmp(arguments, L"action=reply") == 0) { ComPtr<IToastActivatedEventArgs2> inputBoxActivatedEventArgs; HRESULT hr2 = inspectable->QueryInterface(inputBoxActivatedEventArgs.GetAddressOf()); if (SUCCEEDED(hr2)) { ComPtr<Collections::IPropertySet> replyHandle; inputBoxActivatedEventArgs->get_UserInput(&replyHandle); ComPtr<__FIMap_2_HSTRING_IInspectable> replyMap; hr = replyHandle.As(&replyMap); if (SUCCEEDED(hr)) { IInspectable* propertySet; hr = replyMap.Get()->Lookup(WinToastStringWrapper(L"textBox").Get(), &propertySet); if (SUCCEEDED(hr)) { ComPtr<IPropertyValue> propertyValue; hr = propertySet->QueryInterface(IID_PPV_ARGS(&propertyValue)); if (SUCCEEDED(hr)) { // Successfully queried IPropertyValue, now extract the value HSTRING userInput; hr = propertyValue->GetString(&userInput); if (SUCCEEDED(hr)) { // Convert the HSTRING to a wide string PCWSTR strValue = Util::AsString(userInput); eventHandler->toastActivated(std::wstring(strValue)); DllImporter::WindowsDeleteString(userInput); return S_OK; } if (userInput != nullptr) { DllImporter::WindowsDeleteString(userInput); } } } } } } if (arguments && *arguments) { eventHandler->toastActivated(static_cast<long>(wcstol(arguments, nullptr, 10))); DllImporter::WindowsDeleteString(argumentsHandle); markAsReadyForDeletionFunc(); return S_OK; } DllImporter::WindowsDeleteString(argumentsHandle); } } eventHandler->toastActivated(); markAsReadyForDeletionFunc(); return S_OK; }) .Get(), &activatedToken); if (SUCCEEDED(hr)) { hr = notification->add_Dismissed( Callback<Implements<RuntimeClassFlags<ClassicCom>, ITypedEventHandler<ToastNotification*, ToastDismissedEventArgs*>>>( [eventHandler, expirationTime, markAsReadyForDeletionFunc](IToastNotification* notify, IToastDismissedEventArgs* e) { ToastDismissalReason reason; if (SUCCEEDED(e->get_Reason(&reason))) { if (reason == ToastDismissalReason_UserCanceled && expirationTime && InternalDateTime::Now() >= expirationTime) { reason = ToastDismissalReason_TimedOut; } eventHandler->toastDismissed(static_cast<IWinToastHandler::WinToastDismissalReason>(reason)); } markAsReadyForDeletionFunc(); return S_OK; }) .Get(), &dismissedToken); if (SUCCEEDED(hr)) { hr = notification->add_Failed( Callback<Implements<RuntimeClassFlags<ClassicCom>, ITypedEventHandler<ToastNotification*, ToastFailedEventArgs*>>>( [eventHandler, markAsReadyForDeletionFunc](IToastNotification* notify, IToastFailedEventArgs* e) { eventHandler->toastFailed(); markAsReadyForDeletionFunc(); return S_OK; }) .Get(), &failedToken); } } return hr; } inline HRESULT addAttribute(_In_ IXmlDocument* xml, std::wstring const& name, IXmlNamedNodeMap* attributeMap) { ComPtr<ABI::Windows::Data::Xml::Dom::IXmlAttribute> srcAttribute; HRESULT hr = xml->CreateAttribute(WinToastStringWrapper(name).Get(), &srcAttribute); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = srcAttribute.As(&node); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> pNode; hr = attributeMap->SetNamedItem(node.Get(), &pNode); } } return hr; } inline HRESULT createElement(_In_ IXmlDocument* xml, _In_ std::wstring const& root_node, _In_ std::wstring const& element_name, _In_ std::vector<std::wstring> const& attribute_names) { ComPtr<IXmlNodeList> rootList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(root_node).Get(), &rootList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> root; hr = rootList->Item(0, &root); if (SUCCEEDED(hr)) { ComPtr<ABI::Windows::Data::Xml::Dom::IXmlElement> audioElement; hr = xml->CreateElement(WinToastStringWrapper(element_name).Get(), &audioElement); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> audioNodeTmp; hr = audioElement.As(&audioNodeTmp); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> audioNode; hr = root->AppendChild(audioNodeTmp.Get(), &audioNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = audioNode->get_Attributes(&attributes); if (SUCCEEDED(hr)) { for (auto const& it : attribute_names) { hr = addAttribute(xml, it, attributes.Get()); } } } } } } } return hr; } } // namespace Util WinToast* WinToast::instance() { thread_local static WinToast instance; return &instance; } WinToast::WinToast() : _isInitialized(false), _hasCoInitialized(false) { if (!isCompatible()) { DEBUG_MSG(L"Warning: Your system is not compatible with this library "); } } WinToast::~WinToast() { clear(); if (_hasCoInitialized) { CoUninitialize(); } } void WinToast::setAppName(_In_ std::wstring const& appName) { _appName = appName; } void WinToast::setAppUserModelId(_In_ std::wstring const& aumi) { _aumi = aumi; DEBUG_MSG(L"Default App User Model Id: " << _aumi.c_str()); } void WinToast::setShortcutPolicy(_In_ ShortcutPolicy shortcutPolicy) { _shortcutPolicy = shortcutPolicy; } bool WinToast::isCompatible() { DllImporter::initialize(); return !((DllImporter::SetCurrentProcessExplicitAppUserModelID == nullptr) || (DllImporter::PropVariantToString == nullptr) || (DllImporter::RoGetActivationFactory == nullptr) || (DllImporter::WindowsCreateStringReference == nullptr) || (DllImporter::WindowsDeleteString == nullptr)); } bool WinToastLib::WinToast::isSupportingModernFeatures() { constexpr auto MinimumSupportedVersion = 6; return Util::getRealOSVersion().dwMajorVersion > MinimumSupportedVersion; } bool WinToastLib::WinToast::isWin10AnniversaryOrHigher() { return Util::getRealOSVersion().dwBuildNumber >= 14393; } std::wstring WinToast::configureAUMI(_In_ std::wstring const& companyName, _In_ std::wstring const& productName, _In_ std::wstring const& subProduct, _In_ std::wstring const& versionInformation) { std::wstring aumi = companyName; aumi += L"." + productName; if (subProduct.length() > 0) { aumi += L"." + subProduct; if (versionInformation.length() > 0) { aumi += L"." + versionInformation; } } if (aumi.length() > SCHAR_MAX) { DEBUG_MSG("Error: max size allowed for AUMI: 128 characters."); } return aumi; } std::wstring const& WinToast::strerror(WinToastError error) { static std::unordered_map<WinToastError, std::wstring> const Labels = { {WinToastError::NoError, L"No error. The process was executed correctly" }, {WinToastError::NotInitialized, L"The library has not been initialized" }, {WinToastError::SystemNotSupported, L"The OS does not support WinToast" }, {WinToastError::ShellLinkNotCreated, L"The library was not able to create a Shell Link for the app" }, {WinToastError::InvalidAppUserModelID, L"The AUMI is not a valid one" }, {WinToastError::InvalidParameters, L"Invalid parameters, please double-check the AUMI or App Name" }, {WinToastError::NotDisplayed, L"The toast was created correctly but WinToast was not able to display the toast"}, {WinToastError::UnknownError, L"Unknown error" } }; auto const iter = Labels.find(error); assert(iter != Labels.end()); return iter->second; } enum WinToast::ShortcutResult WinToast::createShortcut() { if (_aumi.empty() || _appName.empty()) { DEBUG_MSG(L"Error: App User Model Id or Appname is empty!"); return SHORTCUT_MISSING_PARAMETERS; } if (!isCompatible()) { DEBUG_MSG(L"Your OS is not compatible with this library! =("); return SHORTCUT_INCOMPATIBLE_OS; } if (!_hasCoInitialized) { HRESULT initHr = CoInitializeEx(nullptr, COINIT::COINIT_MULTITHREADED); if (initHr != RPC_E_CHANGED_MODE) { if (FAILED(initHr) && initHr != S_FALSE) { DEBUG_MSG(L"Error on COM library initialization!"); return SHORTCUT_COM_INIT_FAILURE; } else { _hasCoInitialized = true; } } } bool wasChanged; HRESULT hr = validateShellLinkHelper(wasChanged); if (SUCCEEDED(hr)) { return wasChanged ? SHORTCUT_WAS_CHANGED : SHORTCUT_UNCHANGED; } hr = createShellLinkHelper(); return SUCCEEDED(hr) ? SHORTCUT_WAS_CREATED : SHORTCUT_CREATE_FAILED; } bool WinToast::initialize(_Out_opt_ WinToastError* error) { _isInitialized = false; setError(error, WinToastError::NoError); if (!isCompatible()) { setError(error, WinToastError::SystemNotSupported); DEBUG_MSG(L"Error: system not supported."); return false; } if (_aumi.empty() || _appName.empty()) { setError(error, WinToastError::InvalidParameters); DEBUG_MSG(L"Error while initializing, did you set up a valid AUMI and App name?"); return false; } if (_shortcutPolicy != SHORTCUT_POLICY_IGNORE) { if (createShortcut() < 0) { setError(error, WinToastError::ShellLinkNotCreated); DEBUG_MSG(L"Error while attaching the AUMI to the current proccess =("); return false; } } if (FAILED(DllImporter::SetCurrentProcessExplicitAppUserModelID(_aumi.c_str()))) { setError(error, WinToastError::InvalidAppUserModelID); DEBUG_MSG(L"Error while attaching the AUMI to the current proccess =("); return false; } _isInitialized = true; return _isInitialized; } bool WinToast::isInitialized() const { return _isInitialized; } std::wstring const& WinToast::appName() const { return _appName; } std::wstring const& WinToast::appUserModelId() const { return _aumi; } HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { WCHAR path[MAX_PATH] = {L'\0'}; Util::defaultShellLinkPath(_appName, path); // Check if the file exist DWORD attr = GetFileAttributesW(path); if (attr >= 0xFFFFFFF) { DEBUG_MSG("Error, shell link not found. Try to create a new one in: " << path); return E_FAIL; } // Let's load the file as shell link to validate. // - Create a shell link // - Create a persistant file // - Load the path as data for the persistant file // - Read the property AUMI and validate with the current // - Review if AUMI is equal. ComPtr<IShellLink> shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (SUCCEEDED(hr)) { ComPtr<IPersistFile> persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { hr = persistFile->Load(path, STGM_READWRITE); if (SUCCEEDED(hr)) { ComPtr<IPropertyStore> propertyStore; hr = shellLink.As(&propertyStore); if (SUCCEEDED(hr)) { PROPVARIANT appIdPropVar; hr = propertyStore->GetValue(PKEY_AppUserModel_ID, &appIdPropVar); if (SUCCEEDED(hr)) { WCHAR AUMI[MAX_PATH]; hr = DllImporter::PropVariantToString(appIdPropVar, AUMI, MAX_PATH); wasChanged = false; if (FAILED(hr) || _aumi != AUMI) { if (_shortcutPolicy == SHORTCUT_POLICY_REQUIRE_CREATE) { // AUMI Changed for the same app, let's update the current value! =) wasChanged = true; PropVariantClear(&appIdPropVar); hr = InitPropVariantFromString(_aumi.c_str(), &appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->Commit(); if (SUCCEEDED(hr) && SUCCEEDED(persistFile->IsDirty())) { hr = persistFile->Save(path, TRUE); } } } } else { // Not allowed to touch the shortcut to fix the AUMI hr = E_FAIL; } } PropVariantClear(&appIdPropVar); } } } } } return hr; } HRESULT WinToast::createShellLinkHelper() { if (_shortcutPolicy != SHORTCUT_POLICY_REQUIRE_CREATE) { return E_FAIL; } WCHAR exePath[MAX_PATH]{L'\0'}; WCHAR slPath[MAX_PATH]{L'\0'}; Util::defaultShellLinkPath(_appName, slPath); Util::defaultExecutablePath(exePath); std::wstring exeDir = Util::parentDirectory(exePath, sizeof(exePath) / sizeof(exePath[0])); ComPtr<IShellLinkW> shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (SUCCEEDED(hr)) { hr = shellLink->SetPath(exePath); if (SUCCEEDED(hr)) { hr = shellLink->SetArguments(L""); if (SUCCEEDED(hr)) { hr = shellLink->SetWorkingDirectory(exeDir.c_str()); if (SUCCEEDED(hr)) { ComPtr<IPropertyStore> propertyStore; hr = shellLink.As(&propertyStore); if (SUCCEEDED(hr)) { PROPVARIANT appIdPropVar; hr = InitPropVariantFromString(_aumi.c_str(), &appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->Commit(); if (SUCCEEDED(hr)) { ComPtr<IPersistFile> persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { hr = persistFile->Save(slPath, TRUE); } } } PropVariantClear(&appIdPropVar); } } } } } } return hr; } INT64 WinToast::showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler, _Out_ WinToastError* error) { std::shared_ptr<IWinToastHandler> handler(eventHandler); setError(error, WinToastError::NoError); INT64 id = -1; if (!isInitialized()) { setError(error, WinToastError::NotInitialized); DEBUG_MSG("Error when launching the toast. WinToast is not initialized."); return id; } if (!handler) { setError(error, WinToastError::InvalidHandler); DEBUG_MSG("Error when launching the toast. Handler cannot be nullptr."); return id; } ComPtr<IToastNotificationManagerStatics> notificationManager; HRESULT hr = DllImporter::Wrap_GetActivationFactory( WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &notificationManager); if (SUCCEEDED(hr)) { ComPtr<IToastNotifier> notifier; hr = notificationManager->CreateToastNotifierWithId(WinToastStringWrapper(_aumi).Get(), &notifier); if (SUCCEEDED(hr)) { ComPtr<IToastNotificationFactory> notificationFactory; hr = DllImporter::Wrap_GetActivationFactory( WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &notificationFactory); if (SUCCEEDED(hr)) { ComPtr<IXmlDocument> xmlDocument; hr = notificationManager->GetTemplateContent(ToastTemplateType(toast.type()), &xmlDocument); if (SUCCEEDED(hr) && toast.isToastGeneric()) { hr = setBindToastGenericHelper(xmlDocument.Get()); } if (SUCCEEDED(hr)) { for (UINT32 i = 0, fieldsCount = static_cast<UINT32>(toast.textFieldsCount()); i < fieldsCount && SUCCEEDED(hr); i++) { hr = setTextFieldHelper(xmlDocument.Get(), toast.textField(WinToastTemplate::TextField(i)), i); } // Modern feature are supported Windows > Windows 10 if (SUCCEEDED(hr) && isSupportingModernFeatures()) { // Note that we do this *after* using toast.textFieldsCount() to // iterate/fill the template's text fields, since we're adding yet another text field. if (SUCCEEDED(hr) && !toast.attributionText().empty()) { hr = setAttributionTextFieldHelper(xmlDocument.Get(), toast.attributionText()); } std::array<WCHAR, 12> buf; for (std::size_t i = 0, actionsCount = toast.actionsCount(); i < actionsCount && SUCCEEDED(hr); i++) { _snwprintf_s(buf.data(), buf.size(), _TRUNCATE, L"%zd", i); hr = addActionHelper(xmlDocument.Get(), toast.actionLabel(i), buf.data()); } if (SUCCEEDED(hr)) { hr = (toast.audioPath().empty() && toast.audioOption() == WinToastTemplate::AudioOption::Default) ? hr : setAudioFieldHelper(xmlDocument.Get(), toast.audioPath(), toast.audioOption()); } if (SUCCEEDED(hr) && toast.duration() != WinToastTemplate::Duration::System) { hr = addDurationHelper(xmlDocument.Get(), (toast.duration() == WinToastTemplate::Duration::Short) ? L"short" : L"long"); } if (SUCCEEDED(hr) && toast.isInput()) { hr = addInputHelper(xmlDocument.Get()); } if (SUCCEEDED(hr)) { hr = addScenarioHelper(xmlDocument.Get(), toast.scenario()); } } else { DEBUG_MSG("Modern features (Actions/Sounds/Attributes) not supported in this os version"); } if (SUCCEEDED(hr)) { bool isWin10AnniversaryOrAbove = WinToast::isWin10AnniversaryOrHigher(); bool isCircleCropHint = isWin10AnniversaryOrAbove ? toast.isCropHintCircle() : false; hr = toast.hasImage() ? setImageFieldHelper(xmlDocument.Get(), toast.imagePath(), toast.isToastGeneric(), isCircleCropHint) : hr; if (SUCCEEDED(hr) && isWin10AnniversaryOrAbove && toast.hasHeroImage()) { hr = setHeroImageHelper(xmlDocument.Get(), toast.heroImagePath(), toast.isInlineHeroImage()); } if (SUCCEEDED(hr)) { ComPtr<IToastNotification> notification; hr = notificationFactory->CreateToastNotification(xmlDocument.Get(), &notification); if (SUCCEEDED(hr)) { INT64 expiration = 0, relativeExpiration = toast.expiration(); if (relativeExpiration > 0) { InternalDateTime expirationDateTime(relativeExpiration); expiration = expirationDateTime; hr = notification->put_ExpirationTime(&expirationDateTime); } EventRegistrationToken activatedToken, dismissedToken, failedToken; GUID guid; HRESULT hrGuid = CoCreateGuid(&guid); id = guid.Data1; if (SUCCEEDED(hr) && SUCCEEDED(hrGuid)) { hr = Util::setEventHandlers(notification.Get(), handler, expiration, activatedToken, dismissedToken, failedToken, [this, id]() { markAsReadyForDeletion(id); }); if (FAILED(hr)) { setError(error, WinToastError::InvalidHandler); } } if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) { std::lock_guard<std::mutex> lock(m_mutex); _buffer.emplace(id, NotifyData(notification, activatedToken, dismissedToken, failedToken)); DEBUG_MSG("xml: " << Util::AsString(xmlDocument)); hr = notifier->Show(notification.Get()); if (FAILED(hr)) { setError(error, WinToastError::NotDisplayed); } } } } } } } } } } return FAILED(hr) ? -1 : id; } ComPtr<IToastNotifier> WinToast::notifier(_In_ bool* succeded) const { ComPtr<IToastNotificationManagerStatics> notificationManager; ComPtr<IToastNotifier> notifier; HRESULT hr = DllImporter::Wrap_GetActivationFactory( WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &notificationManager); if (SUCCEEDED(hr)) { hr = notificationManager->CreateToastNotifierWithId(WinToastStringWrapper(_aumi).Get(), &notifier); } *succeded = SUCCEEDED(hr); return notifier; } void WinToast::markAsReadyForDeletion(_In_ INT64 id) { std::lock_guard<std::mutex> lock(m_mutex); // Flush the buffer by removing all the toasts that are ready for deletion for (auto it = _buffer.begin(); it != _buffer.end();) { if (it->second.isReadyForDeletion()) { it->second.RemoveTokens(); it = _buffer.erase(it); } else { ++it; } } // Mark the toast as ready for deletion (if it exists) so that it will be removed from the buffer in the next iteration auto const iter = _buffer.find(id); if (iter != _buffer.end()) { _buffer[id].markAsReadyForDeletion(); } } bool WinToast::hideToast(_In_ INT64 id) { std::lock_guard<std::mutex> lock(m_mutex); if (!isInitialized()) { DEBUG_MSG("Error when hiding the toast. WinToast is not initialized."); return false; } auto iter = _buffer.find(id); if (iter == _buffer.end()) { return false; } auto succeded = false; auto notify = notifier(&succeded); if (!succeded) { return false; } auto& notifyData = iter->second; auto result = notify->Hide(notifyData.notification()); if (FAILED(result)) { DEBUG_MSG("Error when hiding the toast. Error code: " << result); return false; } notifyData.RemoveTokens(); _buffer.erase(iter); return SUCCEEDED(result); } void WinToast::clear() { auto succeded = false; auto notify = notifier(&succeded); if (!succeded) { return; } std::lock_guard<std::mutex> lock(m_mutex); auto safeCopy = _buffer; for (auto& data : safeCopy) { auto& notifyData = data.second; notify->Hide(notifyData.notification()); notifyData.RemoveTokens(); } _buffer.clear(); } // // Available as of Windows 10 Anniversary Update // Ref: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts // // NOTE: This will add a new text field, so be aware when iterating over // the toast's text fields or getting a count of them. // HRESULT WinToast::setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text) { Util::createElement(xml, L"binding", L"text", {L"placement"}); ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 nodeListLength; hr = nodeList->get_Length(&nodeListLength); if (SUCCEEDED(hr)) { for (UINT32 i = 0; i < nodeListLength; i++) { ComPtr<IXmlNode> textNode; hr = nodeList->Item(i, &textNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = textNode->get_Attributes(&attributes); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> editedNode; if (SUCCEEDED(hr)) { hr = attributes->GetNamedItem(WinToastStringWrapper(L"placement").Get(), &editedNode); if (FAILED(hr) || !editedNode) { continue; } hr = Util::setNodeStringValue(L"attribution", editedNode.Get(), xml); if (SUCCEEDED(hr)) { return setTextFieldHelper(xml, text, i); } } } } } } } return hr; } HRESULT WinToast::addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"duration").Get(), WinToastStringWrapper(duration).Get()); } } } } return hr; } HRESULT WinToast::addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"scenario").Get(), WinToastStringWrapper(scenario).Get()); } } } } return hr; } HRESULT WinToast::addInputHelper(_In_ IXmlDocument* xml) { std::vector<std::wstring> attrbs; attrbs.push_back(L"id"); attrbs.push_back(L"type"); attrbs.push_back(L"placeHolderContent"); std::vector<std::wstring> attrbs2; attrbs2.push_back(L"content"); attrbs2.push_back(L"arguments"); Util::createElement(xml, L"toast", L"actions", {}); Util::createElement(xml, L"actions", L"input", attrbs); Util::createElement(xml, L"actions", L"action", attrbs2); ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"input").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> inputNode; hr = nodeList->Item(0, &inputNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = inputNode.As(&toastElement); if (SUCCEEDED(hr)) { toastElement->SetAttribute(WinToastStringWrapper(L"id").Get(), WinToastStringWrapper(L"textBox").Get()); toastElement->SetAttribute(WinToastStringWrapper(L"type").Get(), WinToastStringWrapper(L"text").Get()); hr = toastElement->SetAttribute(WinToastStringWrapper(L"placeHolderContent").Get(), WinToastStringWrapper(L"...").Get()); } } } ComPtr<IXmlNodeList> nodeList2; hr = xml->GetElementsByTagName(WinToastStringWrapper(L"action").Get(), &nodeList2); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionNode; hr = nodeList2->Item(0, &actionNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> actionElement; hr = actionNode.As(&actionElement); if (SUCCEEDED(hr)) { actionElement->SetAttribute(WinToastStringWrapper(L"content").Get(), WinToastStringWrapper(L"Reply").Get()); actionElement->SetAttribute(WinToastStringWrapper(L"arguments").Get(), WinToastStringWrapper(L"action=reply").Get()); actionElement->SetAttribute(WinToastStringWrapper(L"hint-inputId").Get(), WinToastStringWrapper(L"textBox").Get()); } } } return hr; } HRESULT WinToast::setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = nodeList->Item(pos, &node); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(text, node.Get(), xml); } } return hr; } HRESULT WinToast::setBindToastGenericHelper(_In_ IXmlDocument* xml) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"binding").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"template").Get(), WinToastStringWrapper(L"ToastGeneric").Get()); } } } } return hr; } HRESULT WinToast::setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, _In_ bool isCropHintCircle) { assert(path.size() < MAX_PATH); wchar_t imagePath[MAX_PATH] = L"file:///"; HRESULT hr = StringCchCatW(imagePath, MAX_PATH, path.c_str()); if (SUCCEEDED(hr)) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"image").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = nodeList->Item(0, &node); ComPtr<IXmlElement> imageElement; HRESULT hrImage = node.As(&imageElement); if (SUCCEEDED(hr) && SUCCEEDED(hrImage) && isToastGeneric) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"placement").Get(), WinToastStringWrapper(L"appLogoOverride").Get()); if (SUCCEEDED(hr) && isCropHintCircle) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"hint-crop").Get(), WinToastStringWrapper(L"circle").Get()); } } if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = node->get_Attributes(&attributes); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> editedNode; hr = attributes->GetNamedItem(WinToastStringWrapper(L"src").Get(), &editedNode); if (SUCCEEDED(hr)) { Util::setNodeStringValue(imagePath, editedNode.Get(), xml); } } } } } return hr; } HRESULT WinToast::setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_opt_ WinToastTemplate::AudioOption option) { std::vector<std::wstring> attrs; if (!path.empty()) { attrs.push_back(L"src"); } if (option == WinToastTemplate::AudioOption::Loop) { attrs.push_back(L"loop"); } if (option == WinToastTemplate::AudioOption::Silent) { attrs.push_back(L"silent"); } Util::createElement(xml, L"toast", L"audio", attrs); ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"audio").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = nodeList->Item(0, &node); if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = node->get_Attributes(&attributes); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> editedNode; if (!path.empty()) { if (SUCCEEDED(hr)) { hr = attributes->GetNamedItem(WinToastStringWrapper(L"src").Get(), &editedNode); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(path, editedNode.Get(), xml); } } } if (SUCCEEDED(hr)) { switch (option) { case WinToastTemplate::AudioOption::Loop: hr = attributes->GetNamedItem(WinToastStringWrapper(L"loop").Get(), &editedNode); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(L"true", editedNode.Get(), xml); } break; case WinToastTemplate::AudioOption::Silent: hr = attributes->GetNamedItem(WinToastStringWrapper(L"silent").Get(), &editedNode); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(L"true", editedNode.Get(), xml); } default: break; } } } } } return hr; } HRESULT WinToast::addActionHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& content, _In_ std::wstring const& arguments) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"actions").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionsNode; if (length > 0) { hr = nodeList->Item(0, &actionsNode); } else { hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"template").Get(), WinToastStringWrapper(L"ToastGeneric").Get()); } if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"duration").Get(), WinToastStringWrapper(L"long").Get()); } if (SUCCEEDED(hr)) { ComPtr<IXmlElement> actionsElement; hr = xml->CreateElement(WinToastStringWrapper(L"actions").Get(), &actionsElement); if (SUCCEEDED(hr)) { hr = actionsElement.As(&actionsNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = toastNode->AppendChild(actionsNode.Get(), &appendedChild); } } } } } } } if (SUCCEEDED(hr)) { ComPtr<IXmlElement> actionElement; hr = xml->CreateElement(WinToastStringWrapper(L"action").Get(), &actionElement); if (SUCCEEDED(hr)) { hr = actionElement->SetAttribute(WinToastStringWrapper(L"content").Get(), WinToastStringWrapper(content).Get()); } if (SUCCEEDED(hr)) { hr = actionElement->SetAttribute(WinToastStringWrapper(L"arguments").Get(), WinToastStringWrapper(arguments).Get()); } if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionNode; hr = actionElement.As(&actionNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = actionsNode->AppendChild(actionNode.Get(), &appendedChild); } } } } } return hr; } HRESULT WinToast::setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"binding").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> bindingNode; if (length > 0) { hr = nodeList->Item(0, &bindingNode); } if (SUCCEEDED(hr)) { ComPtr<IXmlElement> imageElement; hr = xml->CreateElement(WinToastStringWrapper(L"image").Get(), &imageElement); if (SUCCEEDED(hr) && isInlineImage == false) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"placement").Get(), WinToastStringWrapper(L"hero").Get()); } if (SUCCEEDED(hr)) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"src").Get(), WinToastStringWrapper(path).Get()); } if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionNode; hr = imageElement.As(&actionNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = bindingNode->AppendChild(actionNode.Get(), &appendedChild); } } } } } return hr; } void WinToast::setError(_Out_opt_ WinToastError* error, _In_ WinToastError value) { if (error) { *error = value; } } WinToastTemplate::WinToastTemplate(_In_ WinToastTemplateType type) : _type(type) { constexpr static std::size_t TextFieldsCount[] = {1, 2, 2, 3, 1, 2, 2, 3}; _textFields = std::vector<std::wstring>(TextFieldsCount[type], L""); } WinToastTemplate::~WinToastTemplate() { _textFields.clear(); } void WinToastTemplate::setTextField(_In_ std::wstring const& txt, _In_ WinToastTemplate::TextField pos) { auto const position = static_cast<std::size_t>(pos); if (position >= _textFields.size()) { DEBUG_MSG("The selected template type supports only " << _textFields.size() << " text lines"); return; } _textFields[position] = txt; } void WinToastTemplate::setImagePath(_In_ std::wstring const& imgPath, _In_ CropHint cropHint) { _imagePath = imgPath; _cropHint = cropHint; } void WinToastTemplate::setHeroImagePath(_In_ std::wstring const& imgPath, _In_ bool inlineImage) { _heroImagePath = imgPath; _inlineHeroImage = inlineImage; } void WinToastTemplate::setAudioPath(_In_ std::wstring const& audioPath) { _audioPath = audioPath; } void WinToastTemplate::setAudioPath(_In_ AudioSystemFile file) { static std::unordered_map<AudioSystemFile, std::wstring> const Files = { {AudioSystemFile::DefaultSound, L"ms-winsoundevent:Notification.Default" }, {AudioSystemFile::IM, L"ms-winsoundevent:Notification.IM" }, {AudioSystemFile::Mail, L"ms-winsoundevent:Notification.Mail" }, {AudioSystemFile::Reminder, L"ms-winsoundevent:Notification.Reminder" }, {AudioSystemFile::SMS, L"ms-winsoundevent:Notification.SMS" }, {AudioSystemFile::Alarm, L"ms-winsoundevent:Notification.Looping.Alarm" }, {AudioSystemFile::Alarm2, L"ms-winsoundevent:Notification.Looping.Alarm2" }, {AudioSystemFile::Alarm3, L"ms-winsoundevent:Notification.Looping.Alarm3" }, {AudioSystemFile::Alarm4, L"ms-winsoundevent:Notification.Looping.Alarm4" }, {AudioSystemFile::Alarm5, L"ms-winsoundevent:Notification.Looping.Alarm5" }, {AudioSystemFile::Alarm6, L"ms-winsoundevent:Notification.Looping.Alarm6" }, {AudioSystemFile::Alarm7, L"ms-winsoundevent:Notification.Looping.Alarm7" }, {AudioSystemFile::Alarm8, L"ms-winsoundevent:Notification.Looping.Alarm8" }, {AudioSystemFile::Alarm9, L"ms-winsoundevent:Notification.Looping.Alarm9" }, {AudioSystemFile::Alarm10, L"ms-winsoundevent:Notification.Looping.Alarm10"}, {AudioSystemFile::Call, L"ms-winsoundevent:Notification.Looping.Call" }, {AudioSystemFile::Call1, L"ms-winsoundevent:Notification.Looping.Call1" }, {AudioSystemFile::Call2, L"ms-winsoundevent:Notification.Looping.Call2" }, {AudioSystemFile::Call3, L"ms-winsoundevent:Notification.Looping.Call3" }, {AudioSystemFile::Call4, L"ms-winsoundevent:Notification.Looping.Call4" }, {AudioSystemFile::Call5, L"ms-winsoundevent:Notification.Looping.Call5" }, {AudioSystemFile::Call6, L"ms-winsoundevent:Notification.Looping.Call6" }, {AudioSystemFile::Call7, L"ms-winsoundevent:Notification.Looping.Call7" }, {AudioSystemFile::Call8, L"ms-winsoundevent:Notification.Looping.Call8" }, {AudioSystemFile::Call9, L"ms-winsoundevent:Notification.Looping.Call9" }, {AudioSystemFile::Call10, L"ms-winsoundevent:Notification.Looping.Call10" }, }; auto const iter = Files.find(file); assert(iter != Files.end()); _audioPath = iter->second; } void WinToastTemplate::setAudioOption(_In_ WinToastTemplate::AudioOption audioOption) { _audioOption = audioOption; } void WinToastTemplate::setFirstLine(_In_ std::wstring const& text) { setTextField(text, WinToastTemplate::FirstLine); } void WinToastTemplate::setSecondLine(_In_ std::wstring const& text) { setTextField(text, WinToastTemplate::SecondLine); } void WinToastTemplate::setThirdLine(_In_ std::wstring const& text) { setTextField(text, WinToastTemplate::ThirdLine); } void WinToastTemplate::setDuration(_In_ Duration duration) { _duration = duration; } void WinToastTemplate::setExpiration(_In_ INT64 millisecondsFromNow) { _expiration = millisecondsFromNow; } void WinToastLib::WinToastTemplate::setScenario(_In_ Scenario scenario) { switch (scenario) { case Scenario::Default: _scenario = L"Default"; break; case Scenario::Alarm: _scenario = L"Alarm"; break; case Scenario::IncomingCall: _scenario = L"IncomingCall"; break; case Scenario::Reminder: _scenario = L"Reminder"; break; } } void WinToastTemplate::setAttributionText(_In_ std::wstring const& attributionText) { _attributionText = attributionText; } void WinToastTemplate::addAction(_In_ std::wstring const& label) { _actions.push_back(label); } void WinToastTemplate::addInput() { _hasInput = true; } std::size_t WinToastTemplate::textFieldsCount() const { return _textFields.size(); } std::size_t WinToastTemplate::actionsCount() const { return _actions.size(); } bool WinToastTemplate::hasImage() const { return _type < WinToastTemplateType::Text01; } bool WinToastTemplate::hasHeroImage() const { return hasImage() && !_heroImagePath.empty(); } std::vector<std::wstring> const& WinToastTemplate::textFields() const { return _textFields; } std::wstring const& WinToastTemplate::textField(_In_ TextField pos) const { auto const position = static_cast<std::size_t>(pos); assert(position < _textFields.size()); return _textFields[position]; } std::wstring const& WinToastTemplate::actionLabel(_In_ std::size_t position) const { assert(position < _actions.size()); return _actions[position]; } std::wstring const& WinToastTemplate::imagePath() const { return _imagePath; } std::wstring const& WinToastTemplate::heroImagePath() const { return _heroImagePath; } std::wstring const& WinToastTemplate::audioPath() const { return _audioPath; } std::wstring const& WinToastTemplate::attributionText() const { return _attributionText; } std::wstring const& WinToastLib::WinToastTemplate::scenario() const { return _scenario; } INT64 WinToastTemplate::expiration() const { return _expiration; } WinToastTemplate::WinToastTemplateType WinToastTemplate::type() const { return _type; } WinToastTemplate::AudioOption WinToastTemplate::audioOption() const { return _audioOption; } WinToastTemplate::Duration WinToastTemplate::duration() const { return _duration; } bool WinToastTemplate::isToastGeneric() const { return hasHeroImage() || _cropHint == WinToastTemplate::Circle; } bool WinToastTemplate::isInlineHeroImage() const { return _inlineHeroImage; } bool WinToastTemplate::isCropHintCircle() const { return _cropHint == CropHint::Circle; } bool WinToastTemplate::isInput() const { return _hasInput; } 基于上述源码,新增锁屏时系统弹窗不显示在锁屏之上逻辑
最新发布
10-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值