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 #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 11 namespace { 12 13 const wchar_t kGetBrowserMessage[] = L"GetAutomationObject"; 14 15 const wchar_t kBHORegistrationPathFmt[] = 16 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer" 17 L"\\Browser Helper Objects\\%s"; 18 const wchar_t kChromeFrameClientKey[] = 19 L"Software\\Google\\Update\\Clients\\" 20 L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"; 21 const wchar_t kGoogleUpdateVersionValue[] = L"pv"; 22 23 } // namespace 24 25 bool 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 47 HRESULT 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 81 bool 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 95 bool 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 108 bool 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 115 namespace { 116 struct 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. 140 bool 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 164 BOOL 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 189 HWND 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>(¶ms)); 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. 205 LONG 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 229 bool 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 ®_handle); 249 if (result == ERROR_SUCCESS) { 250 RegCloseKey(reg_handle); 251 bho_registered = true; 252 } 253 } 254 } 255 256 return bho_registered; 257 } 258 259 bool 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 ®_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 282