Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: chrome/app/chrome_exe_main_app_win.cc

Issue 2033093003: [Notification] Make HTML5 Notification use ActionCenter on Windows 10, behind Flags. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Sync and merge. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/app/chrome_exe_main_app_win.h ('k') | chrome/app/chrome_exe_main_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/app/chrome_exe_main_app_win.h"
6
7 #include <memory>
8
9 #include "base/win/scoped_co_mem.h"
10 #include "chrome/installer/util/install_util.h"
11 #include "chrome/installer/util/shell_util.h"
12
13 // 2017/04/04: For this to work we also need
14 // HKEY_CLASSES_ROOT\CLSID\{E65AECC7-DD9B-4D14-A4ED-73A5BEF1187A}\LocalServer32
15 // to be assigned command line to launch Chrome.
16
17 #if 0
18 // #include <roapi.h>
19 // #include <wchar.h>
20 #include <NotificationActivationCallback.h>
21 #include <propvarutil.h>
22 #include <psapi.h>
23 #include <shobjidl.h>
24 #include <wrl.h>
25
26 #include <cstring>
27 #include <memory>
28 #include <string>
29
30 namespace mswr = Microsoft::WRL;
31 // namespace mswrw = Microsoft::WRL::Wrappers;
32
33 // namespace winapp = ABI::Windows::ApplicationModel;
34 // namespace winxaml = ABI::Windows::UI::Xaml;
35 // namespace winact = ABI::Windows::ApplicationModel::Activation;
36 // namespace winfoundtn = ABI::Windows::Foundation;
37 // namespace winui = ABI::Windows::UI;
38
39 #else
40
41 // #include <SDKDDKVer.h>
42 #include <Windows.h>
43 #include <Psapi.h>
44 // #include <strsafe.h>
45 #include <ShObjIdl.h>
46 #include <Shlobj.h>
47 #include <Pathcch.h>
48 #include <propvarutil.h>
49 #include <propkey.h>
50 #include <wrl.h>
51 #include <wrl\wrappers\corewrappers.h>
52 #include <windows.ui.notifications.h>
53 #include "NotificationActivationCallback.h"
54
55 // using namespace ABI::Windows::Data::Xml::Dom;
56 using namespace ABI::Windows::UI::Notifications;
57 using namespace Microsoft::WRL;
58 using namespace Microsoft::WRL::Wrappers;
59
60 #endif
61
62 namespace {
63
64 base::string16 GetChromeAppId() {
65 bool is_per_user_install = InstallUtil::IsPerUserInstall();
66 base::string16 appid = ShellUtil::GetBrowserModelId(is_per_user_install);
67 DVLOG(1) << "Chrome Appid is " << appid.c_str();
68 return appid;
69 }
70
71
72 // Name: System.AppUserModel.ToastActivatorCLSID --
73 // PKEY_AppUserModel_ToastActivatorCLSID
74 // Type: Guid -- VT_CLSID
75 // FormatID: {9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 26
76 //
77 // Used to CoCreate an INotificationActivationCallback interface to notify
78 // about toast activations.
79 EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY
80 PKEY_AppUserModel_ToastActivatorCLSID = {
81 {0x9F4C2855,
82 0x9F79,
83 0x4B39,
84 {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}},
85 26};
86
87 struct CoTaskMemStringTraits {
88 typedef PWSTR Type;
89
90 inline static bool Close(_In_ Type h) throw() {
91 ::CoTaskMemFree(h);
92 return true;
93 }
94
95 inline static Type GetInvalidValue() throw() {
96 return nullptr;
97 }
98 };
99 typedef HandleT<CoTaskMemStringTraits> CoTaskMemString;
100
101 // For the app to be activated from Action Center, it needs to provide a COM
102 // server to be called
103 // when the notification is activated. The CLSID of the object needs to be
104 // registered with the
105 // OS via its shortcut so that it knows who to call later.
106 class DECLSPEC_UUID("E65AECC7-DD9B-4D14-A4ED-73A5BEF1187A")
107 NotificationActivator WrlSealed
108 : public RuntimeClass<RuntimeClassFlags<ClassicCom>,
109 INotificationActivationCallback> {
110 public:
111 HRESULT STDMETHODCALLTYPE Activate(
112 _In_ LPCWSTR /*appUserModelId*/,
113 _In_ LPCWSTR invokedArgs,
114 /*_In_reads_(dataCount)*/ const NOTIFICATION_USER_INPUT_DATA* data,
115 ULONG dataCount) override {
116 ::MessageBoxW(NULL, invokedArgs, L"", MB_OK);
117 return S_OK;
118 }
119 };
120 CoCreatableClass(NotificationActivator);
121
122 // In order to display toasts, a desktop application must have a shortcut on the
123 // Start menu.
124 // Also, an AppUserModelID must be set on that shortcut.
125 //
126 // For the app to be activated from Action Center, it needs to register a COM
127 // server with the OS
128 // and register the CLSID of that COM server on the shortcut.
129 //
130 // The shortcut should be created as part of the installer. The following code
131 // shows how to create
132 // a shortcut and assign the AppUserModelID and ToastActivatorCLSID properties
133 // using Windows APIs.
134 //
135 // Included in this project is a wxs file that be used with the WiX toolkit
136 // to make an installer that creates the necessary shortcut. One or the other
137 // should be used.
138 //
139 // This sample doesn't clean up the shortcut or COM registration.
140
141 _Use_decl_annotations_ HRESULT
142 InstallShortcut(PCWSTR shortcutPath, PCWSTR exePath, PCWSTR arguments) {
143 MessageBoxW(NULL, L"InstallShortcut()", L"Title", MB_OK);
144 ComPtr<IShellLink> shellLink;
145 HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
146 IID_PPV_ARGS(&shellLink));
147
148 base::string16 app_id = GetChromeAppId();
149
150 if (SUCCEEDED(hr)) {
151 hr = shellLink->SetPath(exePath);
152
153 if (SUCCEEDED(hr)) {
154 hr = shellLink->SetArguments(arguments);
155
156 if (SUCCEEDED(hr)) {
157 ComPtr<IPropertyStore> propertyStore;
158
159 hr = shellLink.As(&propertyStore);
160 if (SUCCEEDED(hr)) {
161 PROPVARIANT propVar;
162 propVar.vt = VT_LPWSTR;
163 propVar.pwszVal = const_cast<PWSTR>(
164 app_id.c_str()); // for _In_ scenarios, we don't need a copy
165 hr = propertyStore->SetValue(PKEY_AppUserModel_ID, propVar);
166 if (SUCCEEDED(hr)) {
167 propVar.vt = VT_CLSID;
168 propVar.puuid =
169 const_cast<CLSID*>(&__uuidof(NotificationActivator));
170 hr = propertyStore->SetValue(PKEY_AppUserModel_ToastActivatorCLSID,
171 propVar);
172 if (SUCCEEDED(hr)) {
173 hr = propertyStore->Commit();
174 if (SUCCEEDED(hr)) {
175 ComPtr<IPersistFile> persistFile;
176 hr = shellLink.As(&persistFile);
177 if (SUCCEEDED(hr)) {
178 hr = persistFile->Save(shortcutPath, TRUE);
179 }
180 }
181 }
182 }
183 }
184 }
185 }
186 }
187 if (!SUCCEEDED(hr)) {
188 MessageBoxA(NULL, "InstallShortcut() failed.", "Title", MB_OK);
189 }
190 return hr;
191 }
192
193 _Use_decl_annotations_ HRESULT
194 RegisterComServer(PCWSTR exePath) {
195 // We don't need to worry about overflow here as ::GetModuleFileName won't
196 // return anything bigger than the max file system path (much fewer than max
197 // of DWORD).
198 DWORD dataSize = static_cast<DWORD>((::wcslen(exePath) + 1) * sizeof(WCHAR));
199
200 // In this sample, the app UI is registered to launch when the COM callback is
201 // needed.
202 // Other options might be to launch a background process instead that then
203 // decides to launch
204 // the UI if needed by that particular notification.
205 return HRESULT_FROM_WIN32(::RegSetKeyValue(
206 HKEY_CURRENT_USER,
207 LR"(SOFTWARE\Classes\CLSID\{E65AECC7-DD9B-4D14-A4ED-73A5BEF1187A}"
208 LR"\LocalServer32)",
209 nullptr, REG_SZ, reinterpret_cast<const BYTE*>(exePath), dataSize));
210 }
211
212 HRESULT RegisterAppForNotificationSupport() {
213 CoTaskMemString appData;
214
215 auto hr = ::SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr,
216 appData.GetAddressOf());
217 if (SUCCEEDED(hr)) {
218 wchar_t shortcutPath[MAX_PATH];
219 hr = ::PathCchCombine(
220 shortcutPath, ARRAYSIZE(shortcutPath), appData.Get(),
221 LR"(Microsoft\Windows\Start Menu\Programs\Tester\tester.lnk)");
222 if (SUCCEEDED(hr)) {
223 // MessageBoxW(NULL, shortcutPath, L"Title", MB_OK);
224 DWORD attributes = ::GetFileAttributes(shortcutPath);
225 bool fileExists = attributes < 0xFFFFFFF;
226 if (!fileExists) {
227 wchar_t exePath[MAX_PATH];
228 DWORD charWritten =
229 ::GetModuleFileName(nullptr, exePath, ARRAYSIZE(exePath));
230 MessageBoxW(NULL, exePath, L"Title", MB_OK);
231 hr = charWritten > 0 ? S_OK : HRESULT_FROM_WIN32(::GetLastError());
232 if (SUCCEEDED(hr)) {
233 const wchar_t* arguments = L"--enable-features=NativeNotifications "
234 L"--user-data-dir=R:\\p";
235 hr = InstallShortcut(shortcutPath, exePath, arguments);
236 if (SUCCEEDED(hr)) {
237 hr = RegisterComServer(exePath);
238 }
239 }
240 }
241 }
242 }
243 if (!SUCCEEDED(hr)) {
244 MessageBoxA(NULL, "RegisterAppForNotificationSupport() failed.", "Title",
245 MB_OK);
246 }
247 return hr;
248 }
249
250 // Register activator for notifications
251 HRESULT RegisterActivator() {
252 // Module<OutOfProc> needs a callback registered before it can be used.
253 // Since we don't care about when it shuts down, we'll pass an empty lambda
254 // here.
255 Module<OutOfProc>::Create([] {});
256
257 // If a local server process only hosts the COM object then COM expects
258 // the COM server host to shutdown when the references drop to zero.
259 // Since the user might still be using the program after activating the
260 // notification,
261 // we don't want to shutdown immediately. Incrementing the object count tells
262 // COM that
263 // we aren't done yet.
264 Module<OutOfProc>::GetModule().IncrementObjectCount();
265
266 return Module<OutOfProc>::GetModule().RegisterObjects();
267 }
268
269 // Unregister our activator COM object
270 void UnregisterActivator() {
271 Module<OutOfProc>::GetModule().UnregisterObjects();
272
273 Module<OutOfProc>::GetModule().DecrementObjectCount();
274 }
275
276 class HackyRegister {
277 public:
278 HackyRegister() {
279 }
280 HRESULT Run() {
281 HRESULT hr = RegisterActivator();
282 if (SUCCEEDED(hr))
283 has_reg = true;
284 return hr;
285 }
286 ~HackyRegister() {
287 if (has_reg)
288 UnregisterActivator();
289 }
290 private:
291 bool has_reg = false;
292 };
293
294 std::unique_ptr<HackyRegister> my_reg;
295
296 } // namespace
297
298 void PrepareChromeForWindows10() {
299 RoInitializeWrapper winRtInitializer(RO_INIT_MULTITHREADED);
300
301 // Experimental code: Attempt to respond to notificaiton events, using idea
302 // from https://github.com/WindowsNotifications/desktop-toasts
303 HRESULT hr = winRtInitializer;
304 if (!SUCCEEDED(hr))
305 return;
306
307 hr = RegisterAppForNotificationSupport();
308 if (SUCCEEDED(hr)) {
309 my_reg.reset(new HackyRegister());
310 hr = my_reg->Run();
311 if (SUCCEEDED(hr)) {
312 // ::MessageBoxA(NULL, "Registered", "Title", MB_OK);
313 }
314 }
315 }
OLDNEW
« no previous file with comments | « chrome/app/chrome_exe_main_app_win.h ('k') | chrome/app/chrome_exe_main_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698