Home | History | Annotate | Download | only in chrome_frame
      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>(&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.
    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                                  &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 
    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                              &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 
    282