Chromium Code Reviews| Index: chrome_frame/chrome_frame_helper_main.cc |
| =================================================================== |
| --- chrome_frame/chrome_frame_helper_main.cc (revision 86605) |
| +++ chrome_frame/chrome_frame_helper_main.cc (working copy) |
| @@ -1,4 +1,4 @@ |
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +// Copyright (c) 2011 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. |
| // |
| @@ -13,16 +13,38 @@ |
| // |
| #include <crtdbg.h> |
| +#include <objbase.h> |
| #include <windows.h> |
| +#include "chrome_frame/chrome_frame_helper_util.h" |
| #include "chrome_frame/crash_server_init.h" |
| +#include "chrome_frame/registry_watcher.h" |
| +namespace { |
| // Window class and window names. |
|
grt (UTC plus 2)
2011/05/26 17:08:58
nit: newline before this
robertshield
2011/05/27 03:34:59
Done.
|
| const wchar_t kChromeFrameHelperWindowClassName[] = |
| L"ChromeFrameHelperWindowClass"; |
| const wchar_t kChromeFrameHelperWindowName[] = |
| L"ChromeFrameHelperWindowName"; |
| +const wchar_t kChromeFrameClientStateKey[] = |
| + L"Software\\Google\\Update\\ClientState\\" |
| + L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"; |
| +const wchar_t kChromeFrameUninstallCmdExeValue[] = L"UninstallString"; |
| +const wchar_t kChromeFrameUninstallCmdArgsValue[] = L"UninstallArguments"; |
| + |
| +const wchar_t kBHORegistrationPath[] = |
| + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer" |
| + L"\\Browser Helper Objects"; |
| + |
| +const wchar_t kStartupArg[] = L"--startup"; |
| +const wchar_t kForceUninstall[] = L"--force-uninstall"; |
| + |
| +HWND g_hwnd = NULL; |
| +const UINT kRegistryWatcherChangeMessage = WM_USER + 42; |
| + |
| +} // namespace |
| + |
| // Small helper class that assists in loading the DLL that contains code |
| // to register our event hook callback. Automatically removes the hook and |
| // unloads the DLL on destruction. |
| @@ -108,6 +130,8 @@ |
| case WM_CREATE: |
| CloseAllHelperWindowsApartFrom(hwnd); |
| break; |
| + case kRegistryWatcherChangeMessage: |
| + // A system level Chrome appeared. Fall through: |
| case WM_DESTROY: |
| PostQuitMessage(0); |
| break; |
| @@ -133,21 +157,107 @@ |
| return hwnd; |
| } |
| + |
| +// This method runs the user-level Chrome Frame uninstall command. This is |
| +// intended to allow it to delegate to an existing system-level install. |
| +bool UninstallUserLevelChromeFrame() { |
| + bool success = false; |
| + HKEY reg_handle = NULL; |
| + wchar_t reg_path_buffer[MAX_PATH] = {0}; |
| + LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, |
| + kChromeFrameClientStateKey, |
| + 0, |
| + KEY_QUERY_VALUE, |
| + ®_handle); |
| + if (result == ERROR_SUCCESS) { |
| + wchar_t exe_buffer[MAX_PATH] = {0}; |
| + wchar_t args_buffer[MAX_PATH] = {0}; |
| + LONG exe_result = ReadValue(reg_handle, |
| + kChromeFrameUninstallCmdExeValue, |
| + MAX_PATH, |
| + exe_buffer); |
| + LONG args_result = ReadValue(reg_handle, |
| + kChromeFrameUninstallCmdArgsValue, |
| + MAX_PATH, |
| + args_buffer); |
| + RegCloseKey(reg_handle); |
| + reg_handle = NULL; |
| + |
| + if (exe_result == ERROR_SUCCESS && args_result == ERROR_SUCCESS) { |
| + STARTUPINFO startup_info = {0}; |
| + startup_info.cb = sizeof(startup_info); |
| + startup_info.dwFlags = STARTF_USESHOWWINDOW; |
| + startup_info.wShowWindow = SW_SHOW; |
| + PROCESS_INFORMATION process_info = {0}; |
| + |
| + // Quote the command string in the args. |
| + wchar_t argument_string[MAX_PATH * 3] = {0}; |
| + _snwprintf(argument_string, |
|
grt (UTC plus 2)
2011/05/26 17:08:58
int argument_string_len = _snwprintf(...);
if (arg
robertshield
2011/05/27 03:34:59
Done.
|
| + MAX_PATH * 3, |
|
grt (UTC plus 2)
2011/05/26 17:08:58
_countof(argument_string) would be more safe, no?
robertshield
2011/05/27 03:34:59
_countof() - 1, just to ensure that the string rem
grt (UTC plus 2)
2011/05/27 14:07:58
Good call.
|
| + L"\"%s\" %s %s", |
| + exe_buffer, |
| + args_buffer, |
| + kForceUninstall); |
| + |
| + if (CreateProcess(exe_buffer, argument_string, |
| + NULL, NULL, FALSE, 0, NULL, NULL, |
| + &startup_info, &process_info)) { |
| + // Close handles. |
| + CloseHandle(process_info.hThread); |
| + CloseHandle(process_info.hProcess); |
| + success = true; |
| + } |
| + } |
| + } |
| + |
| + return success; |
| +} |
| + |
| +void CALLBACK WaitCallback(void* param, BOOLEAN wait_fired) { |
| + RegistryWatcher* watcher = reinterpret_cast<RegistryWatcher*>(param); |
| + if (watcher->stopping()) |
| + return; |
| + |
| + // Check if the Chrome Frame BHO is now in the list of registered BHOs: |
| + if (IsBHOLoadingPolicyRegistered()) { |
| + // Post message. |
|
grt (UTC plus 2)
2011/05/26 17:08:58
This comment adds nothing. Please either make it
robertshield
2011/05/27 03:34:59
Done.
|
| + PostMessage(g_hwnd, kRegistryWatcherChangeMessage, 0, 0); |
| + } |
| +} |
| + |
| int APIENTRY wWinMain(HINSTANCE hinstance, HINSTANCE, wchar_t*, int show_cmd) { |
| const wchar_t* cmd_line = ::GetCommandLine(); |
| google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( |
| InitializeCrashReporting(cmd_line)); |
| + if (IsSystemLevelChromeFrameInstalled()) { |
| + // If we're running at startup, check for system-level Chrome Frame |
| + // installations. If we have one, time |
| + // to bail, also schedule user-level CF to be uninstalled at next logon. |
| + const wchar_t* cmd_line = ::GetCommandLine(); |
| + if (cmd_line && wcsstr(cmd_line, kStartupArg) != NULL) { |
| + bool uninstalled = UninstallUserLevelChromeFrame(); |
| + _ASSERTE(uninstalled); |
| + } |
| + return 0; |
| + } |
| + |
| // Create a window with a known class and title just to listen for WM_CLOSE |
| // messages that will shut us down. |
| - HWND hwnd = RegisterAndCreateWindow(hinstance); |
| - _ASSERTE(hwnd); |
| + g_hwnd = RegisterAndCreateWindow(hinstance); |
| + _ASSERTE(IsWindow(g_hwnd)); |
| // Load the hook dll, and set the event hooks. |
| HookDllLoader loader; |
| bool loaded = loader.Load(); |
| _ASSERTE(loaded); |
| + // Start up the registry watcher |
| + RegistryWatcher registry_watcher(HKEY_LOCAL_MACHINE, kBHORegistrationPath, |
| + WaitCallback); |
| + bool watching = registry_watcher.StartWatching(); |
| + _ASSERTE(watching); |
| + |
| if (loaded) { |
| MSG msg; |
| BOOL ret; |