| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 // chrome_frame_helper_main.cc : The .exe that bootstraps the | |
| 6 // chrome_frame_helper.dll. | |
| 7 // | |
| 8 // This is a small exe that loads the hook dll to set the event hooks and then | |
| 9 // waits in a message loop. It is intended to be shut down by looking for a | |
| 10 // window with the class and title | |
| 11 // kChromeFrameHelperWindowClassName and kChromeFrameHelperWindowName and then | |
| 12 // sending that window a WM_CLOSE message. | |
| 13 // | |
| 14 | |
| 15 #include <crtdbg.h> | |
| 16 #include <objbase.h> | |
| 17 #include <stdlib.h> | |
| 18 #include <windows.h> | |
| 19 | |
| 20 #include "chrome_frame/chrome_frame_helper_util.h" | |
| 21 #include "chrome_frame/crash_server_init.h" | |
| 22 #include "chrome_frame/registry_watcher.h" | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 // Window class and window names. | |
| 27 const wchar_t kChromeFrameHelperWindowClassName[] = | |
| 28 L"ChromeFrameHelperWindowClass"; | |
| 29 const wchar_t kChromeFrameHelperWindowName[] = | |
| 30 L"ChromeFrameHelperWindowName"; | |
| 31 | |
| 32 const wchar_t kChromeFrameClientStateKey[] = | |
| 33 L"Software\\Google\\Update\\ClientState\\" | |
| 34 L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"; | |
| 35 const wchar_t kChromeFrameUninstallCmdExeValue[] = L"UninstallString"; | |
| 36 const wchar_t kChromeFrameUninstallCmdArgsValue[] = L"UninstallArguments"; | |
| 37 | |
| 38 const wchar_t kBHORegistrationPath[] = | |
| 39 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer" | |
| 40 L"\\Browser Helper Objects"; | |
| 41 | |
| 42 const wchar_t kStartupArg[] = L"--startup"; | |
| 43 const wchar_t kForceUninstall[] = L"--force-uninstall"; | |
| 44 | |
| 45 HWND g_hwnd = NULL; | |
| 46 const UINT kRegistryWatcherChangeMessage = WM_USER + 42; | |
| 47 | |
| 48 } // namespace | |
| 49 | |
| 50 // Small helper class that assists in loading the DLL that contains code | |
| 51 // to register our event hook callback. Automatically removes the hook and | |
| 52 // unloads the DLL on destruction. | |
| 53 class HookDllLoader { | |
| 54 public: | |
| 55 HookDllLoader() : dll_(NULL), start_proc_(NULL), stop_proc_(NULL) {} | |
| 56 ~HookDllLoader() { | |
| 57 if (dll_) { | |
| 58 Unload(); | |
| 59 } | |
| 60 } | |
| 61 | |
| 62 bool Load() { | |
| 63 dll_ = LoadLibrary(L"chrome_frame_helper.dll"); | |
| 64 if (dll_) { | |
| 65 start_proc_ = GetProcAddress(dll_, "StartUserModeBrowserInjection"); | |
| 66 stop_proc_ = GetProcAddress(dll_, "StopUserModeBrowserInjection"); | |
| 67 } | |
| 68 | |
| 69 bool result = true; | |
| 70 if (!start_proc_ || !stop_proc_) { | |
| 71 _ASSERTE(L"failed to load hook dll."); | |
| 72 result = false; | |
| 73 } else { | |
| 74 if (FAILED(start_proc_())) { | |
| 75 _ASSERTE(L"failed to initialize hook dll."); | |
| 76 result = false; | |
| 77 } | |
| 78 } | |
| 79 return result; | |
| 80 } | |
| 81 | |
| 82 void Unload() { | |
| 83 if (stop_proc_) { | |
| 84 stop_proc_(); | |
| 85 } | |
| 86 if (dll_) { | |
| 87 FreeLibrary(dll_); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 HMODULE dll_; | |
| 93 PROC start_proc_; | |
| 94 PROC stop_proc_; | |
| 95 }; | |
| 96 | |
| 97 // Checks the window title and then class of hwnd. If they match with that | |
| 98 // of a chrome_frame_helper.exe window, then add it to the list of windows | |
| 99 // pointed to by lparam. | |
| 100 BOOL CALLBACK CloseHelperWindowsEnumProc(HWND hwnd, LPARAM lparam) { | |
| 101 _ASSERTE(lparam != 0); | |
| 102 | |
| 103 wchar_t title_buffer[MAX_PATH] = {0}; | |
| 104 if (GetWindowText(hwnd, title_buffer, MAX_PATH)) { | |
| 105 if (lstrcmpiW(title_buffer, kChromeFrameHelperWindowName) == 0) { | |
| 106 wchar_t class_buffer[MAX_PATH] = {0}; | |
| 107 if (GetClassName(hwnd, class_buffer, MAX_PATH)) { | |
| 108 if (lstrcmpiW(class_buffer, kChromeFrameHelperWindowClassName) == 0) { | |
| 109 if (hwnd != reinterpret_cast<HWND>(lparam)) { | |
| 110 PostMessage(hwnd, WM_CLOSE, 0, 0); | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 return TRUE; | |
| 118 } | |
| 119 | |
| 120 // Enumerates all top level windows, looking for those that look like a | |
| 121 // Chrome Frame helper window. It then closes all of them except for | |
| 122 // except_me. | |
| 123 void CloseAllHelperWindowsApartFrom(HWND except_me) { | |
| 124 EnumWindows(CloseHelperWindowsEnumProc, reinterpret_cast<LPARAM>(except_me)); | |
| 125 } | |
| 126 | |
| 127 LRESULT CALLBACK ChromeFrameHelperWndProc(HWND hwnd, | |
| 128 UINT message, | |
| 129 WPARAM wparam, | |
| 130 LPARAM lparam) { | |
| 131 switch (message) { | |
| 132 case WM_CREATE: | |
| 133 CloseAllHelperWindowsApartFrom(hwnd); | |
| 134 break; | |
| 135 case kRegistryWatcherChangeMessage: | |
| 136 // A system level Chrome appeared. Fall through: | |
| 137 case WM_DESTROY: | |
| 138 PostQuitMessage(0); | |
| 139 break; | |
| 140 default: | |
| 141 return ::DefWindowProc(hwnd, message, wparam, lparam); | |
| 142 } | |
| 143 return 0; | |
| 144 } | |
| 145 | |
| 146 HWND RegisterAndCreateWindow(HINSTANCE hinstance) { | |
| 147 WNDCLASSEX wcex = {0}; | |
| 148 wcex.cbSize = sizeof(WNDCLASSEX); | |
| 149 wcex.lpfnWndProc = ChromeFrameHelperWndProc; | |
| 150 wcex.hInstance = GetModuleHandle(NULL); | |
| 151 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1); | |
| 152 wcex.lpszClassName = kChromeFrameHelperWindowClassName; | |
| 153 RegisterClassEx(&wcex); | |
| 154 | |
| 155 HWND hwnd = CreateWindow(kChromeFrameHelperWindowClassName, | |
| 156 kChromeFrameHelperWindowName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, | |
| 157 CW_USEDEFAULT, 0, NULL, NULL, hinstance, NULL); | |
| 158 | |
| 159 return hwnd; | |
| 160 } | |
| 161 | |
| 162 | |
| 163 // This method runs the user-level Chrome Frame uninstall command. This is | |
| 164 // intended to allow it to delegate to an existing system-level install. | |
| 165 bool UninstallUserLevelChromeFrame() { | |
| 166 bool success = false; | |
| 167 HKEY reg_handle = NULL; | |
| 168 wchar_t reg_path_buffer[MAX_PATH] = {0}; | |
| 169 LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, | |
| 170 kChromeFrameClientStateKey, | |
| 171 0, | |
| 172 KEY_QUERY_VALUE, | |
| 173 ®_handle); | |
| 174 if (result == ERROR_SUCCESS) { | |
| 175 wchar_t exe_buffer[MAX_PATH] = {0}; | |
| 176 wchar_t args_buffer[MAX_PATH] = {0}; | |
| 177 LONG exe_result = ReadValue(reg_handle, | |
| 178 kChromeFrameUninstallCmdExeValue, | |
| 179 MAX_PATH, | |
| 180 exe_buffer); | |
| 181 LONG args_result = ReadValue(reg_handle, | |
| 182 kChromeFrameUninstallCmdArgsValue, | |
| 183 MAX_PATH, | |
| 184 args_buffer); | |
| 185 RegCloseKey(reg_handle); | |
| 186 reg_handle = NULL; | |
| 187 | |
| 188 if (exe_result == ERROR_SUCCESS && args_result == ERROR_SUCCESS) { | |
| 189 STARTUPINFO startup_info = {0}; | |
| 190 startup_info.cb = sizeof(startup_info); | |
| 191 startup_info.dwFlags = STARTF_USESHOWWINDOW; | |
| 192 startup_info.wShowWindow = SW_SHOW; | |
| 193 PROCESS_INFORMATION process_info = {0}; | |
| 194 | |
| 195 // Quote the command string in the args. | |
| 196 wchar_t argument_string[MAX_PATH * 3] = {0}; | |
| 197 int arg_len = _snwprintf(argument_string, | |
| 198 _countof(argument_string) - 1, | |
| 199 L"\"%s\" %s %s", | |
| 200 exe_buffer, | |
| 201 args_buffer, | |
| 202 kForceUninstall); | |
| 203 | |
| 204 if (arg_len > 0 && CreateProcess(exe_buffer, argument_string, | |
| 205 NULL, NULL, FALSE, 0, NULL, NULL, | |
| 206 &startup_info, &process_info)) { | |
| 207 // Close handles. | |
| 208 CloseHandle(process_info.hThread); | |
| 209 CloseHandle(process_info.hProcess); | |
| 210 success = true; | |
| 211 } | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 return success; | |
| 216 } | |
| 217 | |
| 218 void WaitCallback() { | |
| 219 // Check if the Chrome Frame BHO is now in the list of registered BHOs: | |
| 220 if (IsBHOLoadingPolicyRegistered()) { | |
| 221 PostMessage(g_hwnd, kRegistryWatcherChangeMessage, 0, 0); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 int APIENTRY wWinMain(HINSTANCE hinstance, HINSTANCE, wchar_t*, int show_cmd) { | |
| 226 google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( | |
| 227 InitializeCrashReporting(NORMAL)); | |
| 228 | |
| 229 if (IsSystemLevelChromeFrameInstalled()) { | |
| 230 // If we're running at startup, check for system-level Chrome Frame | |
| 231 // installations. If we have one, time | |
| 232 // to bail, also schedule user-level CF to be uninstalled at next logon. | |
| 233 const wchar_t* cmd_line = ::GetCommandLine(); | |
| 234 if (cmd_line && wcsstr(cmd_line, kStartupArg) != NULL) { | |
| 235 bool uninstalled = UninstallUserLevelChromeFrame(); | |
| 236 _ASSERTE(uninstalled); | |
| 237 } | |
| 238 return 0; | |
| 239 } | |
| 240 | |
| 241 // Create a window with a known class and title just to listen for WM_CLOSE | |
| 242 // messages that will shut us down. | |
| 243 g_hwnd = RegisterAndCreateWindow(hinstance); | |
| 244 _ASSERTE(IsWindow(g_hwnd)); | |
| 245 | |
| 246 // Load the hook dll, and set the event hooks. | |
| 247 HookDllLoader loader; | |
| 248 bool loaded = loader.Load(); | |
| 249 _ASSERTE(loaded); | |
| 250 | |
| 251 // Start up the registry watcher | |
| 252 RegistryWatcher registry_watcher(HKEY_LOCAL_MACHINE, kBHORegistrationPath, | |
| 253 WaitCallback); | |
| 254 bool watching = registry_watcher.StartWatching(); | |
| 255 _ASSERTE(watching); | |
| 256 | |
| 257 if (loaded) { | |
| 258 MSG msg; | |
| 259 BOOL ret; | |
| 260 // Main message loop: | |
| 261 while ((ret = GetMessage(&msg, NULL, 0, 0))) { | |
| 262 if (ret == -1) { | |
| 263 break; | |
| 264 } else { | |
| 265 TranslateMessage(&msg); | |
| 266 DispatchMessage(&msg); | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 UnregisterClass(kChromeFrameHelperWindowClassName, hinstance); | |
| 272 return 0; | |
| 273 } | |
| OLD | NEW |