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.
5 // chrome_frame_helper_main.cc : The .exe that bootstraps the
6 // chrome_frame_helper.dll.
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.
20 #include "chrome_frame/chrome_frame_helper_util.h"
21 #include "chrome_frame/crash_server_init.h"
22 #include "chrome_frame/registry_watcher.h"
26 // Window class and window names.
27 const wchar_t kChromeFrameHelperWindowClassName
[] =
28 L
"ChromeFrameHelperWindowClass";
29 const wchar_t kChromeFrameHelperWindowName
[] =
30 L
"ChromeFrameHelperWindowName";
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";
38 const wchar_t kBHORegistrationPath
[] =
39 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer"
40 L
"\\Browser Helper Objects";
42 const wchar_t kStartupArg
[] = L
"--startup";
43 const wchar_t kForceUninstall
[] = L
"--force-uninstall";
46 const UINT kRegistryWatcherChangeMessage
= WM_USER
+ 42;
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.
55 HookDllLoader() : dll_(NULL
), start_proc_(NULL
), stop_proc_(NULL
) {}
63 dll_
= LoadLibrary(L
"chrome_frame_helper.dll");
65 start_proc_
= GetProcAddress(dll_
, "StartUserModeBrowserInjection");
66 stop_proc_
= GetProcAddress(dll_
, "StopUserModeBrowserInjection");
70 if (!start_proc_
|| !stop_proc_
) {
71 _ASSERTE(L
"failed to load hook dll.");
74 if (FAILED(start_proc_())) {
75 _ASSERTE(L
"failed to initialize hook dll.");
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);
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);
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
123 void CloseAllHelperWindowsApartFrom(HWND except_me
) {
124 EnumWindows(CloseHelperWindowsEnumProc
, reinterpret_cast<LPARAM
>(except_me
));
127 LRESULT CALLBACK
ChromeFrameHelperWndProc(HWND hwnd
,
133 CloseAllHelperWindowsApartFrom(hwnd
);
135 case kRegistryWatcherChangeMessage
:
136 // A system level Chrome appeared. Fall through:
141 return ::DefWindowProc(hwnd
, message
, wparam
, lparam
);
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
);
155 HWND hwnd
= CreateWindow(kChromeFrameHelperWindowClassName
,
156 kChromeFrameHelperWindowName
, WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0,
157 CW_USEDEFAULT
, 0, NULL
, NULL
, hinstance
, NULL
);
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
,
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
,
181 LONG args_result
= ReadValue(reg_handle
,
182 kChromeFrameUninstallCmdArgsValue
,
185 RegCloseKey(reg_handle
);
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};
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,
204 if (arg_len
> 0 && CreateProcess(exe_buffer
, argument_string
,
205 NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
206 &startup_info
, &process_info
)) {
208 CloseHandle(process_info
.hThread
);
209 CloseHandle(process_info
.hProcess
);
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);
225 int APIENTRY
wWinMain(HINSTANCE hinstance
, HINSTANCE
, wchar_t*, int show_cmd
) {
226 google_breakpad::scoped_ptr
<google_breakpad::ExceptionHandler
> breakpad(
227 InitializeCrashReporting(NORMAL
));
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
);
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
));
246 // Load the hook dll, and set the event hooks.
247 HookDllLoader loader
;
248 bool loaded
= loader
.Load();
251 // Start up the registry watcher
252 RegistryWatcher
registry_watcher(HKEY_LOCAL_MACHINE
, kBHORegistrationPath
,
254 bool watching
= registry_watcher
.StartWatching();
260 // Main message loop:
261 while ((ret
= GetMessage(&msg
, NULL
, 0, 0))) {
265 TranslateMessage(&msg
);
266 DispatchMessage(&msg
);
271 UnregisterClass(kChromeFrameHelperWindowClassName
, hinstance
);