| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | notifications.cpp |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | This file contains notification function definitions. |
| 12 | |
| 13 | --*/ |
| 14 | |
| 15 | #include "precomp.h" |
| 16 | #include <windows.ui.notifications.h> |
| 17 | #include <NotificationActivationCallback.h> |
| 18 | #include <appmodel.h> |
| 19 | #include <wrl\wrappers\corewrappers.h> |
| 20 | |
| 21 | using namespace ABI::Windows::Data::Xml::Dom; |
| 22 | using namespace ABI::Windows::UI::Notifications; |
| 23 | using namespace Microsoft::WRL; |
| 24 | using namespace Microsoft::WRL::Wrappers; |
| 25 | |
| 26 | using wsl::shared::Localization; |
| 27 | |
| 28 | namespace { |
| 29 | HRESULT CreateToastNotifier(IToastNotifier** notifier) |
| 30 | { |
| 31 | ComPtr<IToastNotificationManagerStatics> toastStatics; |
| 32 | RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory( |
| 33 | HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics)); |
| 34 | |
| 35 | return toastStatics->CreateToastNotifierWithId(HStringReference(L"Microsoft.WSL").Get(), notifier); |
| 36 | } |
| 37 | |
| 38 | HRESULT CreateXmlDocumentFromString(const wchar_t* xmlString, IXmlDocument** doc) |
| 39 | { |
| 40 | ComPtr<IXmlDocument> answer; |
| 41 | RETURN_IF_FAILED(Windows::Foundation::ActivateInstance(HStringReference(RuntimeClass_Windows_Data_Xml_Dom_XmlDocument).Get(), &answer)); |
| 42 | |
| 43 | ComPtr<IXmlDocumentIO> docIO; |
| 44 | RETURN_IF_FAILED(answer.As(&docIO)); |
| 45 | |
| 46 | RETURN_IF_FAILED(docIO->LoadXml(HStringReference(xmlString).Get())); |
| 47 | |
| 48 | return answer.CopyTo(doc); |
| 49 | } |
| 50 | |
| 51 | HRESULT CreateToastNotification(IXmlDocument* content, IToastNotification** notification) |
| 52 | { |
| 53 | ComPtr<IToastNotificationFactory> factory; |
| 54 | RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory( |
| 55 | HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &factory)); |
| 56 | |
| 57 | return factory->CreateToastNotification(content, notification); |
| 58 | } |
| 59 | |
| 60 | HRESULT DisplayNotification(IXmlDocument* doc) |
| 61 | { |
| 62 | // Create the notifier |
| 63 | // Classic Win32 apps MUST use the compat method to create the notifier |
| 64 | wil::com_ptr<IToastNotifier> notifier; |
| 65 | RETURN_IF_FAILED(CreateToastNotifier(¬ifier)); |
| 66 | |
| 67 | // Create the notification itself (using helper method from compat library) |
| 68 | wil::com_ptr<IToastNotification> toast; |
| 69 | RETURN_IF_FAILED(CreateToastNotification(doc, &toast)); |
| 70 | |
| 71 | // And show it! |
| 72 | return notifier->Show(toast.get()); |
| 73 | } |
| 74 | } // namespace |
| 75 | |
| 76 | namespace wsl::windows::common::notifications { |
| 77 | HRESULT DisplayUpdateNotification(const std::wstring& versionString) |
| 78 | try |
| 79 | { |
| 80 | const std::wstring creationString = std::format( |
| 81 | LR"(<toast> |
| 82 | <visual> |
| 83 | <binding template='ToastGeneric'> |
| 84 | <text>{}</text> |
| 85 | <text>{}</text> |
| 86 | </binding> |
| 87 | </visual> |
| 88 | <actions> |
| 89 | <action arguments='{}' content='{}'/> |
| 90 | <action arguments='{}' content='{}'/> |
| 91 | </actions> |
| 92 | </toast>)", |
| 93 | Localization::MessageNewWslVersionAvailable(Localization::Options::DontImpersonate), |
| 94 | Localization::MessageUpdateToVersion(versionString.c_str(), Localization::Options::DontImpersonate), |
| 95 | wslhost::update_arg, |
| 96 | Localization::MessageUpdate(Localization::Options::DontImpersonate), |
| 97 | wslhost::release_notes_arg, |
| 98 | Localization::MessageViewReleaseNotes(Localization::Options::DontImpersonate)); |
| 99 | |
| 100 | wil::com_ptr<IXmlDocument> doc{}; |
| 101 | THROW_IF_FAILED(CreateXmlDocumentFromString(creationString.c_str(), &doc)); |
| 102 | |
| 103 | THROW_IF_FAILED(DisplayNotification(doc.get())); |
| 104 | |
| 105 | return S_OK; |
| 106 | } |
| 107 | CATCH_RETURN() |
| 108 | |
| 109 | HRESULT DisplayFilesystemNotification(_In_ LPCSTR binaryName) |
| 110 | try |
| 111 | { |
| 112 | const std::wstring creationString = std::format( |
| 113 | LR"(<toast> |
| 114 | <visual> |
| 115 | <binding template='ToastGeneric'> |
| 116 | <text>{}</text> |
| 117 | <text>{}</text> |
| 118 | </binding> |
| 119 | </visual> |
| 120 | <actions> |
| 121 | <action arguments='{} {}' content='{}'/> |
| 122 | <action arguments='{} {}' content="{}"/> |
| 123 | </actions> |
| 124 | </toast>)", |
| 125 | Localization::MessagePerformanceTip(Localization::Options::DontImpersonate), |
| 126 | Localization::MessageProblematicDrvFsUsage(binaryName, Localization::Options::DontImpersonate), |
| 127 | wslhost::docs_arg, |
| 128 | wslhost::docs_arg_filesystem_url, |
| 129 | Localization::MessageViewDocs(Localization::Options::DontImpersonate), |
| 130 | wslhost::disable_notification_arg, |
| 131 | LXSS_NOTIFICATION_DRVFS_PERF_DISABLED, |
| 132 | Localization::MessageDontShowAgain(Localization::Options::DontImpersonate)); |
| 133 | |
| 134 | wil::com_ptr<IXmlDocument> doc{}; |
| 135 | THROW_IF_FAILED(CreateXmlDocumentFromString(creationString.c_str(), &doc)); |
| 136 | |
| 137 | THROW_IF_FAILED(DisplayNotification(doc.get())); |
| 138 | |
| 139 | return S_OK; |
| 140 | } |
| 141 | CATCH_RETURN() |
| 142 | |
| 143 | void DisplayWarningsNotification() |
| 144 | try |
| 145 | { |
| 146 | const std::wstring creationString = std::format( |
| 147 | LR"(<toast> |
| 148 | <visual> |
| 149 | <binding template='ToastGeneric'> |
| 150 | <text>{}</text> |
| 151 | </binding> |
| 152 | </visual> |
| 153 | <actions> |
| 154 | <action arguments='{}' content='{}'/> |
| 155 | </actions> |
| 156 | </toast>)", |
| 157 | Localization::MessageWarningDuringStartup(), |
| 158 | wslhost::event_viewer_arg, |
| 159 | Localization::MessageOpenEventViewer()); |
| 160 | |
| 161 | wil::com_ptr<IXmlDocument> doc{}; |
| 162 | THROW_IF_FAILED(CreateXmlDocumentFromString(creationString.c_str(), &doc)); |
| 163 | |
| 164 | THROW_IF_FAILED(DisplayNotification(doc.get())); |
| 165 | } |
| 166 | CATCH_LOG() |
| 167 | |
| 168 | void DisplayOptionalComponentsNotification() |
| 169 | try |
| 170 | { |
| 171 | const std::wstring creationString = std::format( |
| 172 | LR"(<toast> |
| 173 | <visual> |
| 174 | <binding template='ToastGeneric'> |
| 175 | <text>{}</text> |
| 176 | </binding> |
| 177 | </visual> |
| 178 | <actions> |
| 179 | <action arguments='{}' content='{}'/> |
| 180 | </actions> |
| 181 | </toast>)", |
| 182 | Localization::MessageMissingOptionalComponents(), |
| 183 | wslhost::install_prerequisites_arg, |
| 184 | Localization::MessageInstallMissingOptionalComponents()); |
| 185 | |
| 186 | wil::com_ptr<IXmlDocument> doc{}; |
| 187 | THROW_IF_FAILED(CreateXmlDocumentFromString(creationString.c_str(), &doc)); |
| 188 | |
| 189 | THROW_IF_FAILED(DisplayNotification(doc.get())); |
| 190 | } |
| 191 | CATCH_LOG() |
| 192 | |
| 193 | void DisplayProxyChangeNotification(const std::wstring& message) |
| 194 | try |
| 195 | { |
| 196 | const std::wstring creationString = |
| 197 | std::format(LR"(<toast><visual><binding template='ToastGeneric'><text>{}</text></binding></visual></toast>)", message); |
| 198 | |
| 199 | wil::com_ptr<IXmlDocument> doc{}; |
| 200 | THROW_IF_FAILED(CreateXmlDocumentFromString(creationString.c_str(), &doc)); |
| 201 | |
| 202 | THROW_IF_FAILED(DisplayNotification(doc.get())); |
| 203 | } |
| 204 | CATCH_LOG() |
| 205 | } // namespace wsl::windows::common::notifications |