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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/app/chrome_exe_main_app_win.cc
diff --git a/chrome/app/chrome_exe_main_app_win.cc b/chrome/app/chrome_exe_main_app_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..25d33e97885bdf2e0f8d9af527dfe290f6f7e76c
--- /dev/null
+++ b/chrome/app/chrome_exe_main_app_win.cc
@@ -0,0 +1,315 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/app/chrome_exe_main_app_win.h"
+
+#include <memory>
+
+#include "base/win/scoped_co_mem.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/shell_util.h"
+
+// 2017/04/04: For this to work we also need
+// HKEY_CLASSES_ROOT\CLSID\{E65AECC7-DD9B-4D14-A4ED-73A5BEF1187A}\LocalServer32
+// to be assigned command line to launch Chrome.
+
+#if 0
+// #include <roapi.h>
+// #include <wchar.h>
+#include <NotificationActivationCallback.h>
+#include <propvarutil.h>
+#include <psapi.h>
+#include <shobjidl.h>
+#include <wrl.h>
+
+#include <cstring>
+#include <memory>
+#include <string>
+
+namespace mswr = Microsoft::WRL;
+// namespace mswrw = Microsoft::WRL::Wrappers;
+
+// namespace winapp = ABI::Windows::ApplicationModel;
+// namespace winxaml = ABI::Windows::UI::Xaml;
+// namespace winact = ABI::Windows::ApplicationModel::Activation;
+// namespace winfoundtn = ABI::Windows::Foundation;
+// namespace winui = ABI::Windows::UI;
+
+#else
+
+// #include <SDKDDKVer.h>
+#include <Windows.h>
+#include <Psapi.h>
+// #include <strsafe.h>
+#include <ShObjIdl.h>
+#include <Shlobj.h>
+#include <Pathcch.h>
+#include <propvarutil.h>
+#include <propkey.h>
+#include <wrl.h>
+#include <wrl\wrappers\corewrappers.h>
+#include <windows.ui.notifications.h>
+#include "NotificationActivationCallback.h"
+
+// using namespace ABI::Windows::Data::Xml::Dom;
+using namespace ABI::Windows::UI::Notifications;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+
+#endif
+
+namespace {
+
+base::string16 GetChromeAppId() {
+ bool is_per_user_install = InstallUtil::IsPerUserInstall();
+ base::string16 appid = ShellUtil::GetBrowserModelId(is_per_user_install);
+ DVLOG(1) << "Chrome Appid is " << appid.c_str();
+ return appid;
+}
+
+
+// Name: System.AppUserModel.ToastActivatorCLSID --
+// PKEY_AppUserModel_ToastActivatorCLSID
+// Type: Guid -- VT_CLSID
+// FormatID: {9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 26
+//
+// Used to CoCreate an INotificationActivationCallback interface to notify
+// about toast activations.
+EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY
+ PKEY_AppUserModel_ToastActivatorCLSID = {
+ {0x9F4C2855,
+ 0x9F79,
+ 0x4B39,
+ {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}},
+ 26};
+
+struct CoTaskMemStringTraits {
+ typedef PWSTR Type;
+
+ inline static bool Close(_In_ Type h) throw() {
+ ::CoTaskMemFree(h);
+ return true;
+ }
+
+ inline static Type GetInvalidValue() throw() {
+ return nullptr;
+ }
+};
+typedef HandleT<CoTaskMemStringTraits> CoTaskMemString;
+
+// For the app to be activated from Action Center, it needs to provide a COM
+// server to be called
+// when the notification is activated. The CLSID of the object needs to be
+// registered with the
+// OS via its shortcut so that it knows who to call later.
+class DECLSPEC_UUID("E65AECC7-DD9B-4D14-A4ED-73A5BEF1187A")
+ NotificationActivator WrlSealed
+ : public RuntimeClass<RuntimeClassFlags<ClassicCom>,
+ INotificationActivationCallback> {
+ public:
+ HRESULT STDMETHODCALLTYPE Activate(
+ _In_ LPCWSTR /*appUserModelId*/,
+ _In_ LPCWSTR invokedArgs,
+ /*_In_reads_(dataCount)*/ const NOTIFICATION_USER_INPUT_DATA* data,
+ ULONG dataCount) override {
+ ::MessageBoxW(NULL, invokedArgs, L"", MB_OK);
+ return S_OK;
+ }
+};
+CoCreatableClass(NotificationActivator);
+
+// In order to display toasts, a desktop application must have a shortcut on the
+// Start menu.
+// Also, an AppUserModelID must be set on that shortcut.
+//
+// For the app to be activated from Action Center, it needs to register a COM
+// server with the OS
+// and register the CLSID of that COM server on the shortcut.
+//
+// The shortcut should be created as part of the installer. The following code
+// shows how to create
+// a shortcut and assign the AppUserModelID and ToastActivatorCLSID properties
+// using Windows APIs.
+//
+// Included in this project is a wxs file that be used with the WiX toolkit
+// to make an installer that creates the necessary shortcut. One or the other
+// should be used.
+//
+// This sample doesn't clean up the shortcut or COM registration.
+
+_Use_decl_annotations_ HRESULT
+InstallShortcut(PCWSTR shortcutPath, PCWSTR exePath, PCWSTR arguments) {
+ MessageBoxW(NULL, L"InstallShortcut()", L"Title", MB_OK);
+ ComPtr<IShellLink> shellLink;
+ HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&shellLink));
+
+ base::string16 app_id = GetChromeAppId();
+
+ if (SUCCEEDED(hr)) {
+ hr = shellLink->SetPath(exePath);
+
+ if (SUCCEEDED(hr)) {
+ hr = shellLink->SetArguments(arguments);
+
+ if (SUCCEEDED(hr)) {
+ ComPtr<IPropertyStore> propertyStore;
+
+ hr = shellLink.As(&propertyStore);
+ if (SUCCEEDED(hr)) {
+ PROPVARIANT propVar;
+ propVar.vt = VT_LPWSTR;
+ propVar.pwszVal = const_cast<PWSTR>(
+ app_id.c_str()); // for _In_ scenarios, we don't need a copy
+ hr = propertyStore->SetValue(PKEY_AppUserModel_ID, propVar);
+ if (SUCCEEDED(hr)) {
+ propVar.vt = VT_CLSID;
+ propVar.puuid =
+ const_cast<CLSID*>(&__uuidof(NotificationActivator));
+ hr = propertyStore->SetValue(PKEY_AppUserModel_ToastActivatorCLSID,
+ propVar);
+ if (SUCCEEDED(hr)) {
+ hr = propertyStore->Commit();
+ if (SUCCEEDED(hr)) {
+ ComPtr<IPersistFile> persistFile;
+ hr = shellLink.As(&persistFile);
+ if (SUCCEEDED(hr)) {
+ hr = persistFile->Save(shortcutPath, TRUE);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!SUCCEEDED(hr)) {
+ MessageBoxA(NULL, "InstallShortcut() failed.", "Title", MB_OK);
+ }
+ return hr;
+}
+
+_Use_decl_annotations_ HRESULT
+RegisterComServer(PCWSTR exePath) {
+ // We don't need to worry about overflow here as ::GetModuleFileName won't
+ // return anything bigger than the max file system path (much fewer than max
+ // of DWORD).
+ DWORD dataSize = static_cast<DWORD>((::wcslen(exePath) + 1) * sizeof(WCHAR));
+
+ // In this sample, the app UI is registered to launch when the COM callback is
+ // needed.
+ // Other options might be to launch a background process instead that then
+ // decides to launch
+ // the UI if needed by that particular notification.
+ return HRESULT_FROM_WIN32(::RegSetKeyValue(
+ HKEY_CURRENT_USER,
+ LR"(SOFTWARE\Classes\CLSID\{E65AECC7-DD9B-4D14-A4ED-73A5BEF1187A}"
+ LR"\LocalServer32)",
+ nullptr, REG_SZ, reinterpret_cast<const BYTE*>(exePath), dataSize));
+}
+
+HRESULT RegisterAppForNotificationSupport() {
+ CoTaskMemString appData;
+
+ auto hr = ::SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr,
+ appData.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ wchar_t shortcutPath[MAX_PATH];
+ hr = ::PathCchCombine(
+ shortcutPath, ARRAYSIZE(shortcutPath), appData.Get(),
+ LR"(Microsoft\Windows\Start Menu\Programs\Tester\tester.lnk)");
+ if (SUCCEEDED(hr)) {
+ // MessageBoxW(NULL, shortcutPath, L"Title", MB_OK);
+ DWORD attributes = ::GetFileAttributes(shortcutPath);
+ bool fileExists = attributes < 0xFFFFFFF;
+ if (!fileExists) {
+ wchar_t exePath[MAX_PATH];
+ DWORD charWritten =
+ ::GetModuleFileName(nullptr, exePath, ARRAYSIZE(exePath));
+ MessageBoxW(NULL, exePath, L"Title", MB_OK);
+ hr = charWritten > 0 ? S_OK : HRESULT_FROM_WIN32(::GetLastError());
+ if (SUCCEEDED(hr)) {
+ const wchar_t* arguments = L"--enable-features=NativeNotifications "
+ L"--user-data-dir=R:\\p";
+ hr = InstallShortcut(shortcutPath, exePath, arguments);
+ if (SUCCEEDED(hr)) {
+ hr = RegisterComServer(exePath);
+ }
+ }
+ }
+ }
+ }
+ if (!SUCCEEDED(hr)) {
+ MessageBoxA(NULL, "RegisterAppForNotificationSupport() failed.", "Title",
+ MB_OK);
+ }
+ return hr;
+}
+
+// Register activator for notifications
+HRESULT RegisterActivator() {
+ // Module<OutOfProc> needs a callback registered before it can be used.
+ // Since we don't care about when it shuts down, we'll pass an empty lambda
+ // here.
+ Module<OutOfProc>::Create([] {});
+
+ // If a local server process only hosts the COM object then COM expects
+ // the COM server host to shutdown when the references drop to zero.
+ // Since the user might still be using the program after activating the
+ // notification,
+ // we don't want to shutdown immediately. Incrementing the object count tells
+ // COM that
+ // we aren't done yet.
+ Module<OutOfProc>::GetModule().IncrementObjectCount();
+
+ return Module<OutOfProc>::GetModule().RegisterObjects();
+}
+
+// Unregister our activator COM object
+void UnregisterActivator() {
+ Module<OutOfProc>::GetModule().UnregisterObjects();
+
+ Module<OutOfProc>::GetModule().DecrementObjectCount();
+}
+
+class HackyRegister {
+ public:
+ HackyRegister() {
+ }
+ HRESULT Run() {
+ HRESULT hr = RegisterActivator();
+ if (SUCCEEDED(hr))
+ has_reg = true;
+ return hr;
+ }
+ ~HackyRegister() {
+ if (has_reg)
+ UnregisterActivator();
+ }
+ private:
+ bool has_reg = false;
+};
+
+std::unique_ptr<HackyRegister> my_reg;
+
+} // namespace
+
+void PrepareChromeForWindows10() {
+ RoInitializeWrapper winRtInitializer(RO_INIT_MULTITHREADED);
+
+ // Experimental code: Attempt to respond to notificaiton events, using idea
+ // from https://github.com/WindowsNotifications/desktop-toasts
+ HRESULT hr = winRtInitializer;
+ if (!SUCCEEDED(hr))
+ return;
+
+ hr = RegisterAppForNotificationSupport();
+ if (SUCCEEDED(hr)) {
+ my_reg.reset(new HackyRegister());
+ hr = my_reg->Run();
+ if (SUCCEEDED(hr)) {
+ // ::MessageBoxA(NULL, "Registered", "Title", MB_OK);
+ }
+ }
+}
« 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