blob: fb8721ddeb1cd4cd48bf32796b2ad22df078d221 [file] [log] [blame]
[email protected]b4e75c12010-05-18 18:28:481// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]f7817822009-09-24 05:11:582// 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_activex.h"
6
[email protected]f7817822009-09-24 05:11:587#include <wininet.h>
8
9#include <algorithm>
[email protected]2b19e2fe2010-02-16 02:24:1810#include <map>
[email protected]f7817822009-09-24 05:11:5811
12#include "base/basictypes.h"
13#include "base/command_line.h"
14#include "base/file_util.h"
15#include "base/logging.h"
16#include "base/path_service.h"
17#include "base/process_util.h"
18#include "base/scoped_bstr_win.h"
[email protected]2b19e2fe2010-02-16 02:24:1819#include "base/singleton.h"
[email protected]f7817822009-09-24 05:11:5820#include "base/string_util.h"
[email protected]04e3f352010-05-10 13:48:2421#include "base/trace_event.h"
[email protected]f7817822009-09-24 05:11:5822#include "chrome/common/chrome_constants.h"
23#include "chrome/common/chrome_switches.h"
24#include "chrome/test/automation/tab_proxy.h"
25#include "googleurl/src/gurl.h"
[email protected]f7817822009-09-24 05:11:5826#include "chrome_frame/utils.h"
27
[email protected]2b19e2fe2010-02-16 02:24:1828namespace {
29
30// Class used to maintain a mapping from top-level windows to ChromeFrameActivex
31// instances.
32class TopLevelWindowMapping {
33 public:
34 typedef std::vector<HWND> WindowList;
35
36 static TopLevelWindowMapping* instance() {
37 return Singleton<TopLevelWindowMapping>::get();
38 }
39
40 // Add |cf_window| to the set of windows registered under |top_window|.
41 void AddMapping(HWND top_window, HWND cf_window) {
42 top_window_map_lock_.Lock();
43 top_window_map_[top_window].push_back(cf_window);
44 top_window_map_lock_.Unlock();
45 }
46
47 // Return the set of Chrome-Frame instances under |window|.
48 WindowList GetInstances(HWND window) {
49 top_window_map_lock_.Lock();
50 WindowList list = top_window_map_[window];
51 top_window_map_lock_.Unlock();
52 return list;
53 }
54
55 private:
56 // Constructor is private as this class it to be used as a singleton.
57 // See static method instance().
58 TopLevelWindowMapping() {}
59
60 friend struct DefaultSingletonTraits<TopLevelWindowMapping>;
61
62 typedef std::map<HWND, WindowList> TopWindowMap;
63 TopWindowMap top_window_map_;
64
65 CComAutoCriticalSection top_window_map_lock_;
66
67 DISALLOW_COPY_AND_ASSIGN(TopLevelWindowMapping);
68};
69
70// Message pump hook function that monitors for WM_MOVE and WM_MOVING
71// messages on a top-level window, and passes notification to the appropriate
72// Chrome-Frame instances.
73LRESULT CALLBACK TopWindowProc(int code, WPARAM wparam, LPARAM lparam) {
74 CWPSTRUCT *info = reinterpret_cast<CWPSTRUCT*>(lparam);
75 const UINT &message = info->message;
76 const HWND &message_hwnd = info->hwnd;
77
78 switch (message) {
79 case WM_MOVE:
80 case WM_MOVING: {
81 TopLevelWindowMapping::WindowList cf_instances =
82 TopLevelWindowMapping::instance()->GetInstances(message_hwnd);
83 TopLevelWindowMapping::WindowList::iterator
84 iter(cf_instances.begin()), end(cf_instances.end());
85 for (;iter != end; ++iter) {
86 PostMessage(*iter, WM_HOST_MOVED_NOTIFICATION, NULL, NULL);
87 }
88 break;
89 }
90 default:
91 break;
92 }
93
94 return CallNextHookEx(0, code, wparam, lparam);
95}
96
97HHOOK InstallLocalWindowHook(HWND window) {
98 if (!window)
99 return NULL;
100
101 DWORD proc_thread = ::GetWindowThreadProcessId(window, NULL);
102 if (!proc_thread)
103 return NULL;
104
105 // Note that this hook is installed as a LOCAL hook.
106 return ::SetWindowsHookEx(WH_CALLWNDPROC,
107 TopWindowProc,
108 NULL,
109 proc_thread);
110}
111
112} // unnamed namespace
113
114ChromeFrameActivex::ChromeFrameActivex()
115 : chrome_wndproc_hook_(NULL) {
[email protected]04e3f352010-05-10 13:48:24116 TRACE_EVENT_BEGIN("chromeframe.createactivex", this, "");
[email protected]f7817822009-09-24 05:11:58117}
118
119HRESULT ChromeFrameActivex::FinalConstruct() {
120 HRESULT hr = Base::FinalConstruct();
121 if (FAILED(hr))
122 return hr;
123
124 // No need to call FireOnChanged at this point since nobody will be listening.
125 ready_state_ = READYSTATE_LOADING;
126 return S_OK;
127}
128
129ChromeFrameActivex::~ChromeFrameActivex() {
130 // We expect these to be released during a call to SetClientSite(NULL).
[email protected]efd4dfc22010-03-26 20:14:40131 DCHECK_EQ(0, onmessage_.size());
132 DCHECK_EQ(0, onloaderror_.size());
133 DCHECK_EQ(0, onload_.size());
134 DCHECK_EQ(0, onreadystatechanged_.size());
135 DCHECK_EQ(0, onextensionready_.size());
[email protected]3eb07da2010-02-01 19:48:36136
[email protected]2b19e2fe2010-02-16 02:24:18137 if (chrome_wndproc_hook_) {
138 BOOL unhook_success = ::UnhookWindowsHookEx(chrome_wndproc_hook_);
139 DCHECK(unhook_success);
140 }
141
[email protected]3eb07da2010-02-01 19:48:36142 // ChromeFramePlugin::Uninitialize()
143 Base::Uninitialize();
[email protected]04e3f352010-05-10 13:48:24144
145 TRACE_EVENT_END("chromeframe.createactivex", this, "");
[email protected]f7817822009-09-24 05:11:58146}
147
148LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
149 BOOL& handled) {
150 Base::OnCreate(message, wparam, lparam, handled);
[email protected]2b19e2fe2010-02-16 02:24:18151 // Install the notification hook on the top-level window, so that we can
152 // be notified on move events. Note that the return value is not checked.
153 // This hook is installed here, as opposed to during IOleObject_SetClientSite
154 // because m_hWnd has not yet been assigned during the SetSite call.
155 InstallTopLevelHook(m_spClientSite);
156 return 0;
157}
158
159LRESULT ChromeFrameActivex::OnHostMoved(UINT message, WPARAM wparam,
160 LPARAM lparam, BOOL& handled) {
161 Base::OnHostMoved();
[email protected]f7817822009-09-24 05:11:58162 return 0;
163}
164
[email protected]f7817822009-09-24 05:11:58165HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
166 ScopedComPtr<IOleContainer> container;
167 HRESULT hr = m_spClientSite->GetContainer(container.Receive());
168 if (container)
169 hr = container.QueryInterface(doc);
170 return hr;
171}
172
173HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
174 ScopedComPtr<IHTMLDocument2> document;
175 HRESULT hr = GetContainingDocument(document.Receive());
176 if (document)
177 hr = document->get_parentWindow(window);
178 return hr;
179}
180
181void ChromeFrameActivex::OnLoad(int tab_handle, const GURL& gurl) {
182 ScopedComPtr<IDispatch> event;
183 std::string url = gurl.spec();
184 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
185 Fire_onload(event);
186
187 FireEvent(onload_, url);
[email protected]a1800e82009-11-19 00:53:23188 Base::OnLoad(tab_handle, gurl);
[email protected]f7817822009-09-24 05:11:58189}
190
191void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
192 ScopedComPtr<IDispatch> event;
193 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
194 Fire_onloaderror(event);
195
196 FireEvent(onloaderror_, url);
[email protected]a1800e82009-11-19 00:53:23197 Base::OnLoadFailed(error_code, url);
[email protected]f7817822009-09-24 05:11:58198}
199
200void ChromeFrameActivex::OnMessageFromChromeFrame(int tab_handle,
201 const std::string& message,
202 const std::string& origin,
203 const std::string& target) {
204 DLOG(INFO) << __FUNCTION__;
205
206 if (target.compare("*") != 0) {
207 bool drop = true;
208
209 if (is_privileged_) {
210 // Forward messages if the control is in privileged mode.
211 ScopedComPtr<IDispatch> message_event;
212 if (SUCCEEDED(CreateDomEvent("message", message, origin,
213 message_event.Receive()))) {
214 ScopedBstr target_bstr(UTF8ToWide(target).c_str());
215 Fire_onprivatemessage(message_event, target_bstr);
216
217 FireEvent(onprivatemessage_, message_event, target_bstr);
218 }
219 } else {
220 if (HaveSameOrigin(target, document_url_)) {
221 drop = false;
222 } else {
223 DLOG(WARNING) << "Dropping posted message since target doesn't match "
224 "the current document's origin. target=" << target;
225 }
226 }
227
228 if (drop)
229 return;
230 }
231
232 ScopedComPtr<IDispatch> message_event;
233 if (SUCCEEDED(CreateDomEvent("message", message, origin,
234 message_event.Receive()))) {
235 Fire_onmessage(message_event);
236
237 FireEvent(onmessage_, message_event);
238
239 ScopedVariant event_var;
240 event_var.Set(static_cast<IDispatch*>(message_event));
241 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
242 }
243}
244
245void ChromeFrameActivex::OnAutomationServerLaunchFailed(
246 AutomationLaunchResult reason, const std::string& server_version) {
247 Base::OnAutomationServerLaunchFailed(reason, server_version);
248
249 if (reason == AUTOMATION_VERSION_MISMATCH) {
250 DisplayVersionMismatchWarning(m_hWnd, server_version);
251 }
252}
253
[email protected]00f6b772009-10-23 17:03:41254void ChromeFrameActivex::OnExtensionInstalled(
255 const FilePath& path,
256 void* user_data,
257 AutomationMsg_ExtensionResponseValues response) {
258 ScopedBstr path_str(path.value().c_str());
259 Fire_onextensionready(path_str, response);
260}
261
[email protected]a1e62d12010-03-16 02:18:43262void ChromeFrameActivex::OnGetEnabledExtensionsComplete(
263 void* user_data,
264 const std::vector<FilePath>& extension_directories) {
265 SAFEARRAY* sa = ::SafeArrayCreateVector(VT_BSTR, 0,
266 extension_directories.size());
267 sa->fFeatures = sa->fFeatures | FADF_BSTR;
268 ::SafeArrayLock(sa);
269
270 for (size_t i = 0; i < extension_directories.size(); ++i) {
271 LONG index = static_cast<LONG>(i);
272 ::SafeArrayPutElement(sa, &index, reinterpret_cast<void*>(
273 CComBSTR(extension_directories[i].ToWStringHack().c_str()).Detach()));
274 }
275
276 Fire_ongetenabledextensionscomplete(sa);
277 ::SafeArrayUnlock(sa);
278 ::SafeArrayDestroy(sa);
279}
280
[email protected]efd4dfc22010-03-26 20:14:40281void ChromeFrameActivex::OnChannelError() {
282 Fire_onchannelerror();
283}
284
285HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
[email protected]f7817822009-09-24 05:11:58286 HRESULT hr = S_OK;
287 int dc_type = ::GetObjectType(draw_info.hicTargetDev);
288 if (dc_type == OBJ_ENHMETADC) {
289 RECT print_bounds = {0};
290 print_bounds.left = draw_info.prcBounds->left;
291 print_bounds.right = draw_info.prcBounds->right;
292 print_bounds.top = draw_info.prcBounds->top;
293 print_bounds.bottom = draw_info.prcBounds->bottom;
294
295 automation_client_->Print(draw_info.hdcDraw, print_bounds);
296 } else {
297 hr = Base::OnDraw(draw_info);
298 }
299
300 return hr;
301}
302
303STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
304 DCHECK(bag);
305
306 const wchar_t* event_props[] = {
307 (L"onload"),
308 (L"onloaderror"),
309 (L"onmessage"),
310 (L"onreadystatechanged"),
311 };
312
313 ScopedComPtr<IHTMLObjectElement> obj_element;
314 GetObjectElement(obj_element.Receive());
315
316 ScopedBstr object_id;
317 GetObjectScriptId(obj_element, object_id.Receive());
318
319 ScopedComPtr<IHTMLElement2> element;
320 element.QueryFrom(obj_element);
321 HRESULT hr = S_OK;
322
323 for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
324 ScopedBstr prop(event_props[i]);
325 ScopedVariant value;
326 if (SUCCEEDED(bag->Read(prop, value.Receive(), error_log))) {
327 if (value.type() != VT_BSTR ||
328 FAILED(hr = CreateScriptBlockForEvent(element, object_id,
329 V_BSTR(&value), prop))) {
330 DLOG(ERROR) << "Failed to create script block for " << prop
331 << StringPrintf(L"hr=0x%08X, vt=%i", hr, value.type());
332 } else {
333 DLOG(INFO) << "script block created for event " << prop <<
334 StringPrintf(" (0x%08X)", hr) << " connections: " <<
335 ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
336 }
337 } else {
338 DLOG(INFO) << "event property " << prop << " not in property bag";
339 }
340 }
341
342 ScopedVariant src;
343 if (SUCCEEDED(bag->Read(StackBstr(L"src"), src.Receive(), error_log))) {
344 if (src.type() == VT_BSTR) {
345 hr = put_src(V_BSTR(&src));
346 DCHECK(hr != E_UNEXPECTED);
347 }
348 }
349
350 ScopedVariant use_chrome_network;
351 if (SUCCEEDED(bag->Read(StackBstr(L"useChromeNetwork"),
352 use_chrome_network.Receive(), error_log))) {
353 VariantChangeType(use_chrome_network.AsInput(),
354 use_chrome_network.AsInput(),
355 0, VT_BOOL);
356 if (use_chrome_network.type() == VT_BOOL) {
357 hr = put_useChromeNetwork(V_BOOL(&use_chrome_network));
358 DCHECK(hr != E_UNEXPECTED);
359 }
360 }
361
362 DLOG_IF(ERROR, FAILED(hr))
363 << StringPrintf("Failed to load property bag: 0x%08X", hr);
364
365 return hr;
366}
367
[email protected]b4e75c12010-05-18 18:28:48368const wchar_t g_activex_insecure_content_error[] = {
[email protected]f7817822009-09-24 05:11:58369 L"data:text/html,<html><body><b>ChromeFrame Security Error<br><br>"
370 L"Cannot navigate to HTTP url when document URL is HTTPS</body></html>"};
[email protected]2b8fd322009-10-02 00:00:59371
[email protected]f7817822009-09-24 05:11:58372STDMETHODIMP ChromeFrameActivex::put_src(BSTR src) {
373 GURL document_url(GetDocumentUrl());
374 if (document_url.SchemeIsSecure()) {
375 GURL source_url(src);
376 if (!source_url.SchemeIsSecure()) {
[email protected]b4e75c12010-05-18 18:28:48377 Base::put_src(ScopedBstr(g_activex_insecure_content_error));
[email protected]f7817822009-09-24 05:11:58378 return E_ACCESSDENIED;
379 }
380 }
381 return Base::put_src(src);
382}
383
384HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
385 IOleClientSite* client_site) {
386 HRESULT hr = Base::IOleObject_SetClientSite(client_site);
387 if (FAILED(hr) || !client_site) {
388 EventHandlers* handlers[] = {
389 &onmessage_,
390 &onloaderror_,
391 &onload_,
392 &onreadystatechanged_,
[email protected]00f6b772009-10-23 17:03:41393 &onextensionready_,
[email protected]f7817822009-09-24 05:11:58394 };
395
396 for (int i = 0; i < arraysize(handlers); ++i)
397 handlers[i]->clear();
398
399 // Drop privileged mode on uninitialization.
400 is_privileged_ = false;
401 } else {
402 ScopedComPtr<IHTMLDocument2> document;
403 GetContainingDocument(document.Receive());
404 if (document) {
405 ScopedBstr url;
406 if (SUCCEEDED(document->get_URL(url.Receive())))
407 WideToUTF8(url, url.Length(), &document_url_);
408 }
409
410 // Probe to see whether the host implements the privileged service.
411 ScopedComPtr<IChromeFramePrivileged> service;
412 HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged, client_site,
413 service.Receive());
414 if (SUCCEEDED(service_hr) && service) {
415 // Does the host want privileged mode?
416 boolean wants_privileged = false;
417 service_hr = service->GetWantsPrivileged(&wants_privileged);
418
419 if (SUCCEEDED(service_hr) && wants_privileged)
420 is_privileged_ = true;
[email protected]7403d38f2010-03-22 22:50:49421
422 url_fetcher_.set_privileged_mode(is_privileged_);
[email protected]f7817822009-09-24 05:11:58423 }
424
425 std::wstring chrome_extra_arguments;
426 std::wstring profile_name(GetHostProcessName(false));
427 if (is_privileged_) {
428 // Does the host want to provide extra arguments?
429 ScopedBstr extra_arguments_arg;
430 service_hr = service->GetChromeExtraArguments(
431 extra_arguments_arg.Receive());
432 if (S_OK == service_hr && extra_arguments_arg)
433 chrome_extra_arguments.assign(extra_arguments_arg,
434 extra_arguments_arg.Length());
435
[email protected]50f53162009-10-23 19:16:20436 ScopedBstr automated_functions_arg;
437 service_hr = service->GetExtensionApisToAutomate(
438 automated_functions_arg.Receive());
439 if (S_OK == service_hr && automated_functions_arg) {
440 std::string automated_functions(
441 WideToASCII(static_cast<BSTR>(automated_functions_arg)));
442 functions_enabled_.clear();
443 // SplitString writes one empty entry for blank strings, so we need this
444 // to allow specifying zero automation of API functions.
445 if (!automated_functions.empty())
446 SplitString(automated_functions, ',', &functions_enabled_);
447 }
448
[email protected]f7817822009-09-24 05:11:58449 ScopedBstr profile_name_arg;
450 service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
451 if (S_OK == service_hr && profile_name_arg)
452 profile_name.assign(profile_name_arg, profile_name_arg.Length());
453 }
454
[email protected]3eb07da2010-02-01 19:48:36455 url_fetcher_.set_frame_busting(!is_privileged_);
456 automation_client_->SetUrlFetcher(&url_fetcher_);
[email protected]f7817822009-09-24 05:11:58457 if (!InitializeAutomation(profile_name, chrome_extra_arguments,
[email protected]f7019302010-03-26 19:58:32458 IsIEInPrivate(), true)) {
[email protected]f7817822009-09-24 05:11:58459 return E_FAIL;
460 }
461 }
462
463 return hr;
464}
465
466HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
467 BSTR* id) {
468 DCHECK(object_elem != NULL);
469 DCHECK(id != NULL);
470
471 HRESULT hr = E_FAIL;
472 if (object_elem) {
473 ScopedComPtr<IHTMLElement> elem;
474 hr = elem.QueryFrom(object_elem);
475 if (elem) {
476 hr = elem->get_id(id);
477 }
478 }
479
480 return hr;
481}
482
483HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
484 DCHECK(m_spClientSite);
485 if (!m_spClientSite)
486 return E_UNEXPECTED;
487
488 ScopedComPtr<IOleControlSite> site;
489 HRESULT hr = site.QueryFrom(m_spClientSite);
490 if (site) {
491 ScopedComPtr<IDispatch> disp;
492 hr = site->GetExtendedControl(disp.Receive());
493 if (disp) {
494 hr = disp.QueryInterface(element);
495 } else {
496 DCHECK(FAILED(hr));
497 }
498 }
499
500 return hr;
501}
502
503HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
504 IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
505 BSTR event_name) {
506 DCHECK(insert_after);
[email protected]efd4dfc22010-03-26 20:14:40507 DCHECK_GT(::SysStringLen(event_name), 0UL); // should always have this
[email protected]f7817822009-09-24 05:11:58508
509 // This might be 0 if not specified in the HTML document.
510 if (!::SysStringLen(instance_id)) {
511 // TODO(tommi): Should we give ourselves an ID if this happens?
512 NOTREACHED() << "Need to handle this";
513 return E_INVALIDARG;
514 }
515
516 ScopedComPtr<IHTMLDocument2> document;
517 HRESULT hr = GetContainingDocument(document.Receive());
518 if (SUCCEEDED(hr)) {
519 ScopedComPtr<IHTMLElement> element, new_element;
520 document->createElement(StackBstr(L"script"), element.Receive());
521 if (element) {
522 ScopedComPtr<IHTMLScriptElement> script_element;
523 if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
524 script_element->put_htmlFor(instance_id);
525 script_element->put_event(event_name);
526 script_element->put_text(script);
527
528 hr = insert_after->insertAdjacentElement(StackBstr(L"afterEnd"),
529 element,
530 new_element.Receive());
531 }
532 }
533 }
534
535 return hr;
536}
537
[email protected]f7817822009-09-24 05:11:58538void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
539 const std::string& arg) {
540 if (handlers.size()) {
541 ScopedComPtr<IDispatch> event;
542 if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
543 FireEvent(handlers, event);
544 }
545 }
546}
547
548void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
549 IDispatch* event) {
550 DCHECK(event != NULL);
551 VARIANT arg = { VT_DISPATCH };
552 arg.pdispVal = event;
553 DISPPARAMS params = { &arg, NULL, 1, 0 };
554 for (EventHandlers::const_iterator it = handlers.begin();
555 it != handlers.end();
556 ++it) {
557 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
558 DISPATCH_METHOD, &params, NULL, NULL, NULL);
559 // 0x80020101 == SCRIPT_E_REPORTED.
560 // When the script we're invoking has an error, we get this error back.
561 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
562 << StringPrintf(L"Failed to invoke script: 0x%08X", hr);
563 }
564}
565
566void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
567 IDispatch* event, BSTR target) {
568 DCHECK(event != NULL);
569 // Arguments in reverse order to event handler function declaration,
570 // because that's what DISPPARAMS requires.
571 VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
572 args[0].bstrVal = target;
573 args[1].pdispVal = event;
574 DISPPARAMS params = { args, NULL, arraysize(args), 0 };
575 for (EventHandlers::const_iterator it = handlers.begin();
576 it != handlers.end();
577 ++it) {
578 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
579 DISPATCH_METHOD, &params, NULL, NULL, NULL);
580 // 0x80020101 == SCRIPT_E_REPORTED.
581 // When the script we're invoking has an error, we get this error back.
582 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
583 << StringPrintf(L"Failed to invoke script: 0x%08X", hr);
584 }
585}
[email protected]2b19e2fe2010-02-16 02:24:18586
587HRESULT ChromeFrameActivex::InstallTopLevelHook(IOleClientSite* client_site) {
588 // Get the parent window of the site, and install our hook on the topmost
589 // window of the parent.
590 ScopedComPtr<IOleWindow> ole_window;
591 HRESULT hr = ole_window.QueryFrom(client_site);
592 if (FAILED(hr))
593 return hr;
594
595 HWND parent_wnd;
596 hr = ole_window->GetWindow(&parent_wnd);
597 if (FAILED(hr))
598 return hr;
599
600 HWND top_window = ::GetAncestor(parent_wnd, GA_ROOT);
601 chrome_wndproc_hook_ = InstallLocalWindowHook(top_window);
602 if (chrome_wndproc_hook_)
603 TopLevelWindowMapping::instance()->AddMapping(top_window, m_hWnd);
604
605 return chrome_wndproc_hook_ ? S_OK : E_FAIL;
606}
[email protected]c442e9f2010-04-29 18:37:44607
[email protected]ca982ec42010-05-02 14:47:14608HRESULT ChromeFrameActivex::registerBhoIfNeeded() {
609 if (!m_spUnkSite) {
[email protected]c442e9f2010-04-29 18:37:44610 NOTREACHED() << "Invalid client site";
611 return E_FAIL;
612 }
613
614 if (NavigationManager::GetThreadInstance() != NULL) {
615 DLOG(INFO) << "BHO already loaded";
616 return S_OK;
617 }
618
619 ScopedComPtr<IWebBrowser2> web_browser2;
[email protected]ca982ec42010-05-02 14:47:14620 HRESULT hr = DoQueryService(SID_SWebBrowserApp, m_spUnkSite,
[email protected]c442e9f2010-04-29 18:37:44621 web_browser2.Receive());
622 if (FAILED(hr) || web_browser2.get() == NULL) {
623 DLOG(WARNING) << "Failed to get IWebBrowser2 from client site. Error:"
624 << StringPrintf(" 0x%08X", hr);
625 return hr;
626 }
627
628 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
629 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
630 arraysize(bho_class_id_as_string));
631
632 ScopedComPtr<IObjectWithSite> bho;
633 hr = bho.CreateInstance(CLSID_ChromeFrameBHO, NULL, CLSCTX_INPROC_SERVER);
634 if (FAILED(hr)) {
635 NOTREACHED() << "Failed to register ChromeFrame BHO. Error:"
636 << StringPrintf(" 0x%08X", hr);
637 return hr;
638 }
639
640 hr = bho->SetSite(web_browser2);
641 if (FAILED(hr)) {
642 NOTREACHED() << "ChromeFrame BHO SetSite failed. Error:"
643 << StringPrintf(" 0x%08X", hr);
644 return hr;
645 }
646
647 web_browser2->PutProperty(ScopedBstr(bho_class_id_as_string),
648 ScopedVariant(bho));
649 return S_OK;
650}