Disable PerformanceMonitorBrowserTest.DisableAndEnableExtensionEvent on non-debug...
[chromium-blink-merge.git] / chrome_frame / chrome_frame_activex.cc
blob654f6407c4dca61c3b8ef99dc832105fc01dfd19
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.
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/file_util.h"
16 #include "base/logging.h"
17 #include "base/memory/singleton.h"
18 #include "base/path_service.h"
19 #include "base/process_util.h"
20 #include "base/string_split.h"
21 #include "base/string_util.h"
22 #include "base/stringprintf.h"
23 #include "base/utf_string_conversions.h"
24 #include "base/win/scoped_bstr.h"
25 #include "base/win/scoped_variant.h"
26 #include "chrome/common/automation_messages.h"
27 #include "chrome/common/chrome_constants.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/test/automation/tab_proxy.h"
30 #include "chrome_frame/utils.h"
31 #include "googleurl/src/gurl.h"
33 namespace {
35 // Class used to maintain a mapping from top-level windows to ChromeFrameActivex
36 // instances.
37 class TopLevelWindowMapping {
38 public:
39 typedef std::vector<HWND> WindowList;
41 static TopLevelWindowMapping* GetInstance() {
42 return Singleton<TopLevelWindowMapping>::get();
45 // Add |cf_window| to the set of windows registered under |top_window|.
46 void AddMapping(HWND top_window, HWND cf_window) {
47 top_window_map_lock_.Lock();
48 top_window_map_[top_window].push_back(cf_window);
49 top_window_map_lock_.Unlock();
52 // Return the set of Chrome-Frame instances under |window|.
53 WindowList GetInstances(HWND window) {
54 top_window_map_lock_.Lock();
55 WindowList list = top_window_map_[window];
56 top_window_map_lock_.Unlock();
57 return list;
60 private:
61 // Constructor is private as this class it to be used as a singleton.
62 // See static method instance().
63 TopLevelWindowMapping() {}
65 friend struct DefaultSingletonTraits<TopLevelWindowMapping>;
67 typedef std::map<HWND, WindowList> TopWindowMap;
68 TopWindowMap top_window_map_;
70 CComAutoCriticalSection top_window_map_lock_;
72 DISALLOW_COPY_AND_ASSIGN(TopLevelWindowMapping);
75 // Message pump hook function that monitors for WM_MOVE and WM_MOVING
76 // messages on a top-level window, and passes notification to the appropriate
77 // Chrome-Frame instances.
78 LRESULT CALLBACK TopWindowProc(int code, WPARAM wparam, LPARAM lparam) {
79 CWPSTRUCT *info = reinterpret_cast<CWPSTRUCT*>(lparam);
80 const UINT &message = info->message;
81 const HWND &message_hwnd = info->hwnd;
83 switch (message) {
84 case WM_MOVE:
85 case WM_MOVING: {
86 TopLevelWindowMapping::WindowList cf_instances =
87 TopLevelWindowMapping::GetInstance()->GetInstances(message_hwnd);
88 TopLevelWindowMapping::WindowList::iterator
89 iter(cf_instances.begin()), end(cf_instances.end());
90 for (;iter != end; ++iter) {
91 PostMessage(*iter, WM_HOST_MOVED_NOTIFICATION, NULL, NULL);
93 break;
95 default:
96 break;
99 return CallNextHookEx(0, code, wparam, lparam);
102 HHOOK InstallLocalWindowHook(HWND window) {
103 if (!window)
104 return NULL;
106 DWORD proc_thread = ::GetWindowThreadProcessId(window, NULL);
107 if (!proc_thread)
108 return NULL;
110 // Note that this hook is installed as a LOCAL hook.
111 return ::SetWindowsHookEx(WH_CALLWNDPROC,
112 TopWindowProc,
113 NULL,
114 proc_thread);
117 } // unnamed namespace
119 namespace chrome_frame {
120 std::string ActiveXCreateUrl(const GURL& parsed_url,
121 const AttachExternalTabParams& params) {
122 return base::StringPrintf(
123 "%hs?attach_external_tab&%I64u&%d&%d&%d&%d&%d&%hs",
124 parsed_url.GetOrigin().spec().c_str(),
125 params.cookie,
126 params.disposition,
127 params.dimensions.x(),
128 params.dimensions.y(),
129 params.dimensions.width(),
130 params.dimensions.height(),
131 params.profile_name.c_str());
134 int GetDisposition(const AttachExternalTabParams& params) {
135 return params.disposition;
138 void GetMiniContextMenuData(UINT cmd,
139 const MiniContextMenuParams& params,
140 GURL* referrer,
141 GURL* url) {
142 *referrer = params.frame_url.is_empty() ? params.page_url : params.frame_url;
143 *url = (cmd == IDS_CONTENT_CONTEXT_SAVELINKAS ?
144 params.link_url : params.src_url);
147 } // namespace chrome_frame
149 ChromeFrameActivex::ChromeFrameActivex()
150 : chrome_wndproc_hook_(NULL) {
151 TRACE_EVENT_BEGIN_ETW("chromeframe.createactivex", this, "");
154 HRESULT ChromeFrameActivex::FinalConstruct() {
155 HRESULT hr = Base::FinalConstruct();
156 if (FAILED(hr))
157 return hr;
159 // No need to call FireOnChanged at this point since nobody will be listening.
160 ready_state_ = READYSTATE_LOADING;
161 return S_OK;
164 ChromeFrameActivex::~ChromeFrameActivex() {
165 // We expect these to be released during a call to SetClientSite(NULL).
166 DCHECK_EQ(0u, onmessage_.size());
167 DCHECK_EQ(0u, onloaderror_.size());
168 DCHECK_EQ(0u, onload_.size());
169 DCHECK_EQ(0u, onreadystatechanged_.size());
170 DCHECK_EQ(0u, onextensionready_.size());
172 if (chrome_wndproc_hook_) {
173 BOOL unhook_success = ::UnhookWindowsHookEx(chrome_wndproc_hook_);
174 DCHECK(unhook_success);
177 // ChromeFramePlugin::Uninitialize()
178 Base::Uninitialize();
180 TRACE_EVENT_END_ETW("chromeframe.createactivex", this, "");
183 LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
184 BOOL& handled) {
185 Base::OnCreate(message, wparam, lparam, handled);
186 // Install the notification hook on the top-level window, so that we can
187 // be notified on move events. Note that the return value is not checked.
188 // This hook is installed here, as opposed to during IOleObject_SetClientSite
189 // because m_hWnd has not yet been assigned during the SetSite call.
190 InstallTopLevelHook(m_spClientSite);
191 return 0;
194 LRESULT ChromeFrameActivex::OnHostMoved(UINT message, WPARAM wparam,
195 LPARAM lparam, BOOL& handled) {
196 Base::OnHostMoved();
197 return 0;
200 HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
201 base::win::ScopedComPtr<IOleContainer> container;
202 HRESULT hr = m_spClientSite->GetContainer(container.Receive());
203 if (container)
204 hr = container.QueryInterface(doc);
205 return hr;
208 HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
209 base::win::ScopedComPtr<IHTMLDocument2> document;
210 HRESULT hr = GetContainingDocument(document.Receive());
211 if (document)
212 hr = document->get_parentWindow(window);
213 return hr;
216 void ChromeFrameActivex::OnLoad(const GURL& gurl) {
217 base::win::ScopedComPtr<IDispatch> event;
218 std::string url = gurl.spec();
219 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
220 Fire_onload(event);
222 FireEvent(onload_, url);
223 Base::OnLoad(gurl);
226 void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
227 base::win::ScopedComPtr<IDispatch> event;
228 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
229 Fire_onloaderror(event);
231 FireEvent(onloaderror_, url);
232 Base::OnLoadFailed(error_code, url);
235 void ChromeFrameActivex::OnMessageFromChromeFrame(const std::string& message,
236 const std::string& origin,
237 const std::string& target) {
238 DVLOG(1) << __FUNCTION__;
240 if (target.compare("*") != 0) {
241 bool drop = true;
243 if (is_privileged()) {
244 // Forward messages if the control is in privileged mode.
245 base::win::ScopedComPtr<IDispatch> message_event;
246 if (SUCCEEDED(CreateDomEvent("message", message, origin,
247 message_event.Receive()))) {
248 base::win::ScopedBstr target_bstr(UTF8ToWide(target).c_str());
249 Fire_onprivatemessage(message_event, target_bstr);
251 FireEvent(onprivatemessage_, message_event, target_bstr);
253 } else {
254 if (HaveSameOrigin(target, document_url_)) {
255 drop = false;
256 } else {
257 DLOG(WARNING) << "Dropping posted message since target doesn't match "
258 "the current document's origin. target=" << target;
262 if (drop)
263 return;
266 base::win::ScopedComPtr<IDispatch> message_event;
267 if (SUCCEEDED(CreateDomEvent("message", message, origin,
268 message_event.Receive()))) {
269 Fire_onmessage(message_event);
271 FireEvent(onmessage_, message_event);
273 base::win::ScopedVariant event_var;
274 event_var.Set(static_cast<IDispatch*>(message_event));
275 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
279 bool ChromeFrameActivex::ShouldShowVersionMismatchDialog(
280 bool is_privileged,
281 IOleClientSite* client_site) {
282 if (!is_privileged) {
283 return true;
286 if (client_site) {
287 base::win::ScopedComPtr<IChromeFramePrivileged> service;
288 HRESULT hr = DoQueryService(SID_ChromeFramePrivileged,
289 client_site,
290 service.Receive());
291 if (SUCCEEDED(hr) && service) {
292 return (S_FALSE != service->ShouldShowVersionMismatchDialog());
296 NOTREACHED();
297 return true;
300 void ChromeFrameActivex::OnAutomationServerLaunchFailed(
301 AutomationLaunchResult reason, const std::string& server_version) {
302 Base::OnAutomationServerLaunchFailed(reason, server_version);
304 if (reason == AUTOMATION_VERSION_MISMATCH &&
305 ShouldShowVersionMismatchDialog(is_privileged(), m_spClientSite)) {
306 UMA_HISTOGRAM_COUNTS("ChromeFrame.VersionMismatchDisplayed", 1);
307 DisplayVersionMismatchWarning(m_hWnd, server_version);
311 void ChromeFrameActivex::OnChannelError() {
312 Fire_onchannelerror();
315 HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
316 HRESULT hr = S_OK;
317 int dc_type = ::GetObjectType(draw_info.hicTargetDev);
318 if (dc_type == OBJ_ENHMETADC) {
319 RECT print_bounds = {0};
320 print_bounds.left = draw_info.prcBounds->left;
321 print_bounds.right = draw_info.prcBounds->right;
322 print_bounds.top = draw_info.prcBounds->top;
323 print_bounds.bottom = draw_info.prcBounds->bottom;
325 automation_client_->Print(draw_info.hdcDraw, print_bounds);
326 } else {
327 hr = Base::OnDraw(draw_info);
330 return hr;
333 STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
334 DCHECK(bag);
336 const wchar_t* event_props[] = {
337 (L"onload"),
338 (L"onloaderror"),
339 (L"onmessage"),
340 (L"onreadystatechanged"),
343 base::win::ScopedComPtr<IHTMLObjectElement> obj_element;
344 GetObjectElement(obj_element.Receive());
346 base::win::ScopedBstr object_id;
347 GetObjectScriptId(obj_element, object_id.Receive());
349 base::win::ScopedComPtr<IHTMLElement2> element;
350 element.QueryFrom(obj_element);
351 HRESULT hr = S_OK;
353 for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
354 base::win::ScopedBstr prop(event_props[i]);
355 base::win::ScopedVariant value;
356 if (SUCCEEDED(bag->Read(prop, value.Receive(), error_log))) {
357 if (value.type() != VT_BSTR ||
358 FAILED(hr = CreateScriptBlockForEvent(element, object_id,
359 V_BSTR(&value), prop))) {
360 DLOG(ERROR) << "Failed to create script block for " << prop
361 << base::StringPrintf(L"hr=0x%08X, vt=%i", hr,
362 value.type());
363 } else {
364 DVLOG(1) << "script block created for event " << prop
365 << base::StringPrintf(" (0x%08X)", hr) << " connections: " <<
366 ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
368 } else {
369 DVLOG(1) << "event property " << prop << " not in property bag";
373 base::win::ScopedVariant src;
374 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"src"), src.Receive(),
375 error_log))) {
376 if (src.type() == VT_BSTR) {
377 hr = put_src(V_BSTR(&src));
378 DCHECK(hr != E_UNEXPECTED);
382 base::win::ScopedVariant use_chrome_network;
383 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"useChromeNetwork"),
384 use_chrome_network.Receive(), error_log))) {
385 VariantChangeType(use_chrome_network.AsInput(),
386 use_chrome_network.AsInput(),
387 0, VT_BOOL);
388 if (use_chrome_network.type() == VT_BOOL) {
389 hr = put_useChromeNetwork(V_BOOL(&use_chrome_network));
390 DCHECK(hr != E_UNEXPECTED);
394 DLOG_IF(ERROR, FAILED(hr))
395 << base::StringPrintf("Failed to load property bag: 0x%08X", hr);
397 return hr;
400 const wchar_t g_activex_insecure_content_error[] = {
401 L"data:text/html,<html><body><b>ChromeFrame Security Error<br><br>"
402 L"Cannot navigate to HTTP url when document URL is HTTPS</body></html>"};
404 STDMETHODIMP ChromeFrameActivex::put_src(BSTR src) {
405 GURL document_url(GetDocumentUrl());
406 if (document_url.SchemeIsSecure()) {
407 GURL source_url(src);
408 if (!source_url.SchemeIsSecure()) {
409 Base::put_src(base::win::ScopedBstr(g_activex_insecure_content_error));
410 return E_ACCESSDENIED;
413 return Base::put_src(src);
416 HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
417 IOleClientSite* client_site) {
418 HRESULT hr = Base::IOleObject_SetClientSite(client_site);
419 if (FAILED(hr) || !client_site) {
420 EventHandlers* handlers[] = {
421 &onmessage_,
422 &onloaderror_,
423 &onload_,
424 &onreadystatechanged_,
425 &onextensionready_,
428 for (int i = 0; i < arraysize(handlers); ++i)
429 handlers[i]->clear();
431 // Drop privileged mode on uninitialization.
432 set_is_privileged(false);
433 } else {
434 base::win::ScopedComPtr<IHTMLDocument2> document;
435 GetContainingDocument(document.Receive());
436 if (document) {
437 base::win::ScopedBstr url;
438 if (SUCCEEDED(document->get_URL(url.Receive())))
439 WideToUTF8(url, url.Length(), &document_url_);
442 // Probe to see whether the host implements the privileged service.
443 base::win::ScopedComPtr<IChromeFramePrivileged> service;
444 HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged,
445 m_spClientSite,
446 service.Receive());
447 if (SUCCEEDED(service_hr) && service) {
448 // Does the host want privileged mode?
449 boolean wants_privileged = false;
450 service_hr = service->GetWantsPrivileged(&wants_privileged);
452 if (SUCCEEDED(service_hr) && wants_privileged)
453 set_is_privileged(true);
455 url_fetcher_->set_privileged_mode(is_privileged());
458 std::wstring profile_name(GetHostProcessName(false));
459 if (is_privileged()) {
460 base::win::ScopedBstr profile_name_arg;
461 service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
462 if (S_OK == service_hr && profile_name_arg)
463 profile_name.assign(profile_name_arg, profile_name_arg.Length());
466 std::string utf8_url;
467 if (url_.Length()) {
468 WideToUTF8(url_, url_.Length(), &utf8_url);
471 InitializeAutomationSettings();
473 url_fetcher_->set_frame_busting(!is_privileged());
474 automation_client_->SetUrlFetcher(url_fetcher_.get());
475 if (!InitializeAutomation(profile_name, IsIEInPrivate(), true,
476 GURL(utf8_url), GURL(), false)) {
477 DLOG(ERROR) << "Failed to navigate to url:" << utf8_url;
478 return E_FAIL;
481 // Log a metric that Chrome Frame is being used in Widget mode
482 UMA_LAUNCH_TYPE_COUNT(RENDERER_TYPE_CHROME_WIDGET);
485 return hr;
488 HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
489 BSTR* id) {
490 DCHECK(object_elem != NULL);
491 DCHECK(id != NULL);
493 HRESULT hr = E_FAIL;
494 if (object_elem) {
495 base::win::ScopedComPtr<IHTMLElement> elem;
496 hr = elem.QueryFrom(object_elem);
497 if (elem) {
498 hr = elem->get_id(id);
502 return hr;
505 HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
506 DCHECK(m_spClientSite);
507 if (!m_spClientSite)
508 return E_UNEXPECTED;
510 base::win::ScopedComPtr<IOleControlSite> site;
511 HRESULT hr = site.QueryFrom(m_spClientSite);
512 if (site) {
513 base::win::ScopedComPtr<IDispatch> disp;
514 hr = site->GetExtendedControl(disp.Receive());
515 if (disp) {
516 hr = disp.QueryInterface(element);
517 } else {
518 DCHECK(FAILED(hr));
522 return hr;
525 HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
526 IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
527 BSTR event_name) {
528 DCHECK(insert_after);
529 DCHECK_GT(::SysStringLen(event_name), 0UL); // should always have this
531 // This might be 0 if not specified in the HTML document.
532 if (!::SysStringLen(instance_id)) {
533 // TODO(tommi): Should we give ourselves an ID if this happens?
534 NOTREACHED() << "Need to handle this";
535 return E_INVALIDARG;
538 base::win::ScopedComPtr<IHTMLDocument2> document;
539 HRESULT hr = GetContainingDocument(document.Receive());
540 if (SUCCEEDED(hr)) {
541 base::win::ScopedComPtr<IHTMLElement> element, new_element;
542 document->createElement(base::win::ScopedBstr(L"script"),
543 element.Receive());
544 if (element) {
545 base::win::ScopedComPtr<IHTMLScriptElement> script_element;
546 if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
547 script_element->put_htmlFor(instance_id);
548 script_element->put_event(event_name);
549 script_element->put_text(script);
551 hr = insert_after->insertAdjacentElement(
552 base::win::ScopedBstr(L"afterEnd"),
553 element,
554 new_element.Receive());
559 return hr;
562 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
563 const std::string& arg) {
564 if (handlers.size()) {
565 base::win::ScopedComPtr<IDispatch> event;
566 if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
567 FireEvent(handlers, event);
572 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
573 IDispatch* event) {
574 DCHECK(event != NULL);
575 VARIANT arg = { VT_DISPATCH };
576 arg.pdispVal = event;
577 DISPPARAMS params = { &arg, NULL, 1, 0 };
578 for (EventHandlers::const_iterator it = handlers.begin();
579 it != handlers.end();
580 ++it) {
581 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
582 DISPATCH_METHOD, &params, NULL, NULL, NULL);
583 // 0x80020101 == SCRIPT_E_REPORTED.
584 // When the script we're invoking has an error, we get this error back.
585 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
586 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
590 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
591 IDispatch* event, BSTR target) {
592 DCHECK(event != NULL);
593 // Arguments in reverse order to event handler function declaration,
594 // because that's what DISPPARAMS requires.
595 VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
596 args[0].bstrVal = target;
597 args[1].pdispVal = event;
598 DISPPARAMS params = { args, NULL, arraysize(args), 0 };
599 for (EventHandlers::const_iterator it = handlers.begin();
600 it != handlers.end();
601 ++it) {
602 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
603 DISPATCH_METHOD, &params, NULL, NULL, NULL);
604 // 0x80020101 == SCRIPT_E_REPORTED.
605 // When the script we're invoking has an error, we get this error back.
606 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
607 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
611 HRESULT ChromeFrameActivex::InstallTopLevelHook(IOleClientSite* client_site) {
612 // Get the parent window of the site, and install our hook on the topmost
613 // window of the parent.
614 base::win::ScopedComPtr<IOleWindow> ole_window;
615 HRESULT hr = ole_window.QueryFrom(client_site);
616 if (FAILED(hr))
617 return hr;
619 HWND parent_wnd;
620 hr = ole_window->GetWindow(&parent_wnd);
621 if (FAILED(hr))
622 return hr;
624 HWND top_window = ::GetAncestor(parent_wnd, GA_ROOT);
625 chrome_wndproc_hook_ = InstallLocalWindowHook(top_window);
626 if (chrome_wndproc_hook_)
627 TopLevelWindowMapping::GetInstance()->AddMapping(top_window, m_hWnd);
629 return chrome_wndproc_hook_ ? S_OK : E_FAIL;
632 HRESULT ChromeFrameActivex::registerBhoIfNeeded() {
633 if (!m_spUnkSite) {
634 NOTREACHED() << "Invalid client site";
635 return E_FAIL;
638 if (NavigationManager::GetThreadInstance() != NULL) {
639 DVLOG(1) << "BHO already loaded";
640 return S_OK;
643 base::win::ScopedComPtr<IWebBrowser2> web_browser2;
644 HRESULT hr = DoQueryService(SID_SWebBrowserApp, m_spUnkSite,
645 web_browser2.Receive());
646 if (FAILED(hr) || web_browser2.get() == NULL) {
647 DLOG(WARNING) << "Failed to get IWebBrowser2 from client site. Error:"
648 << base::StringPrintf(" 0x%08X", hr);
649 return hr;
652 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
653 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
654 arraysize(bho_class_id_as_string));
656 base::win::ScopedComPtr<IObjectWithSite> bho;
657 hr = bho.CreateInstance(CLSID_ChromeFrameBHO, NULL, CLSCTX_INPROC_SERVER);
658 if (FAILED(hr)) {
659 NOTREACHED() << "Failed to register ChromeFrame BHO. Error:"
660 << base::StringPrintf(" 0x%08X", hr);
661 return hr;
664 hr = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT_REFRESH, NULL, 0, 0);
665 if (FAILED(hr)) {
666 DLOG(ERROR) << "Failed to refresh user agent string from registry. "
667 << "UrlMkSetSessionOption returned "
668 << base::StringPrintf("0x%08x", hr);
669 return hr;
672 hr = bho->SetSite(web_browser2);
673 if (FAILED(hr)) {
674 NOTREACHED() << "ChromeFrame BHO SetSite failed. Error:"
675 << base::StringPrintf(" 0x%08X", hr);
676 return hr;
679 web_browser2->PutProperty(base::win::ScopedBstr(bho_class_id_as_string),
680 base::win::ScopedVariant(bho));
681 return S_OK;