app_list: Fix sync animation crash.
[chromium-blink-merge.git] / chrome_frame / chrome_frame_activex.cc
blob9a76b78c5de09bce5a3f1a528a670d33caff8de3
1 // Copyright (c) 2012 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.
5 #include "chrome_frame/chrome_frame_activex.h"
7 #include <wininet.h>
9 #include <algorithm>
10 #include <map>
12 #include "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h"
15 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "base/path_service.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/win/scoped_bstr.h"
23 #include "base/win/scoped_variant.h"
24 #include "chrome/common/automation_messages.h"
25 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/test/automation/tab_proxy.h"
28 #include "chrome_frame/utils.h"
29 #include "url/gurl.h"
31 namespace {
33 // Class used to maintain a mapping from top-level windows to ChromeFrameActivex
34 // instances.
35 class TopLevelWindowMapping {
36 public:
37 typedef std::vector<HWND> WindowList;
39 static TopLevelWindowMapping* GetInstance() {
40 return Singleton<TopLevelWindowMapping>::get();
43 // Add |cf_window| to the set of windows registered under |top_window|.
44 void AddMapping(HWND top_window, HWND cf_window) {
45 top_window_map_lock_.Lock();
46 top_window_map_[top_window].push_back(cf_window);
47 top_window_map_lock_.Unlock();
50 // Return the set of Chrome-Frame instances under |window|.
51 WindowList GetInstances(HWND window) {
52 top_window_map_lock_.Lock();
53 WindowList list = top_window_map_[window];
54 top_window_map_lock_.Unlock();
55 return list;
58 private:
59 // Constructor is private as this class it to be used as a singleton.
60 // See static method instance().
61 TopLevelWindowMapping() {}
63 friend struct DefaultSingletonTraits<TopLevelWindowMapping>;
65 typedef std::map<HWND, WindowList> TopWindowMap;
66 TopWindowMap top_window_map_;
68 CComAutoCriticalSection top_window_map_lock_;
70 DISALLOW_COPY_AND_ASSIGN(TopLevelWindowMapping);
73 // Message pump hook function that monitors for WM_MOVE and WM_MOVING
74 // messages on a top-level window, and passes notification to the appropriate
75 // Chrome-Frame instances.
76 LRESULT CALLBACK TopWindowProc(int code, WPARAM wparam, LPARAM lparam) {
77 CWPSTRUCT* info = reinterpret_cast<CWPSTRUCT*>(lparam);
78 const UINT &message = info->message;
79 const HWND &message_hwnd = info->hwnd;
81 switch (message) {
82 case WM_MOVE:
83 case WM_MOVING: {
84 TopLevelWindowMapping::WindowList cf_instances =
85 TopLevelWindowMapping::GetInstance()->GetInstances(message_hwnd);
86 TopLevelWindowMapping::WindowList::iterator
87 iter(cf_instances.begin()), end(cf_instances.end());
88 for (; iter != end; ++iter) {
89 PostMessage(*iter, WM_HOST_MOVED_NOTIFICATION, NULL, NULL);
91 break;
93 default:
94 break;
97 return CallNextHookEx(0, code, wparam, lparam);
100 HHOOK InstallLocalWindowHook(HWND window) {
101 if (!window)
102 return NULL;
104 DWORD proc_thread = ::GetWindowThreadProcessId(window, NULL);
105 if (!proc_thread)
106 return NULL;
108 // Note that this hook is installed as a LOCAL hook.
109 return ::SetWindowsHookEx(WH_CALLWNDPROC,
110 TopWindowProc,
111 NULL,
112 proc_thread);
115 } // unnamed namespace
117 namespace chrome_frame {
118 std::string ActiveXCreateUrl(const GURL& parsed_url,
119 const AttachExternalTabParams& params) {
120 return base::StringPrintf(
121 "%hs?attach_external_tab&%I64u&%d&%d&%d&%d&%d&%hs",
122 parsed_url.GetOrigin().spec().c_str(),
123 params.cookie,
124 params.disposition,
125 params.dimensions.x(),
126 params.dimensions.y(),
127 params.dimensions.width(),
128 params.dimensions.height(),
129 params.profile_name.c_str());
132 int GetDisposition(const AttachExternalTabParams& params) {
133 return params.disposition;
136 void GetMiniContextMenuData(UINT cmd,
137 const MiniContextMenuParams& params,
138 GURL* referrer,
139 GURL* url) {
140 *referrer = params.frame_url.is_empty() ? params.page_url : params.frame_url;
141 *url = (cmd == IDS_CONTENT_CONTEXT_SAVELINKAS ?
142 params.link_url : params.src_url);
145 } // namespace chrome_frame
147 ChromeFrameActivex::ChromeFrameActivex()
148 : chrome_wndproc_hook_(NULL),
149 attaching_to_existing_cf_tab_(false) {
150 TRACE_EVENT_BEGIN_ETW("chromeframe.createactivex", this, "");
153 HRESULT ChromeFrameActivex::FinalConstruct() {
154 HRESULT hr = Base::FinalConstruct();
155 if (FAILED(hr))
156 return hr;
158 // No need to call FireOnChanged at this point since nobody will be listening.
159 ready_state_ = READYSTATE_LOADING;
160 return S_OK;
163 ChromeFrameActivex::~ChromeFrameActivex() {
164 // We expect these to be released during a call to SetClientSite(NULL).
165 DCHECK_EQ(0u, onmessage_.size());
166 DCHECK_EQ(0u, onloaderror_.size());
167 DCHECK_EQ(0u, onload_.size());
168 DCHECK_EQ(0u, onreadystatechanged_.size());
169 DCHECK_EQ(0u, onextensionready_.size());
171 if (chrome_wndproc_hook_) {
172 BOOL unhook_success = ::UnhookWindowsHookEx(chrome_wndproc_hook_);
173 DCHECK(unhook_success);
176 // ChromeFramePlugin::Uninitialize()
177 Base::Uninitialize();
179 TRACE_EVENT_END_ETW("chromeframe.createactivex", this, "");
182 LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
183 BOOL& handled) {
184 Base::OnCreate(message, wparam, lparam, handled);
185 // Install the notification hook on the top-level window, so that we can
186 // be notified on move events. Note that the return value is not checked.
187 // This hook is installed here, as opposed to during IOleObject_SetClientSite
188 // because m_hWnd has not yet been assigned during the SetSite call.
189 InstallTopLevelHook(m_spClientSite);
190 return 0;
193 LRESULT ChromeFrameActivex::OnHostMoved(UINT message, WPARAM wparam,
194 LPARAM lparam, BOOL& handled) {
195 Base::OnHostMoved();
196 return 0;
199 HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
200 base::win::ScopedComPtr<IOleContainer> container;
201 HRESULT hr = m_spClientSite->GetContainer(container.Receive());
202 if (container)
203 hr = container.QueryInterface(doc);
204 return hr;
207 HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
208 base::win::ScopedComPtr<IHTMLDocument2> document;
209 HRESULT hr = GetContainingDocument(document.Receive());
210 if (document)
211 hr = document->get_parentWindow(window);
212 return hr;
215 void ChromeFrameActivex::OnLoad(const GURL& gurl) {
216 base::win::ScopedComPtr<IDispatch> event;
217 std::string url = gurl.spec();
218 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
219 Fire_onload(event);
221 FireEvent(onload_, url);
222 Base::OnLoad(gurl);
225 void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
226 base::win::ScopedComPtr<IDispatch> event;
227 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
228 Fire_onloaderror(event);
230 FireEvent(onloaderror_, url);
231 Base::OnLoadFailed(error_code, url);
234 void ChromeFrameActivex::OnMessageFromChromeFrame(const std::string& message,
235 const std::string& origin,
236 const std::string& target) {
237 DVLOG(1) << __FUNCTION__;
239 if (target.compare("*") != 0) {
240 bool drop = true;
242 if (is_privileged()) {
243 // Forward messages if the control is in privileged mode.
244 base::win::ScopedComPtr<IDispatch> message_event;
245 if (SUCCEEDED(CreateDomEvent("message", message, origin,
246 message_event.Receive()))) {
247 base::win::ScopedBstr target_bstr(UTF8ToWide(target).c_str());
248 Fire_onprivatemessage(message_event, target_bstr);
250 FireEvent(onprivatemessage_, message_event, target_bstr);
252 } else {
253 if (HaveSameOrigin(target, document_url_)) {
254 drop = false;
255 } else {
256 DLOG(WARNING) << "Dropping posted message since target doesn't match "
257 "the current document's origin. target=" << target;
261 if (drop)
262 return;
265 base::win::ScopedComPtr<IDispatch> message_event;
266 if (SUCCEEDED(CreateDomEvent("message", message, origin,
267 message_event.Receive()))) {
268 Fire_onmessage(message_event);
270 FireEvent(onmessage_, message_event);
272 base::win::ScopedVariant event_var;
273 event_var.Set(static_cast<IDispatch*>(message_event));
274 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
278 bool ChromeFrameActivex::ShouldShowVersionMismatchDialog(
279 bool is_privileged,
280 IOleClientSite* client_site) {
281 if (!is_privileged) {
282 return true;
285 if (client_site) {
286 base::win::ScopedComPtr<IChromeFramePrivileged> service;
287 HRESULT hr = DoQueryService(SID_ChromeFramePrivileged,
288 client_site,
289 service.Receive());
290 if (SUCCEEDED(hr) && service) {
291 return (S_FALSE != service->ShouldShowVersionMismatchDialog());
295 NOTREACHED();
296 return true;
299 void ChromeFrameActivex::OnAutomationServerLaunchFailed(
300 AutomationLaunchResult reason, const std::string& server_version) {
301 Base::OnAutomationServerLaunchFailed(reason, server_version);
303 if (reason == AUTOMATION_VERSION_MISMATCH &&
304 ShouldShowVersionMismatchDialog(is_privileged(), m_spClientSite)) {
305 UMA_HISTOGRAM_COUNTS("ChromeFrame.VersionMismatchDisplayed", 1);
306 DisplayVersionMismatchWarning(m_hWnd, server_version);
310 void ChromeFrameActivex::OnChannelError() {
311 Fire_onchannelerror();
314 HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
315 HRESULT hr = S_OK;
316 int dc_type = ::GetObjectType(draw_info.hicTargetDev);
317 if (dc_type == OBJ_ENHMETADC) {
318 RECT print_bounds = {0};
319 print_bounds.left = draw_info.prcBounds->left;
320 print_bounds.right = draw_info.prcBounds->right;
321 print_bounds.top = draw_info.prcBounds->top;
322 print_bounds.bottom = draw_info.prcBounds->bottom;
324 automation_client_->Print(draw_info.hdcDraw, print_bounds);
325 } else {
326 hr = Base::OnDraw(draw_info);
329 return hr;
332 STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
333 DCHECK(bag);
335 const wchar_t* event_props[] = {
336 (L"onload"),
337 (L"onloaderror"),
338 (L"onmessage"),
339 (L"onreadystatechanged"),
342 base::win::ScopedComPtr<IHTMLObjectElement> obj_element;
343 GetObjectElement(obj_element.Receive());
345 base::win::ScopedBstr object_id;
346 GetObjectScriptId(obj_element, object_id.Receive());
348 base::win::ScopedComPtr<IHTMLElement2> element;
349 element.QueryFrom(obj_element);
350 HRESULT hr = S_OK;
352 for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
353 base::win::ScopedBstr prop(event_props[i]);
354 base::win::ScopedVariant value;
355 if (SUCCEEDED(bag->Read(prop, value.Receive(), error_log))) {
356 if (value.type() != VT_BSTR ||
357 FAILED(hr = CreateScriptBlockForEvent(element, object_id,
358 V_BSTR(&value), prop))) {
359 DLOG(ERROR) << "Failed to create script block for " << prop
360 << base::StringPrintf(L"hr=0x%08X, vt=%i", hr,
361 value.type());
362 } else {
363 DVLOG(1) << "script block created for event " << prop
364 << base::StringPrintf(" (0x%08X)", hr) << " connections: " <<
365 ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
367 } else {
368 DVLOG(1) << "event property " << prop << " not in property bag";
372 base::win::ScopedVariant src;
373 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"src"), src.Receive(),
374 error_log))) {
375 if (src.type() == VT_BSTR) {
376 hr = put_src(V_BSTR(&src));
377 DCHECK(hr != E_UNEXPECTED);
381 base::win::ScopedVariant use_chrome_network;
382 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"useChromeNetwork"),
383 use_chrome_network.Receive(), error_log))) {
384 VariantChangeType(use_chrome_network.AsInput(),
385 use_chrome_network.AsInput(),
386 0, VT_BOOL);
387 if (use_chrome_network.type() == VT_BOOL) {
388 hr = put_useChromeNetwork(V_BOOL(&use_chrome_network));
389 DCHECK(hr != E_UNEXPECTED);
393 DLOG_IF(ERROR, FAILED(hr))
394 << base::StringPrintf("Failed to load property bag: 0x%08X", hr);
396 return hr;
399 const wchar_t g_activex_insecure_content_error[] = {
400 L"data:text/html,<html><body><b>ChromeFrame Security Error<br><br>"
401 L"Cannot navigate to HTTP url when document URL is HTTPS</body></html>"};
403 STDMETHODIMP ChromeFrameActivex::put_src(BSTR src) {
404 GURL document_url(GetDocumentUrl());
405 if (document_url.SchemeIsSecure()) {
406 GURL source_url(src);
407 if (!source_url.SchemeIsSecure()) {
408 Base::put_src(base::win::ScopedBstr(g_activex_insecure_content_error));
409 return E_ACCESSDENIED;
412 HRESULT hr = S_OK;
413 // If we are connecting to an existing ExternalTabContainer instance in
414 // Chrome then we should wait for Chrome to initiate the navigation.
415 if (!attaching_to_existing_cf_tab_) {
416 hr = Base::put_src(src);
417 } else {
418 url_.Reset(::SysAllocString(src));
419 attaching_to_existing_cf_tab_ = false;
421 return S_OK;
424 HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
425 IOleClientSite* client_site) {
426 HRESULT hr = Base::IOleObject_SetClientSite(client_site);
427 if (FAILED(hr) || !client_site) {
428 EventHandlers* handlers[] = {
429 &onmessage_,
430 &onloaderror_,
431 &onload_,
432 &onreadystatechanged_,
433 &onextensionready_,
436 for (int i = 0; i < arraysize(handlers); ++i)
437 handlers[i]->clear();
439 // Drop privileged mode on uninitialization.
440 set_is_privileged(false);
441 } else {
442 base::win::ScopedComPtr<IHTMLDocument2> document;
443 GetContainingDocument(document.Receive());
444 if (document) {
445 base::win::ScopedBstr url;
446 if (SUCCEEDED(document->get_URL(url.Receive())))
447 WideToUTF8(url, url.Length(), &document_url_);
450 // Probe to see whether the host implements the privileged service.
451 base::win::ScopedComPtr<IChromeFramePrivileged> service;
452 HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged,
453 m_spClientSite,
454 service.Receive());
455 if (SUCCEEDED(service_hr) && service) {
456 // Does the host want privileged mode?
457 boolean wants_privileged = false;
458 service_hr = service->GetWantsPrivileged(&wants_privileged);
460 if (SUCCEEDED(service_hr) && wants_privileged)
461 set_is_privileged(true);
463 url_fetcher_->set_privileged_mode(is_privileged());
466 std::wstring profile_name(GetHostProcessName(false));
467 if (is_privileged()) {
468 base::win::ScopedBstr profile_name_arg;
469 service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
470 if (S_OK == service_hr && profile_name_arg)
471 profile_name.assign(profile_name_arg, profile_name_arg.Length());
474 std::string utf8_url;
475 if (url_.Length()) {
476 WideToUTF8(url_, url_.Length(), &utf8_url);
479 InitializeAutomationSettings();
481 if (service) {
482 base::win::ScopedBstr navigation_url;
483 service->GetNavigationUrl(navigation_url.Receive());
484 if (navigation_url.Length()) {
485 ChromeFrameUrl cf_url;
486 cf_url.Parse(navigation_url.operator BSTR());
487 if (cf_url.attach_to_external_tab()) {
488 automation_client_->AttachExternalTab(cf_url.cookie());
489 attaching_to_existing_cf_tab_ = true;
493 url_fetcher_->set_frame_busting(!is_privileged());
494 automation_client_->SetUrlFetcher(url_fetcher_.get());
495 if (!InitializeAutomation(profile_name, IsIEInPrivate(), true,
496 GURL(utf8_url), GURL(), false)) {
497 DLOG(ERROR) << "Failed to navigate to url:" << utf8_url;
498 return E_FAIL;
501 // Log a metric that Chrome Frame is being used in Widget mode
502 UMA_LAUNCH_TYPE_COUNT(RENDERER_TYPE_CHROME_WIDGET);
505 return hr;
508 HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
509 BSTR* id) {
510 DCHECK(object_elem != NULL);
511 DCHECK(id != NULL);
513 HRESULT hr = E_FAIL;
514 if (object_elem) {
515 base::win::ScopedComPtr<IHTMLElement> elem;
516 hr = elem.QueryFrom(object_elem);
517 if (elem) {
518 hr = elem->get_id(id);
522 return hr;
525 HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
526 DCHECK(m_spClientSite);
527 if (!m_spClientSite)
528 return E_UNEXPECTED;
530 base::win::ScopedComPtr<IOleControlSite> site;
531 HRESULT hr = site.QueryFrom(m_spClientSite);
532 if (site) {
533 base::win::ScopedComPtr<IDispatch> disp;
534 hr = site->GetExtendedControl(disp.Receive());
535 if (disp) {
536 hr = disp.QueryInterface(element);
537 } else {
538 DCHECK(FAILED(hr));
542 return hr;
545 HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
546 IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
547 BSTR event_name) {
548 DCHECK(insert_after);
549 DCHECK_GT(::SysStringLen(event_name), 0UL); // should always have this
551 // This might be 0 if not specified in the HTML document.
552 if (!::SysStringLen(instance_id)) {
553 // TODO(tommi): Should we give ourselves an ID if this happens?
554 NOTREACHED() << "Need to handle this";
555 return E_INVALIDARG;
558 base::win::ScopedComPtr<IHTMLDocument2> document;
559 HRESULT hr = GetContainingDocument(document.Receive());
560 if (SUCCEEDED(hr)) {
561 base::win::ScopedComPtr<IHTMLElement> element, new_element;
562 document->createElement(base::win::ScopedBstr(L"script"),
563 element.Receive());
564 if (element) {
565 base::win::ScopedComPtr<IHTMLScriptElement> script_element;
566 if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
567 script_element->put_htmlFor(instance_id);
568 script_element->put_event(event_name);
569 script_element->put_text(script);
571 hr = insert_after->insertAdjacentElement(
572 base::win::ScopedBstr(L"afterEnd"),
573 element,
574 new_element.Receive());
579 return hr;
582 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
583 const std::string& arg) {
584 if (handlers.size()) {
585 base::win::ScopedComPtr<IDispatch> event;
586 if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
587 FireEvent(handlers, event);
592 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
593 IDispatch* event) {
594 DCHECK(event != NULL);
595 VARIANT arg = { VT_DISPATCH };
596 arg.pdispVal = event;
597 DISPPARAMS params = { &arg, NULL, 1, 0 };
598 for (EventHandlers::const_iterator it = handlers.begin();
599 it != handlers.end();
600 ++it) {
601 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
602 DISPATCH_METHOD, &params, NULL, NULL, NULL);
603 // 0x80020101 == SCRIPT_E_REPORTED.
604 // When the script we're invoking has an error, we get this error back.
605 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
606 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
610 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
611 IDispatch* event, BSTR target) {
612 DCHECK(event != NULL);
613 // Arguments in reverse order to event handler function declaration,
614 // because that's what DISPPARAMS requires.
615 VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
616 args[0].bstrVal = target;
617 args[1].pdispVal = event;
618 DISPPARAMS params = { args, NULL, arraysize(args), 0 };
619 for (EventHandlers::const_iterator it = handlers.begin();
620 it != handlers.end();
621 ++it) {
622 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
623 DISPATCH_METHOD, &params, NULL, NULL, NULL);
624 // 0x80020101 == SCRIPT_E_REPORTED.
625 // When the script we're invoking has an error, we get this error back.
626 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
627 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
631 HRESULT ChromeFrameActivex::InstallTopLevelHook(IOleClientSite* client_site) {
632 // Get the parent window of the site, and install our hook on the topmost
633 // window of the parent.
634 base::win::ScopedComPtr<IOleWindow> ole_window;
635 HRESULT hr = ole_window.QueryFrom(client_site);
636 if (FAILED(hr))
637 return hr;
639 HWND parent_wnd;
640 hr = ole_window->GetWindow(&parent_wnd);
641 if (FAILED(hr))
642 return hr;
644 HWND top_window = ::GetAncestor(parent_wnd, GA_ROOT);
645 chrome_wndproc_hook_ = InstallLocalWindowHook(top_window);
646 if (chrome_wndproc_hook_)
647 TopLevelWindowMapping::GetInstance()->AddMapping(top_window, m_hWnd);
649 return chrome_wndproc_hook_ ? S_OK : E_FAIL;
652 HRESULT ChromeFrameActivex::registerBhoIfNeeded() {
653 if (!m_spUnkSite) {
654 NOTREACHED() << "Invalid client site";
655 return E_FAIL;
658 if (NavigationManager::GetThreadInstance() != NULL) {
659 DVLOG(1) << "BHO already loaded";
660 return S_OK;
663 base::win::ScopedComPtr<IWebBrowser2> web_browser2;
664 HRESULT hr = DoQueryService(SID_SWebBrowserApp, m_spUnkSite,
665 web_browser2.Receive());
666 if (FAILED(hr) || web_browser2.get() == NULL) {
667 DLOG(WARNING) << "Failed to get IWebBrowser2 from client site. Error:"
668 << base::StringPrintf(" 0x%08X", hr);
669 return hr;
672 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
673 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
674 arraysize(bho_class_id_as_string));
676 base::win::ScopedComPtr<IObjectWithSite> bho;
677 hr = bho.CreateInstance(CLSID_ChromeFrameBHO, NULL, CLSCTX_INPROC_SERVER);
678 if (FAILED(hr)) {
679 NOTREACHED() << "Failed to register ChromeFrame BHO. Error:"
680 << base::StringPrintf(" 0x%08X", hr);
681 return hr;
684 hr = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT_REFRESH, NULL, 0, 0);
685 if (FAILED(hr)) {
686 DLOG(ERROR) << "Failed to refresh user agent string from registry. "
687 << "UrlMkSetSessionOption returned "
688 << base::StringPrintf("0x%08x", hr);
689 return hr;
692 hr = bho->SetSite(web_browser2);
693 if (FAILED(hr)) {
694 NOTREACHED() << "ChromeFrame BHO SetSite failed. Error:"
695 << base::StringPrintf(" 0x%08X", hr);
696 return hr;
699 web_browser2->PutProperty(base::win::ScopedBstr(bho_class_id_as_string),
700 base::win::ScopedVariant(bho));
701 return S_OK;