blob: 27e1555a86e4b560525b1eca15343a1ed7422ef3 [file] [log] [blame]
[email protected]6a7748e2011-05-27 16:44:311// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]9ceda772010-08-30 15:34:112// 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>
[email protected]6a7748e2011-05-27 16:44:3116#include <objbase.h>
17#include <stdlib.h>
[email protected]9ceda772010-08-30 15:34:1118#include <windows.h>
19
[email protected]6a7748e2011-05-27 16:44:3120#include "chrome_frame/chrome_frame_helper_util.h"
[email protected]e4fe427b2010-09-03 19:57:4221#include "chrome_frame/crash_server_init.h"
[email protected]6a7748e2011-05-27 16:44:3122#include "chrome_frame/registry_watcher.h"
23
24namespace {
[email protected]e4fe427b2010-09-03 19:57:4225
[email protected]9ceda772010-08-30 15:34:1126// Window class and window names.
27const wchar_t kChromeFrameHelperWindowClassName[] =
28 L"ChromeFrameHelperWindowClass";
29const wchar_t kChromeFrameHelperWindowName[] =
30 L"ChromeFrameHelperWindowName";
31
[email protected]6a7748e2011-05-27 16:44:3132const wchar_t kChromeFrameClientStateKey[] =
33 L"Software\\Google\\Update\\ClientState\\"
34 L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}";
35const wchar_t kChromeFrameUninstallCmdExeValue[] = L"UninstallString";
36const wchar_t kChromeFrameUninstallCmdArgsValue[] = L"UninstallArguments";
37
38const wchar_t kBHORegistrationPath[] =
39 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer"
40 L"\\Browser Helper Objects";
41
42const wchar_t kStartupArg[] = L"--startup";
43const wchar_t kForceUninstall[] = L"--force-uninstall";
44
45HWND g_hwnd = NULL;
46const UINT kRegistryWatcherChangeMessage = WM_USER + 42;
47
48} // namespace
49
[email protected]9ceda772010-08-30 15:34:1150// 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.
53class 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
[email protected]9283f272010-09-08 18:23:3097// 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.
100BOOL 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.
123void CloseAllHelperWindowsApartFrom(HWND except_me) {
124 EnumWindows(CloseHelperWindowsEnumProc, reinterpret_cast<LPARAM>(except_me));
125}
[email protected]9ceda772010-08-30 15:34:11126
127LRESULT CALLBACK ChromeFrameHelperWndProc(HWND hwnd,
128 UINT message,
129 WPARAM wparam,
130 LPARAM lparam) {
131 switch (message) {
[email protected]9283f272010-09-08 18:23:30132 case WM_CREATE:
133 CloseAllHelperWindowsApartFrom(hwnd);
134 break;
[email protected]6a7748e2011-05-27 16:44:31135 case kRegistryWatcherChangeMessage:
136 // A system level Chrome appeared. Fall through:
[email protected]9ceda772010-08-30 15:34:11137 case WM_DESTROY:
138 PostQuitMessage(0);
139 break;
140 default:
141 return ::DefWindowProc(hwnd, message, wparam, lparam);
142 }
143 return 0;
144}
145
146HWND 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
[email protected]6a7748e2011-05-27 16:44:31162
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.
165bool 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 &reg_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
218void 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
[email protected]9ceda772010-08-30 15:34:11225int APIENTRY wWinMain(HINSTANCE hinstance, HINSTANCE, wchar_t*, int show_cmd) {
[email protected]e4fe427b2010-09-03 19:57:42226 google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad(
[email protected]15bb2f42011-06-23 20:20:02227 InitializeCrashReporting(NORMAL));
[email protected]9ceda772010-08-30 15:34:11228
[email protected]6a7748e2011-05-27 16:44:31229 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
[email protected]9ceda772010-08-30 15:34:11241 // Create a window with a known class and title just to listen for WM_CLOSE
242 // messages that will shut us down.
[email protected]6a7748e2011-05-27 16:44:31243 g_hwnd = RegisterAndCreateWindow(hinstance);
244 _ASSERTE(IsWindow(g_hwnd));
[email protected]9ceda772010-08-30 15:34:11245
246 // Load the hook dll, and set the event hooks.
247 HookDllLoader loader;
248 bool loaded = loader.Load();
249 _ASSERTE(loaded);
250
[email protected]6a7748e2011-05-27 16:44:31251 // 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
[email protected]9ceda772010-08-30 15:34:11257 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
[email protected]840321b92011-04-29 19:18:34271 UnregisterClass(kChromeFrameHelperWindowClassName, hinstance);
[email protected]9ceda772010-08-30 15:34:11272 return 0;
273}