blob: 59212c39e765ca3d92e32419a9de7b493aaf71dd [file] [log] [blame]
[email protected]7b237e22012-07-17 22:28:061// Copyright (c) 2012 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"
[email protected]58580352010-10-26 04:07:5014#include "base/debug/trace_event.h"
[email protected]f7817822009-09-24 05:11:5815#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1516#include "base/memory/singleton.h"
[email protected]f7817822009-09-24 05:11:5817#include "base/path_service.h"
18#include "base/process_util.h"
[email protected]d778e0422013-03-06 18:10:2219#include "base/strings/string_split.h"
[email protected]ce2086e2013-06-11 04:42:1020#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
[email protected]d2d79d52013-06-07 22:23:4822#include "base/strings/utf_string_conversions.h"
[email protected]ce0e72462010-10-16 03:46:0523#include "base/win/scoped_bstr.h"
24#include "base/win/scoped_variant.h"
[email protected]a22f7e02011-02-09 07:15:3525#include "chrome/common/automation_messages.h"
[email protected]f7817822009-09-24 05:11:5826#include "chrome/common/chrome_constants.h"
27#include "chrome/common/chrome_switches.h"
28#include "chrome/test/automation/tab_proxy.h"
[email protected]f7817822009-09-24 05:11:5829#include "chrome_frame/utils.h"
[email protected]8ee65ba2011-04-12 20:53:2330#include "googleurl/src/gurl.h"
[email protected]f7817822009-09-24 05:11:5831
[email protected]2b19e2fe2010-02-16 02:24:1832namespace {
33
34// Class used to maintain a mapping from top-level windows to ChromeFrameActivex
35// instances.
36class TopLevelWindowMapping {
37 public:
38 typedef std::vector<HWND> WindowList;
39
[email protected]8e8bb6d2010-12-13 08:18:5540 static TopLevelWindowMapping* GetInstance() {
[email protected]2b19e2fe2010-02-16 02:24:1841 return Singleton<TopLevelWindowMapping>::get();
42 }
43
44 // Add |cf_window| to the set of windows registered under |top_window|.
45 void AddMapping(HWND top_window, HWND cf_window) {
46 top_window_map_lock_.Lock();
47 top_window_map_[top_window].push_back(cf_window);
48 top_window_map_lock_.Unlock();
49 }
50
51 // Return the set of Chrome-Frame instances under |window|.
52 WindowList GetInstances(HWND window) {
53 top_window_map_lock_.Lock();
54 WindowList list = top_window_map_[window];
55 top_window_map_lock_.Unlock();
56 return list;
57 }
58
59 private:
60 // Constructor is private as this class it to be used as a singleton.
61 // See static method instance().
62 TopLevelWindowMapping() {}
63
64 friend struct DefaultSingletonTraits<TopLevelWindowMapping>;
65
66 typedef std::map<HWND, WindowList> TopWindowMap;
67 TopWindowMap top_window_map_;
68
69 CComAutoCriticalSection top_window_map_lock_;
70
71 DISALLOW_COPY_AND_ASSIGN(TopLevelWindowMapping);
72};
73
74// Message pump hook function that monitors for WM_MOVE and WM_MOVING
75// messages on a top-level window, and passes notification to the appropriate
76// Chrome-Frame instances.
77LRESULT CALLBACK TopWindowProc(int code, WPARAM wparam, LPARAM lparam) {
[email protected]47163d42013-05-16 02:37:5078 CWPSTRUCT* info = reinterpret_cast<CWPSTRUCT*>(lparam);
[email protected]2b19e2fe2010-02-16 02:24:1879 const UINT &message = info->message;
80 const HWND &message_hwnd = info->hwnd;
81
82 switch (message) {
83 case WM_MOVE:
84 case WM_MOVING: {
85 TopLevelWindowMapping::WindowList cf_instances =
[email protected]8e8bb6d2010-12-13 08:18:5586 TopLevelWindowMapping::GetInstance()->GetInstances(message_hwnd);
[email protected]2b19e2fe2010-02-16 02:24:1887 TopLevelWindowMapping::WindowList::iterator
88 iter(cf_instances.begin()), end(cf_instances.end());
[email protected]47163d42013-05-16 02:37:5089 for (; iter != end; ++iter) {
[email protected]2b19e2fe2010-02-16 02:24:1890 PostMessage(*iter, WM_HOST_MOVED_NOTIFICATION, NULL, NULL);
91 }
92 break;
93 }
94 default:
95 break;
96 }
97
98 return CallNextHookEx(0, code, wparam, lparam);
99}
100
101HHOOK InstallLocalWindowHook(HWND window) {
102 if (!window)
103 return NULL;
104
105 DWORD proc_thread = ::GetWindowThreadProcessId(window, NULL);
106 if (!proc_thread)
107 return NULL;
108
109 // Note that this hook is installed as a LOCAL hook.
110 return ::SetWindowsHookEx(WH_CALLWNDPROC,
111 TopWindowProc,
112 NULL,
113 proc_thread);
114}
115
116} // unnamed namespace
117
[email protected]a22f7e02011-02-09 07:15:35118namespace chrome_frame {
119std::string ActiveXCreateUrl(const GURL& parsed_url,
120 const AttachExternalTabParams& params) {
121 return base::StringPrintf(
122 "%hs?attach_external_tab&%I64u&%d&%d&%d&%d&%d&%hs",
123 parsed_url.GetOrigin().spec().c_str(),
124 params.cookie,
125 params.disposition,
126 params.dimensions.x(),
127 params.dimensions.y(),
128 params.dimensions.width(),
129 params.dimensions.height(),
130 params.profile_name.c_str());
131}
132
133int GetDisposition(const AttachExternalTabParams& params) {
134 return params.disposition;
135}
136
137void GetMiniContextMenuData(UINT cmd,
138 const MiniContextMenuParams& params,
139 GURL* referrer,
140 GURL* url) {
141 *referrer = params.frame_url.is_empty() ? params.page_url : params.frame_url;
142 *url = (cmd == IDS_CONTENT_CONTEXT_SAVELINKAS ?
143 params.link_url : params.src_url);
144}
145
146} // namespace chrome_frame
147
[email protected]2b19e2fe2010-02-16 02:24:18148ChromeFrameActivex::ChromeFrameActivex()
[email protected]7b237e22012-07-17 22:28:06149 : chrome_wndproc_hook_(NULL),
150 attaching_to_existing_cf_tab_(false) {
[email protected]366ae242011-05-10 02:23:58151 TRACE_EVENT_BEGIN_ETW("chromeframe.createactivex", this, "");
[email protected]f7817822009-09-24 05:11:58152}
153
154HRESULT ChromeFrameActivex::FinalConstruct() {
155 HRESULT hr = Base::FinalConstruct();
156 if (FAILED(hr))
157 return hr;
158
159 // No need to call FireOnChanged at this point since nobody will be listening.
160 ready_state_ = READYSTATE_LOADING;
161 return S_OK;
162}
163
164ChromeFrameActivex::~ChromeFrameActivex() {
165 // We expect these to be released during a call to SetClientSite(NULL).
[email protected]f55bd4862010-05-27 15:38:07166 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());
[email protected]3eb07da2010-02-01 19:48:36171
[email protected]2b19e2fe2010-02-16 02:24:18172 if (chrome_wndproc_hook_) {
173 BOOL unhook_success = ::UnhookWindowsHookEx(chrome_wndproc_hook_);
174 DCHECK(unhook_success);
175 }
176
[email protected]3eb07da2010-02-01 19:48:36177 // ChromeFramePlugin::Uninitialize()
178 Base::Uninitialize();
[email protected]04e3f352010-05-10 13:48:24179
[email protected]366ae242011-05-10 02:23:58180 TRACE_EVENT_END_ETW("chromeframe.createactivex", this, "");
[email protected]f7817822009-09-24 05:11:58181}
182
183LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
184 BOOL& handled) {
185 Base::OnCreate(message, wparam, lparam, handled);
[email protected]2b19e2fe2010-02-16 02:24:18186 // 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;
192}
193
194LRESULT ChromeFrameActivex::OnHostMoved(UINT message, WPARAM wparam,
195 LPARAM lparam, BOOL& handled) {
196 Base::OnHostMoved();
[email protected]f7817822009-09-24 05:11:58197 return 0;
198}
199
[email protected]f7817822009-09-24 05:11:58200HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
[email protected]8ee65ba2011-04-12 20:53:23201 base::win::ScopedComPtr<IOleContainer> container;
[email protected]f7817822009-09-24 05:11:58202 HRESULT hr = m_spClientSite->GetContainer(container.Receive());
203 if (container)
204 hr = container.QueryInterface(doc);
205 return hr;
206}
207
208HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
[email protected]8ee65ba2011-04-12 20:53:23209 base::win::ScopedComPtr<IHTMLDocument2> document;
[email protected]f7817822009-09-24 05:11:58210 HRESULT hr = GetContainingDocument(document.Receive());
211 if (document)
212 hr = document->get_parentWindow(window);
213 return hr;
214}
215
[email protected]f5494d42010-12-23 22:15:34216void ChromeFrameActivex::OnLoad(const GURL& gurl) {
[email protected]8ee65ba2011-04-12 20:53:23217 base::win::ScopedComPtr<IDispatch> event;
[email protected]f7817822009-09-24 05:11:58218 std::string url = gurl.spec();
219 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
220 Fire_onload(event);
221
222 FireEvent(onload_, url);
[email protected]f5494d42010-12-23 22:15:34223 Base::OnLoad(gurl);
[email protected]f7817822009-09-24 05:11:58224}
225
226void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
[email protected]8ee65ba2011-04-12 20:53:23227 base::win::ScopedComPtr<IDispatch> event;
[email protected]f7817822009-09-24 05:11:58228 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
229 Fire_onloaderror(event);
230
231 FireEvent(onloaderror_, url);
[email protected]a1800e82009-11-19 00:53:23232 Base::OnLoadFailed(error_code, url);
[email protected]f7817822009-09-24 05:11:58233}
234
[email protected]f5494d42010-12-23 22:15:34235void ChromeFrameActivex::OnMessageFromChromeFrame(const std::string& message,
[email protected]f7817822009-09-24 05:11:58236 const std::string& origin,
237 const std::string& target) {
[email protected]2b9a9f162010-10-19 20:30:45238 DVLOG(1) << __FUNCTION__;
[email protected]f7817822009-09-24 05:11:58239
240 if (target.compare("*") != 0) {
241 bool drop = true;
242
[email protected]0753db592010-12-15 14:45:05243 if (is_privileged()) {
[email protected]f7817822009-09-24 05:11:58244 // Forward messages if the control is in privileged mode.
[email protected]8ee65ba2011-04-12 20:53:23245 base::win::ScopedComPtr<IDispatch> message_event;
[email protected]f7817822009-09-24 05:11:58246 if (SUCCEEDED(CreateDomEvent("message", message, origin,
247 message_event.Receive()))) {
[email protected]ce0e72462010-10-16 03:46:05248 base::win::ScopedBstr target_bstr(UTF8ToWide(target).c_str());
[email protected]f7817822009-09-24 05:11:58249 Fire_onprivatemessage(message_event, target_bstr);
250
251 FireEvent(onprivatemessage_, message_event, target_bstr);
252 }
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;
259 }
260 }
261
262 if (drop)
263 return;
264 }
265
[email protected]8ee65ba2011-04-12 20:53:23266 base::win::ScopedComPtr<IDispatch> message_event;
[email protected]f7817822009-09-24 05:11:58267 if (SUCCEEDED(CreateDomEvent("message", message, origin,
268 message_event.Receive()))) {
269 Fire_onmessage(message_event);
270
271 FireEvent(onmessage_, message_event);
272
[email protected]ce0e72462010-10-16 03:46:05273 base::win::ScopedVariant event_var;
[email protected]f7817822009-09-24 05:11:58274 event_var.Set(static_cast<IDispatch*>(message_event));
275 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
276 }
277}
278
[email protected]f30e7472010-11-10 01:14:41279bool ChromeFrameActivex::ShouldShowVersionMismatchDialog(
280 bool is_privileged,
281 IOleClientSite* client_site) {
282 if (!is_privileged) {
283 return true;
284 }
285
286 if (client_site) {
[email protected]8ee65ba2011-04-12 20:53:23287 base::win::ScopedComPtr<IChromeFramePrivileged> service;
[email protected]f30e7472010-11-10 01:14:41288 HRESULT hr = DoQueryService(SID_ChromeFramePrivileged,
289 client_site,
290 service.Receive());
291 if (SUCCEEDED(hr) && service) {
292 return (S_FALSE != service->ShouldShowVersionMismatchDialog());
293 }
294 }
295
296 NOTREACHED();
297 return true;
298}
299
[email protected]f7817822009-09-24 05:11:58300void ChromeFrameActivex::OnAutomationServerLaunchFailed(
301 AutomationLaunchResult reason, const std::string& server_version) {
302 Base::OnAutomationServerLaunchFailed(reason, server_version);
303
[email protected]f30e7472010-11-10 01:14:41304 if (reason == AUTOMATION_VERSION_MISMATCH &&
[email protected]0753db592010-12-15 14:45:05305 ShouldShowVersionMismatchDialog(is_privileged(), m_spClientSite)) {
[email protected]92c79d32011-04-06 18:41:15306 UMA_HISTOGRAM_COUNTS("ChromeFrame.VersionMismatchDisplayed", 1);
[email protected]f7817822009-09-24 05:11:58307 DisplayVersionMismatchWarning(m_hWnd, server_version);
308 }
309}
310
[email protected]efd4dfc22010-03-26 20:14:40311void ChromeFrameActivex::OnChannelError() {
312 Fire_onchannelerror();
313}
314
315HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
[email protected]f7817822009-09-24 05:11:58316 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;
324
325 automation_client_->Print(draw_info.hdcDraw, print_bounds);
326 } else {
327 hr = Base::OnDraw(draw_info);
328 }
329
330 return hr;
331}
332
333STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
334 DCHECK(bag);
335
336 const wchar_t* event_props[] = {
337 (L"onload"),
338 (L"onloaderror"),
339 (L"onmessage"),
340 (L"onreadystatechanged"),
341 };
342
[email protected]ce0e72462010-10-16 03:46:05343 base::win::ScopedComPtr<IHTMLObjectElement> obj_element;
[email protected]f7817822009-09-24 05:11:58344 GetObjectElement(obj_element.Receive());
345
[email protected]ce0e72462010-10-16 03:46:05346 base::win::ScopedBstr object_id;
[email protected]f7817822009-09-24 05:11:58347 GetObjectScriptId(obj_element, object_id.Receive());
348
[email protected]8ee65ba2011-04-12 20:53:23349 base::win::ScopedComPtr<IHTMLElement2> element;
[email protected]f7817822009-09-24 05:11:58350 element.QueryFrom(obj_element);
351 HRESULT hr = S_OK;
352
353 for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
[email protected]ce0e72462010-10-16 03:46:05354 base::win::ScopedBstr prop(event_props[i]);
355 base::win::ScopedVariant value;
[email protected]f7817822009-09-24 05:11:58356 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
[email protected]d3451d832010-10-01 11:17:37361 << base::StringPrintf(L"hr=0x%08X, vt=%i", hr,
362 value.type());
[email protected]f7817822009-09-24 05:11:58363 } else {
[email protected]2b9a9f162010-10-19 20:30:45364 DVLOG(1) << "script block created for event " << prop
365 << base::StringPrintf(" (0x%08X)", hr) << " connections: " <<
[email protected]f7817822009-09-24 05:11:58366 ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
367 }
368 } else {
[email protected]2b9a9f162010-10-19 20:30:45369 DVLOG(1) << "event property " << prop << " not in property bag";
[email protected]f7817822009-09-24 05:11:58370 }
371 }
372
[email protected]ce0e72462010-10-16 03:46:05373 base::win::ScopedVariant src;
374 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"src"), src.Receive(),
375 error_log))) {
[email protected]f7817822009-09-24 05:11:58376 if (src.type() == VT_BSTR) {
377 hr = put_src(V_BSTR(&src));
378 DCHECK(hr != E_UNEXPECTED);
379 }
380 }
381
[email protected]ce0e72462010-10-16 03:46:05382 base::win::ScopedVariant use_chrome_network;
383 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"useChromeNetwork"),
[email protected]f7817822009-09-24 05:11:58384 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);
391 }
392 }
393
394 DLOG_IF(ERROR, FAILED(hr))
[email protected]d3451d832010-10-01 11:17:37395 << base::StringPrintf("Failed to load property bag: 0x%08X", hr);
[email protected]f7817822009-09-24 05:11:58396
397 return hr;
398}
399
[email protected]b4e75c12010-05-18 18:28:48400const wchar_t g_activex_insecure_content_error[] = {
[email protected]f7817822009-09-24 05:11:58401 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>"};
[email protected]2b8fd322009-10-02 00:00:59403
[email protected]f7817822009-09-24 05:11:58404STDMETHODIMP 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()) {
[email protected]965722ff2010-10-20 15:50:30409 Base::put_src(base::win::ScopedBstr(g_activex_insecure_content_error));
[email protected]f7817822009-09-24 05:11:58410 return E_ACCESSDENIED;
411 }
412 }
[email protected]7b237e22012-07-17 22:28:06413 HRESULT hr = S_OK;
414 // If we are connecting to an existing ExternalTabContainer instance in
415 // Chrome then we should wait for Chrome to initiate the navigation.
416 if (!attaching_to_existing_cf_tab_) {
417 hr = Base::put_src(src);
418 } else {
419 url_.Reset(::SysAllocString(src));
420 attaching_to_existing_cf_tab_ = false;
421 }
422 return S_OK;
[email protected]f7817822009-09-24 05:11:58423}
424
425HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
426 IOleClientSite* client_site) {
427 HRESULT hr = Base::IOleObject_SetClientSite(client_site);
428 if (FAILED(hr) || !client_site) {
429 EventHandlers* handlers[] = {
430 &onmessage_,
431 &onloaderror_,
432 &onload_,
433 &onreadystatechanged_,
[email protected]00f6b772009-10-23 17:03:41434 &onextensionready_,
[email protected]f7817822009-09-24 05:11:58435 };
436
437 for (int i = 0; i < arraysize(handlers); ++i)
438 handlers[i]->clear();
439
440 // Drop privileged mode on uninitialization.
[email protected]0753db592010-12-15 14:45:05441 set_is_privileged(false);
[email protected]f7817822009-09-24 05:11:58442 } else {
[email protected]8ee65ba2011-04-12 20:53:23443 base::win::ScopedComPtr<IHTMLDocument2> document;
[email protected]f7817822009-09-24 05:11:58444 GetContainingDocument(document.Receive());
445 if (document) {
[email protected]965722ff2010-10-20 15:50:30446 base::win::ScopedBstr url;
[email protected]f7817822009-09-24 05:11:58447 if (SUCCEEDED(document->get_URL(url.Receive())))
448 WideToUTF8(url, url.Length(), &document_url_);
449 }
450
451 // Probe to see whether the host implements the privileged service.
[email protected]8ee65ba2011-04-12 20:53:23452 base::win::ScopedComPtr<IChromeFramePrivileged> service;
[email protected]4c4aae72010-07-30 05:54:21453 HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged,
454 m_spClientSite,
455 service.Receive());
[email protected]f7817822009-09-24 05:11:58456 if (SUCCEEDED(service_hr) && service) {
457 // Does the host want privileged mode?
458 boolean wants_privileged = false;
459 service_hr = service->GetWantsPrivileged(&wants_privileged);
460
461 if (SUCCEEDED(service_hr) && wants_privileged)
[email protected]0753db592010-12-15 14:45:05462 set_is_privileged(true);
[email protected]7403d38f2010-03-22 22:50:49463
[email protected]0753db592010-12-15 14:45:05464 url_fetcher_->set_privileged_mode(is_privileged());
[email protected]f7817822009-09-24 05:11:58465 }
466
[email protected]f7817822009-09-24 05:11:58467 std::wstring profile_name(GetHostProcessName(false));
[email protected]0753db592010-12-15 14:45:05468 if (is_privileged()) {
[email protected]ce0e72462010-10-16 03:46:05469 base::win::ScopedBstr profile_name_arg;
[email protected]f7817822009-09-24 05:11:58470 service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
471 if (S_OK == service_hr && profile_name_arg)
472 profile_name.assign(profile_name_arg, profile_name_arg.Length());
473 }
474
[email protected]e150e822010-06-03 23:10:55475 std::string utf8_url;
476 if (url_.Length()) {
477 WideToUTF8(url_, url_.Length(), &utf8_url);
478 }
479
[email protected]9eeb35e2010-09-30 21:38:50480 InitializeAutomationSettings();
[email protected]e1081d92010-09-10 20:29:11481
[email protected]7b237e22012-07-17 22:28:06482 if (service) {
483 base::win::ScopedBstr navigation_url;
484 service->GetNavigationUrl(navigation_url.Receive());
485 if (navigation_url.Length()) {
486 ChromeFrameUrl cf_url;
487 cf_url.Parse(navigation_url.operator BSTR());
488 if (cf_url.attach_to_external_tab()) {
489 automation_client_->AttachExternalTab(cf_url.cookie());
490 attaching_to_existing_cf_tab_ = true;
491 }
492 }
493 }
[email protected]0753db592010-12-15 14:45:05494 url_fetcher_->set_frame_busting(!is_privileged());
[email protected]bbfa9a12010-08-10 14:09:37495 automation_client_->SetUrlFetcher(url_fetcher_.get());
[email protected]c70e5582011-12-20 21:22:45496 if (!InitializeAutomation(profile_name, IsIEInPrivate(), true,
497 GURL(utf8_url), GURL(), false)) {
[email protected]4c4aae72010-07-30 05:54:21498 DLOG(ERROR) << "Failed to navigate to url:" << utf8_url;
[email protected]f7817822009-09-24 05:11:58499 return E_FAIL;
500 }
[email protected]d8e13512010-09-22 17:02:58501
502 // Log a metric that Chrome Frame is being used in Widget mode
[email protected]92c79d32011-04-06 18:41:15503 UMA_LAUNCH_TYPE_COUNT(RENDERER_TYPE_CHROME_WIDGET);
[email protected]f7817822009-09-24 05:11:58504 }
505
506 return hr;
507}
508
509HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
510 BSTR* id) {
511 DCHECK(object_elem != NULL);
512 DCHECK(id != NULL);
513
514 HRESULT hr = E_FAIL;
515 if (object_elem) {
[email protected]8ee65ba2011-04-12 20:53:23516 base::win::ScopedComPtr<IHTMLElement> elem;
[email protected]f7817822009-09-24 05:11:58517 hr = elem.QueryFrom(object_elem);
518 if (elem) {
519 hr = elem->get_id(id);
520 }
521 }
522
523 return hr;
524}
525
526HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
527 DCHECK(m_spClientSite);
528 if (!m_spClientSite)
529 return E_UNEXPECTED;
530
[email protected]8ee65ba2011-04-12 20:53:23531 base::win::ScopedComPtr<IOleControlSite> site;
[email protected]f7817822009-09-24 05:11:58532 HRESULT hr = site.QueryFrom(m_spClientSite);
533 if (site) {
[email protected]8ee65ba2011-04-12 20:53:23534 base::win::ScopedComPtr<IDispatch> disp;
[email protected]f7817822009-09-24 05:11:58535 hr = site->GetExtendedControl(disp.Receive());
536 if (disp) {
537 hr = disp.QueryInterface(element);
538 } else {
539 DCHECK(FAILED(hr));
540 }
541 }
542
543 return hr;
544}
545
546HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
547 IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
548 BSTR event_name) {
549 DCHECK(insert_after);
[email protected]efd4dfc22010-03-26 20:14:40550 DCHECK_GT(::SysStringLen(event_name), 0UL); // should always have this
[email protected]f7817822009-09-24 05:11:58551
552 // This might be 0 if not specified in the HTML document.
553 if (!::SysStringLen(instance_id)) {
554 // TODO(tommi): Should we give ourselves an ID if this happens?
555 NOTREACHED() << "Need to handle this";
556 return E_INVALIDARG;
557 }
558
[email protected]8ee65ba2011-04-12 20:53:23559 base::win::ScopedComPtr<IHTMLDocument2> document;
[email protected]f7817822009-09-24 05:11:58560 HRESULT hr = GetContainingDocument(document.Receive());
561 if (SUCCEEDED(hr)) {
[email protected]8ee65ba2011-04-12 20:53:23562 base::win::ScopedComPtr<IHTMLElement> element, new_element;
[email protected]d9dc4ad2010-10-16 04:01:00563 document->createElement(base::win::ScopedBstr(L"script"),
564 element.Receive());
[email protected]f7817822009-09-24 05:11:58565 if (element) {
[email protected]8ee65ba2011-04-12 20:53:23566 base::win::ScopedComPtr<IHTMLScriptElement> script_element;
[email protected]f7817822009-09-24 05:11:58567 if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
568 script_element->put_htmlFor(instance_id);
569 script_element->put_event(event_name);
570 script_element->put_text(script);
571
[email protected]d9dc4ad2010-10-16 04:01:00572 hr = insert_after->insertAdjacentElement(
[email protected]94b7e8d72010-10-16 04:07:38573 base::win::ScopedBstr(L"afterEnd"),
[email protected]d9dc4ad2010-10-16 04:01:00574 element,
575 new_element.Receive());
[email protected]f7817822009-09-24 05:11:58576 }
577 }
578 }
579
580 return hr;
581}
582
[email protected]f7817822009-09-24 05:11:58583void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
584 const std::string& arg) {
585 if (handlers.size()) {
[email protected]8ee65ba2011-04-12 20:53:23586 base::win::ScopedComPtr<IDispatch> event;
[email protected]f7817822009-09-24 05:11:58587 if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
588 FireEvent(handlers, event);
589 }
590 }
591}
592
593void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
594 IDispatch* event) {
595 DCHECK(event != NULL);
596 VARIANT arg = { VT_DISPATCH };
597 arg.pdispVal = event;
598 DISPPARAMS params = { &arg, NULL, 1, 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)
[email protected]d3451d832010-10-01 11:17:37607 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
[email protected]f7817822009-09-24 05:11:58608 }
609}
610
611void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
612 IDispatch* event, BSTR target) {
613 DCHECK(event != NULL);
614 // Arguments in reverse order to event handler function declaration,
615 // because that's what DISPPARAMS requires.
616 VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
617 args[0].bstrVal = target;
618 args[1].pdispVal = event;
619 DISPPARAMS params = { args, NULL, arraysize(args), 0 };
620 for (EventHandlers::const_iterator it = handlers.begin();
621 it != handlers.end();
622 ++it) {
623 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
624 DISPATCH_METHOD, &params, NULL, NULL, NULL);
625 // 0x80020101 == SCRIPT_E_REPORTED.
626 // When the script we're invoking has an error, we get this error back.
627 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
[email protected]d3451d832010-10-01 11:17:37628 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
[email protected]f7817822009-09-24 05:11:58629 }
630}
[email protected]2b19e2fe2010-02-16 02:24:18631
632HRESULT ChromeFrameActivex::InstallTopLevelHook(IOleClientSite* client_site) {
633 // Get the parent window of the site, and install our hook on the topmost
634 // window of the parent.
[email protected]8ee65ba2011-04-12 20:53:23635 base::win::ScopedComPtr<IOleWindow> ole_window;
[email protected]2b19e2fe2010-02-16 02:24:18636 HRESULT hr = ole_window.QueryFrom(client_site);
637 if (FAILED(hr))
638 return hr;
639
640 HWND parent_wnd;
641 hr = ole_window->GetWindow(&parent_wnd);
642 if (FAILED(hr))
643 return hr;
644
645 HWND top_window = ::GetAncestor(parent_wnd, GA_ROOT);
646 chrome_wndproc_hook_ = InstallLocalWindowHook(top_window);
647 if (chrome_wndproc_hook_)
[email protected]8e8bb6d2010-12-13 08:18:55648 TopLevelWindowMapping::GetInstance()->AddMapping(top_window, m_hWnd);
[email protected]2b19e2fe2010-02-16 02:24:18649
650 return chrome_wndproc_hook_ ? S_OK : E_FAIL;
651}
[email protected]c442e9f2010-04-29 18:37:44652
[email protected]ca982ec42010-05-02 14:47:14653HRESULT ChromeFrameActivex::registerBhoIfNeeded() {
654 if (!m_spUnkSite) {
[email protected]c442e9f2010-04-29 18:37:44655 NOTREACHED() << "Invalid client site";
656 return E_FAIL;
657 }
658
659 if (NavigationManager::GetThreadInstance() != NULL) {
[email protected]2b9a9f162010-10-19 20:30:45660 DVLOG(1) << "BHO already loaded";
[email protected]c442e9f2010-04-29 18:37:44661 return S_OK;
662 }
663
[email protected]8ee65ba2011-04-12 20:53:23664 base::win::ScopedComPtr<IWebBrowser2> web_browser2;
[email protected]ca982ec42010-05-02 14:47:14665 HRESULT hr = DoQueryService(SID_SWebBrowserApp, m_spUnkSite,
[email protected]c442e9f2010-04-29 18:37:44666 web_browser2.Receive());
667 if (FAILED(hr) || web_browser2.get() == NULL) {
668 DLOG(WARNING) << "Failed to get IWebBrowser2 from client site. Error:"
[email protected]d3451d832010-10-01 11:17:37669 << base::StringPrintf(" 0x%08X", hr);
[email protected]c442e9f2010-04-29 18:37:44670 return hr;
671 }
672
673 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
674 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
675 arraysize(bho_class_id_as_string));
676
[email protected]8ee65ba2011-04-12 20:53:23677 base::win::ScopedComPtr<IObjectWithSite> bho;
[email protected]c442e9f2010-04-29 18:37:44678 hr = bho.CreateInstance(CLSID_ChromeFrameBHO, NULL, CLSCTX_INPROC_SERVER);
679 if (FAILED(hr)) {
680 NOTREACHED() << "Failed to register ChromeFrame BHO. Error:"
[email protected]d3451d832010-10-01 11:17:37681 << base::StringPrintf(" 0x%08X", hr);
[email protected]c442e9f2010-04-29 18:37:44682 return hr;
683 }
684
[email protected]c3a972842011-01-14 00:05:52685 hr = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT_REFRESH, NULL, 0, 0);
686 if (FAILED(hr)) {
687 DLOG(ERROR) << "Failed to refresh user agent string from registry. "
688 << "UrlMkSetSessionOption returned "
689 << base::StringPrintf("0x%08x", hr);
690 return hr;
691 }
692
[email protected]c442e9f2010-04-29 18:37:44693 hr = bho->SetSite(web_browser2);
694 if (FAILED(hr)) {
695 NOTREACHED() << "ChromeFrame BHO SetSite failed. Error:"
[email protected]d3451d832010-10-01 11:17:37696 << base::StringPrintf(" 0x%08X", hr);
[email protected]c442e9f2010-04-29 18:37:44697 return hr;
698 }
699
[email protected]ce0e72462010-10-16 03:46:05700 web_browser2->PutProperty(base::win::ScopedBstr(bho_class_id_as_string),
[email protected]965722ff2010-10-20 15:50:30701 base::win::ScopedVariant(bho));
[email protected]c3a972842011-01-14 00:05:52702 return S_OK;
[email protected]c442e9f2010-04-29 18:37:44703}