blob: d0d94ff99cc2bd8bf55734c25d09422927688347 [file] [log] [blame]
[email protected]9ceda772010-08-30 15:34:111// Copyright (c) 2010 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/bho_loader.h"
6
7#include <atlbase.h>
8#include <atlcomcli.h>
9#include <exdisp.h>
10
11#include "chrome_frame/chrome_frame_helper_util.h"
12#include "chrome_frame/event_hooker.h"
13#include "chrome_tab.h" // NOLINT
14
15
16// Describes the window class we look for.
17const wchar_t kStatusBarWindowClass[] = L"msctls_statusbar32";
18
19BHOLoader::BHOLoader() : hooker_(new EventHooker()) {
20}
21
22BHOLoader::~BHOLoader() {
23 if (hooker_) {
24 delete hooker_;
25 hooker_ = NULL;
26 }
27}
28
29void BHOLoader::OnHookEvent(DWORD event, HWND window) {
30 // Step 1: Make sure that we are in a process named iexplore.exe.
31 if (IsNamedProcess(L"iexplore.exe")) {
32 // Step 2: Check to see if the window is of the right class.
33 // IE loads BHOs in the WM_CREATE handler of the tab window approximately
34 // after it creates the status bar window. To be as close to IE as possible
35 // in our simulation on BHO loading, we watch for the status bar to be
36 // created and do our simulated BHO loading at that time.
37 if (IsWindowOfClass(window, kStatusBarWindowClass)) {
[email protected]4c01d63e2010-09-07 18:30:0838 // Check that the window was created on the current thread.
39 DWORD thread_id = GetWindowThreadProcessId(window, NULL);
40 _ASSERTE(thread_id == GetCurrentThreadId());
41
[email protected]9ceda772010-08-30 15:34:1142 HWND parent_window = GetParent(window);
43 // Step 3:
44 // Parent window of status bar window is the web browser window. Try to
45 // get its IWebBrowser2 interface
46 CComPtr<IWebBrowser2> browser;
47 UtilGetWebBrowserObjectFromWindow(parent_window, __uuidof(browser),
48 reinterpret_cast<void**>(&browser));
49 if (browser) {
[email protected]4c01d63e2010-09-07 18:30:0850 // Figure out if we're already in the property map.
51 wchar_t bho_clsid_as_string[MAX_PATH] = {0};
52 StringFromGUID2(CLSID_ChromeFrameBHO, bho_clsid_as_string,
53 ARRAYSIZE(bho_clsid_as_string));
54 CComBSTR bho_clsid_as_string_bstr(bho_clsid_as_string);
[email protected]9ceda772010-08-30 15:34:1155
[email protected]4c01d63e2010-09-07 18:30:0856 CComVariant existing_bho;
57 HRESULT hr = browser->GetProperty(bho_clsid_as_string_bstr,
58 &existing_bho);
[email protected]9ceda772010-08-30 15:34:1159
[email protected]4c01d63e2010-09-07 18:30:0860 if (existing_bho.vt != VT_DISPATCH || existing_bho.pdispVal == NULL) {
61 // Step 4:
62 // We have the IWebBrowser2 interface. Now create the BHO instance
63 CComPtr<IObjectWithSite> bho_object;
64 hr = bho_object.CoCreateInstance(CLSID_ChromeFrameBHO,
65 NULL,
66 CLSCTX_INPROC_SERVER);
[email protected]9ceda772010-08-30 15:34:1167
[email protected]4c01d63e2010-09-07 18:30:0868 _ASSERTE(bho_object);
69 if (SUCCEEDED(hr) && bho_object) {
70 // Step 5:
71 // Initialize the BHO by calling SetSite and passing it IWebBrowser2
72 hr = bho_object->SetSite(browser);
73 _ASSERTE(bho_object);
74 if (SUCCEEDED(hr)) {
75 // Step 6:
76 // Now add the BHO to the collection of automation objects. This
77 // will ensure that BHO will be accessible from the web pages as
78 // any other BHO. Importantly, it will make sure that our BHO
79 // will be cleaned up at the right time along with other BHOs.
80 CComVariant object_variant(bho_object);
81 browser->PutProperty(bho_clsid_as_string_bstr, object_variant);
82 }
[email protected]9ceda772010-08-30 15:34:1183 }
84 }
85 }
86 }
87 }
88}
89
90bool BHOLoader::StartHook() {
91 return hooker_->StartHook();
92}
93
94void BHOLoader::StopHook() {
95 hooker_->StopHook();
96}
97
98BHOLoader* BHOLoader::GetInstance() {
99 static BHOLoader loader;
100 return &loader;
101}