blob: 02445572b6000ab769c42cb7b191711f83816405 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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#include "chrome_frame/chrome_frame_helper_util.h"
6#include "chrome_frame/chrome_tab.h"
7
8#include <shlwapi.h>
9#include <stdio.h>
10
11namespace {
12
13const wchar_t kGetBrowserMessage[] = L"GetAutomationObject";
14
15const wchar_t kBHORegistrationPathFmt[] =
16 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer"
17 L"\\Browser Helper Objects\\%s";
18const wchar_t kChromeFrameClientKey[] =
19 L"Software\\Google\\Update\\Clients\\"
20 L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}";
21const wchar_t kGoogleUpdateVersionValue[] = L"pv";
22
23} // namespace
24
25bool UtilIsWebBrowserWindow(HWND window_to_check) {
26 bool is_browser_window = false;
27
28 if (!IsWindow(window_to_check)) {
29 return is_browser_window;
30 }
31
32 static wchar_t* known_ie_window_classes[] = {
33 L"IEFrame",
34 L"TabWindowClass"
35 };
36
37 for (int i = 0; i < ARRAYSIZE(known_ie_window_classes); i++) {
38 if (IsWindowOfClass(window_to_check, known_ie_window_classes[i])) {
39 is_browser_window = true;
40 break;
41 }
42 }
43
44 return is_browser_window;
45}
46
47HRESULT UtilGetWebBrowserObjectFromWindow(HWND window,
48 REFIID iid,
49 void** web_browser_object) {
50 if (NULL == web_browser_object) {
51 return E_POINTER;
52 }
53
54 // Check whether this window is really a web browser window.
55 if (UtilIsWebBrowserWindow(window)) {
56 // IWebBroswer2 interface pointer can be retrieved from the browser
57 // window by simply sending a registered message "GetAutomationObject"
58 // Note that since we are sending a message to parent window make sure that
59 // it is in the same thread.
60 if (GetWindowThreadProcessId(window, NULL) != GetCurrentThreadId()) {
61 return E_UNEXPECTED;
62 }
63
64 static const ULONG get_browser_message =
65 RegisterWindowMessageW(kGetBrowserMessage);
66
67 *web_browser_object =
68 reinterpret_cast<void*>(SendMessage(window,
69 get_browser_message,
70 reinterpret_cast<WPARAM>(&iid),
71 NULL));
72 if (NULL != *web_browser_object) {
73 return S_OK;
74 }
75 } else {
76 return E_INVALIDARG;
77 }
78 return E_NOINTERFACE;
79}
80
81bool IsWindowOfClass(HWND window_to_check, const wchar_t* window_class) {
82 bool window_matches = false;
83 const int buf_size = MAX_PATH;
84 wchar_t buffer[buf_size] = {0};
85 DWORD size = GetClassNameW(window_to_check, buffer, buf_size);
86 // If the window name is any longer than this, it isn't the one we want.
87 if (size < (buf_size - 1)) {
88 if (!lstrcmpiW(window_class, buffer)) {
89 window_matches = true;
90 }
91 }
92 return window_matches;
93}
94
95bool IsNamedWindow(HWND window, const wchar_t* window_name) {
96 bool window_matches = false;
97 const int buf_size = MAX_PATH;
98 wchar_t buffer[buf_size] = {0};
99 DWORD size = GetWindowText(window, buffer, buf_size);
100 if (size < (buf_size - 1)) {
101 if (!lstrcmpiW(window_name, buffer)) {
102 window_matches = true;
103 }
104 }
105 return window_matches;
106}
107
108bool IsNamedProcess(const wchar_t* process_name) {
109 wchar_t file_path[2048] = {0};
110 GetModuleFileName(NULL, file_path, 2047);
111 wchar_t* file_name = PathFindFileName(file_path);
112 return (0 == lstrcmpiW(file_name, process_name));
113}
114
115namespace {
116struct FindWindowParams {
117 HWND parent_;
118 const wchar_t* class_name_;
119 const wchar_t* window_name_;
120 HWND window_found_;
121 DWORD thread_id_;
122 DWORD process_id_;
123 FindWindowParams(HWND parent,
124 const wchar_t* class_name,
125 const wchar_t* window_name,
126 DWORD thread_id,
127 DWORD process_id)
128 : parent_(parent),
129 class_name_(class_name),
130 window_name_(window_name),
131 window_found_(NULL),
132 thread_id_(thread_id),
133 process_id_(process_id) {
134 }
135};
136
137// Checks a window against a set of parameters defined in params. If the
138// window matches, fills in params->window_found_ with the HWND of the window
139// and returns true. Returns false otherwise.
140bool WindowMatches(HWND window, FindWindowParams* params) {
141 bool found = false;
142 DWORD process_id = 0;
143 DWORD thread_id = GetWindowThreadProcessId(window, &process_id);
144
145 // First check that the PID and TID match if we're interested.
146 if (params->process_id_ == 0 || params->process_id_ == process_id) {
147 if (params->thread_id_ == 0 || params->thread_id_ == thread_id) {
148 // Then check that we match on class and window names, again only if
149 // we're interested.
150 if ((params->class_name_ == NULL ||
151 IsWindowOfClass(window, params->class_name_)) &&
152 (params->window_name_ == NULL) ||
153 IsNamedWindow(window, params->window_name_)) {
154 found = true;
155 params->window_found_ = window;
156 }
157 }
158 }
159 return found;
160}
161
162} // namespace
163
164BOOL CALLBACK WndEnumProc(HWND window, LPARAM lparam) {
165 FindWindowParams* params = reinterpret_cast<FindWindowParams *>(lparam);
166 if (!params) {
167 return FALSE;
168 }
169
170 if (WindowMatches(window, params)) {
171 // We found a match on a top level window. Return false to stop enumerating.
172 return FALSE;
173 } else {
174 // If criteria not satisfied, let us try child windows.
175 HWND child_window = RecurseFindWindow(window,
176 params->class_name_,
177 params->window_name_,
178 params->thread_id_,
179 params->process_id_);
180 if (child_window != NULL) {
181 // We found the window we are looking for.
182 params->window_found_ = child_window;
183 return FALSE;
184 }
185 return TRUE;
186 }
187}
188
189HWND RecurseFindWindow(HWND parent,
190 const wchar_t* class_name,
191 const wchar_t* window_name,
192 DWORD thread_id_to_match,
193 DWORD process_id_to_match) {
194 if ((class_name == NULL) && (window_name == NULL)) {
195 return NULL;
196 }
197 FindWindowParams params(parent, class_name, window_name,
198 thread_id_to_match, process_id_to_match);
199 EnumChildWindows(parent, WndEnumProc, reinterpret_cast<LPARAM>(&params));
200 return params.window_found_;
201}
202
203// TODO(robertshield): This is stolen shamelessly from mini_installer.cc.
204// Refactor this before (more) bad things happen.
205LONG ReadValue(HKEY key,
206 const wchar_t* value_name,
207 size_t value_size,
208 wchar_t* value) {
209 DWORD type;
210 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t));
211 LONG result = ::RegQueryValueEx(key, value_name, NULL, &type,
212 reinterpret_cast<BYTE*>(value),
213 &byte_length);
214 if (result == ERROR_SUCCESS) {
215 if (type != REG_SZ) {
216 result = ERROR_NOT_SUPPORTED;
217 } else if (byte_length == 0) {
218 *value = L'\0';
219 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') {
220 if ((byte_length / sizeof(wchar_t)) < value_size)
221 value[byte_length / sizeof(wchar_t)] = L'\0';
222 else
223 result = ERROR_MORE_DATA;
224 }
225 }
226 return result;
227}
228
229bool IsBHOLoadingPolicyRegistered() {
230 wchar_t bho_clsid_as_string[MAX_PATH] = {0};
231 int count = StringFromGUID2(CLSID_ChromeFrameBHO, bho_clsid_as_string,
232 ARRAYSIZE(bho_clsid_as_string));
233
234 bool bho_registered = false;
235 if (count > 0) {
236 wchar_t reg_path_buffer[MAX_PATH] = {0};
237 int path_count = _snwprintf(reg_path_buffer,
238 MAX_PATH - 1,
239 kBHORegistrationPathFmt,
240 bho_clsid_as_string);
241
242 if (path_count > 0) {
243 HKEY reg_handle = NULL;
244 LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
245 reg_path_buffer,
246 0,
247 KEY_QUERY_VALUE,
248 &reg_handle);
249 if (result == ERROR_SUCCESS) {
250 RegCloseKey(reg_handle);
251 bho_registered = true;
252 }
253 }
254 }
255
256 return bho_registered;
257}
258
259bool IsSystemLevelChromeFrameInstalled() {
260 bool system_level_installed = false;
261 HKEY reg_handle = NULL;
262 LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
263 kChromeFrameClientKey,
264 0,
265 KEY_QUERY_VALUE,
266 &reg_handle);
267 if (result == ERROR_SUCCESS) {
268 wchar_t version_buffer[MAX_PATH] = {0};
269 result = ReadValue(reg_handle,
270 kGoogleUpdateVersionValue,
271 MAX_PATH,
272 version_buffer);
273 if (result == ERROR_SUCCESS && version_buffer[0] != L'\0') {
274 system_level_installed = true;
275 }
276 RegCloseKey(reg_handle);
277 }
278
279 return system_level_installed;
280}
281