- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / chrome_frame_helper_main.cc
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                              &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
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 }