blob: 00d0b102f961ab447d632e6c6f4667cfd27327e9 [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"
[email protected]2b19e2fe2010-02-16 02:24:1818#include "base/singleton.h"
[email protected]4e5ae20f2010-09-24 04:52:1119#include "base/string_split.h"
[email protected]f7817822009-09-24 05:11:5820#include "base/string_util.h"
[email protected]d3451d832010-10-01 11:17:3721#include "base/stringprintf.h"
[email protected]04e3f352010-05-10 13:48:2422#include "base/trace_event.h"
[email protected]252cad62010-08-18 18:33:5723#include "base/utf_string_conversions.h"
[email protected]ce0e72462010-10-16 03:46:0524#include "base/win/scoped_bstr.h"
25#include "base/win/scoped_variant.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"
29#include "googleurl/src/gurl.h"
[email protected]f7817822009-09-24 05:11:5830#include "chrome_frame/utils.h"
31
[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
40 static TopLevelWindowMapping* instance() {
41 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) {
78 CWPSTRUCT *info = reinterpret_cast<CWPSTRUCT*>(lparam);
79 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 =
86 TopLevelWindowMapping::instance()->GetInstances(message_hwnd);
87 TopLevelWindowMapping::WindowList::iterator
88 iter(cf_instances.begin()), end(cf_instances.end());
89 for (;iter != end; ++iter) {
90 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
118ChromeFrameActivex::ChromeFrameActivex()
119 : chrome_wndproc_hook_(NULL) {
[email protected]04e3f352010-05-10 13:48:24120 TRACE_EVENT_BEGIN("chromeframe.createactivex", this, "");
[email protected]f7817822009-09-24 05:11:58121}
122
123HRESULT ChromeFrameActivex::FinalConstruct() {
124 HRESULT hr = Base::FinalConstruct();
125 if (FAILED(hr))
126 return hr;
127
128 // No need to call FireOnChanged at this point since nobody will be listening.
129 ready_state_ = READYSTATE_LOADING;
130 return S_OK;
131}
132
133ChromeFrameActivex::~ChromeFrameActivex() {
134 // We expect these to be released during a call to SetClientSite(NULL).
[email protected]f55bd4862010-05-27 15:38:07135 DCHECK_EQ(0u, onmessage_.size());
136 DCHECK_EQ(0u, onloaderror_.size());
137 DCHECK_EQ(0u, onload_.size());
138 DCHECK_EQ(0u, onreadystatechanged_.size());
139 DCHECK_EQ(0u, onextensionready_.size());
[email protected]3eb07da2010-02-01 19:48:36140
[email protected]2b19e2fe2010-02-16 02:24:18141 if (chrome_wndproc_hook_) {
142 BOOL unhook_success = ::UnhookWindowsHookEx(chrome_wndproc_hook_);
143 DCHECK(unhook_success);
144 }
145
[email protected]3eb07da2010-02-01 19:48:36146 // ChromeFramePlugin::Uninitialize()
147 Base::Uninitialize();
[email protected]04e3f352010-05-10 13:48:24148
149 TRACE_EVENT_END("chromeframe.createactivex", this, "");
[email protected]f7817822009-09-24 05:11:58150}
151
152LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
153 BOOL& handled) {
154 Base::OnCreate(message, wparam, lparam, handled);
[email protected]2b19e2fe2010-02-16 02:24:18155 // Install the notification hook on the top-level window, so that we can
156 // be notified on move events. Note that the return value is not checked.
157 // This hook is installed here, as opposed to during IOleObject_SetClientSite
158 // because m_hWnd has not yet been assigned during the SetSite call.
159 InstallTopLevelHook(m_spClientSite);
160 return 0;
161}
162
163LRESULT ChromeFrameActivex::OnHostMoved(UINT message, WPARAM wparam,
164 LPARAM lparam, BOOL& handled) {
165 Base::OnHostMoved();
[email protected]f7817822009-09-24 05:11:58166 return 0;
167}
168
[email protected]f7817822009-09-24 05:11:58169HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
170 ScopedComPtr<IOleContainer> container;
171 HRESULT hr = m_spClientSite->GetContainer(container.Receive());
172 if (container)
173 hr = container.QueryInterface(doc);
174 return hr;
175}
176
177HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
178 ScopedComPtr<IHTMLDocument2> document;
179 HRESULT hr = GetContainingDocument(document.Receive());
180 if (document)
181 hr = document->get_parentWindow(window);
182 return hr;
183}
184
185void ChromeFrameActivex::OnLoad(int tab_handle, const GURL& gurl) {
186 ScopedComPtr<IDispatch> event;
187 std::string url = gurl.spec();
188 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
189 Fire_onload(event);
190
191 FireEvent(onload_, url);
[email protected]a1800e82009-11-19 00:53:23192 Base::OnLoad(tab_handle, gurl);
[email protected]f7817822009-09-24 05:11:58193}
194
195void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
196 ScopedComPtr<IDispatch> event;
197 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
198 Fire_onloaderror(event);
199
200 FireEvent(onloaderror_, url);
[email protected]a1800e82009-11-19 00:53:23201 Base::OnLoadFailed(error_code, url);
[email protected]f7817822009-09-24 05:11:58202}
203
204void ChromeFrameActivex::OnMessageFromChromeFrame(int tab_handle,
205 const std::string& message,
206 const std::string& origin,
207 const std::string& target) {
208 DLOG(INFO) << __FUNCTION__;
209
210 if (target.compare("*") != 0) {
211 bool drop = true;
212
213 if (is_privileged_) {
214 // Forward messages if the control is in privileged mode.
215 ScopedComPtr<IDispatch> message_event;
216 if (SUCCEEDED(CreateDomEvent("message", message, origin,
217 message_event.Receive()))) {
[email protected]ce0e72462010-10-16 03:46:05218 base::win::ScopedBstr target_bstr(UTF8ToWide(target).c_str());
[email protected]f7817822009-09-24 05:11:58219 Fire_onprivatemessage(message_event, target_bstr);
220
221 FireEvent(onprivatemessage_, message_event, target_bstr);
222 }
223 } else {
224 if (HaveSameOrigin(target, document_url_)) {
225 drop = false;
226 } else {
227 DLOG(WARNING) << "Dropping posted message since target doesn't match "
228 "the current document's origin. target=" << target;
229 }
230 }
231
232 if (drop)
233 return;
234 }
235
236 ScopedComPtr<IDispatch> message_event;
237 if (SUCCEEDED(CreateDomEvent("message", message, origin,
238 message_event.Receive()))) {
239 Fire_onmessage(message_event);
240
241 FireEvent(onmessage_, message_event);
242
[email protected]ce0e72462010-10-16 03:46:05243 base::win::ScopedVariant event_var;
[email protected]f7817822009-09-24 05:11:58244 event_var.Set(static_cast<IDispatch*>(message_event));
245 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
246 }
247}
248
249void ChromeFrameActivex::OnAutomationServerLaunchFailed(
250 AutomationLaunchResult reason, const std::string& server_version) {
251 Base::OnAutomationServerLaunchFailed(reason, server_version);
252
253 if (reason == AUTOMATION_VERSION_MISMATCH) {
254 DisplayVersionMismatchWarning(m_hWnd, server_version);
255 }
256}
257
[email protected]00f6b772009-10-23 17:03:41258void ChromeFrameActivex::OnExtensionInstalled(
259 const FilePath& path,
260 void* user_data,
261 AutomationMsg_ExtensionResponseValues response) {
[email protected]ce0e72462010-10-16 03:46:05262 base::win::ScopedBstr path_str(path.value().c_str());
[email protected]00f6b772009-10-23 17:03:41263 Fire_onextensionready(path_str, response);
264}
265
[email protected]a1e62d12010-03-16 02:18:43266void ChromeFrameActivex::OnGetEnabledExtensionsComplete(
267 void* user_data,
268 const std::vector<FilePath>& extension_directories) {
269 SAFEARRAY* sa = ::SafeArrayCreateVector(VT_BSTR, 0,
270 extension_directories.size());
271 sa->fFeatures = sa->fFeatures | FADF_BSTR;
272 ::SafeArrayLock(sa);
273
274 for (size_t i = 0; i < extension_directories.size(); ++i) {
275 LONG index = static_cast<LONG>(i);
276 ::SafeArrayPutElement(sa, &index, reinterpret_cast<void*>(
[email protected]466a9222010-06-08 01:03:16277 CComBSTR(extension_directories[i].value().c_str()).Detach()));
[email protected]a1e62d12010-03-16 02:18:43278 }
279
280 Fire_ongetenabledextensionscomplete(sa);
281 ::SafeArrayUnlock(sa);
282 ::SafeArrayDestroy(sa);
283}
284
[email protected]efd4dfc22010-03-26 20:14:40285void ChromeFrameActivex::OnChannelError() {
286 Fire_onchannelerror();
287}
288
289HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
[email protected]f7817822009-09-24 05:11:58290 HRESULT hr = S_OK;
291 int dc_type = ::GetObjectType(draw_info.hicTargetDev);
292 if (dc_type == OBJ_ENHMETADC) {
293 RECT print_bounds = {0};
294 print_bounds.left = draw_info.prcBounds->left;
295 print_bounds.right = draw_info.prcBounds->right;
296 print_bounds.top = draw_info.prcBounds->top;
297 print_bounds.bottom = draw_info.prcBounds->bottom;
298
299 automation_client_->Print(draw_info.hdcDraw, print_bounds);
300 } else {
301 hr = Base::OnDraw(draw_info);
302 }
303
304 return hr;
305}
306
307STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
308 DCHECK(bag);
309
310 const wchar_t* event_props[] = {
311 (L"onload"),
312 (L"onloaderror"),
313 (L"onmessage"),
314 (L"onreadystatechanged"),
315 };
316
[email protected]ce0e72462010-10-16 03:46:05317 base::win::ScopedComPtr<IHTMLObjectElement> obj_element;
[email protected]f7817822009-09-24 05:11:58318 GetObjectElement(obj_element.Receive());
319
[email protected]ce0e72462010-10-16 03:46:05320 base::win::ScopedBstr object_id;
[email protected]f7817822009-09-24 05:11:58321 GetObjectScriptId(obj_element, object_id.Receive());
322
323 ScopedComPtr<IHTMLElement2> element;
324 element.QueryFrom(obj_element);
325 HRESULT hr = S_OK;
326
327 for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
[email protected]ce0e72462010-10-16 03:46:05328 base::win::ScopedBstr prop(event_props[i]);
329 base::win::ScopedVariant value;
[email protected]f7817822009-09-24 05:11:58330 if (SUCCEEDED(bag->Read(prop, value.Receive(), error_log))) {
331 if (value.type() != VT_BSTR ||
332 FAILED(hr = CreateScriptBlockForEvent(element, object_id,
333 V_BSTR(&value), prop))) {
334 DLOG(ERROR) << "Failed to create script block for " << prop
[email protected]d3451d832010-10-01 11:17:37335 << base::StringPrintf(L"hr=0x%08X, vt=%i", hr,
336 value.type());
[email protected]f7817822009-09-24 05:11:58337 } else {
338 DLOG(INFO) << "script block created for event " << prop <<
[email protected]d3451d832010-10-01 11:17:37339 base::StringPrintf(" (0x%08X)", hr) << " connections: " <<
[email protected]f7817822009-09-24 05:11:58340 ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
341 }
342 } else {
343 DLOG(INFO) << "event property " << prop << " not in property bag";
344 }
345 }
346
[email protected]ce0e72462010-10-16 03:46:05347 base::win::ScopedVariant src;
348 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"src"), src.Receive(),
349 error_log))) {
[email protected]f7817822009-09-24 05:11:58350 if (src.type() == VT_BSTR) {
351 hr = put_src(V_BSTR(&src));
352 DCHECK(hr != E_UNEXPECTED);
353 }
354 }
355
[email protected]ce0e72462010-10-16 03:46:05356 base::win::ScopedVariant use_chrome_network;
357 if (SUCCEEDED(bag->Read(base::win::ScopedBstr(L"useChromeNetwork"),
[email protected]f7817822009-09-24 05:11:58358 use_chrome_network.Receive(), error_log))) {
359 VariantChangeType(use_chrome_network.AsInput(),
360 use_chrome_network.AsInput(),
361 0, VT_BOOL);
362 if (use_chrome_network.type() == VT_BOOL) {
363 hr = put_useChromeNetwork(V_BOOL(&use_chrome_network));
364 DCHECK(hr != E_UNEXPECTED);
365 }
366 }
367
368 DLOG_IF(ERROR, FAILED(hr))
[email protected]d3451d832010-10-01 11:17:37369 << base::StringPrintf("Failed to load property bag: 0x%08X", hr);
[email protected]f7817822009-09-24 05:11:58370
371 return hr;
372}
373
[email protected]b4e75c12010-05-18 18:28:48374const wchar_t g_activex_insecure_content_error[] = {
[email protected]f7817822009-09-24 05:11:58375 L"data:text/html,<html><body><b>ChromeFrame Security Error<br><br>"
376 L"Cannot navigate to HTTP url when document URL is HTTPS</body></html>"};
[email protected]2b8fd322009-10-02 00:00:59377
[email protected]f7817822009-09-24 05:11:58378STDMETHODIMP ChromeFrameActivex::put_src(BSTR src) {
379 GURL document_url(GetDocumentUrl());
380 if (document_url.SchemeIsSecure()) {
381 GURL source_url(src);
382 if (!source_url.SchemeIsSecure()) {
[email protected]b4e75c12010-05-18 18:28:48383 Base::put_src(ScopedBstr(g_activex_insecure_content_error));
[email protected]f7817822009-09-24 05:11:58384 return E_ACCESSDENIED;
385 }
386 }
387 return Base::put_src(src);
388}
389
390HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
391 IOleClientSite* client_site) {
392 HRESULT hr = Base::IOleObject_SetClientSite(client_site);
393 if (FAILED(hr) || !client_site) {
394 EventHandlers* handlers[] = {
395 &onmessage_,
396 &onloaderror_,
397 &onload_,
398 &onreadystatechanged_,
[email protected]00f6b772009-10-23 17:03:41399 &onextensionready_,
[email protected]f7817822009-09-24 05:11:58400 };
401
402 for (int i = 0; i < arraysize(handlers); ++i)
403 handlers[i]->clear();
404
405 // Drop privileged mode on uninitialization.
406 is_privileged_ = false;
407 } else {
408 ScopedComPtr<IHTMLDocument2> document;
409 GetContainingDocument(document.Receive());
410 if (document) {
411 ScopedBstr url;
412 if (SUCCEEDED(document->get_URL(url.Receive())))
413 WideToUTF8(url, url.Length(), &document_url_);
414 }
415
416 // Probe to see whether the host implements the privileged service.
417 ScopedComPtr<IChromeFramePrivileged> service;
[email protected]4c4aae72010-07-30 05:54:21418 HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged,
419 m_spClientSite,
420 service.Receive());
[email protected]f7817822009-09-24 05:11:58421 if (SUCCEEDED(service_hr) && service) {
422 // Does the host want privileged mode?
423 boolean wants_privileged = false;
424 service_hr = service->GetWantsPrivileged(&wants_privileged);
425
426 if (SUCCEEDED(service_hr) && wants_privileged)
427 is_privileged_ = true;
[email protected]7403d38f2010-03-22 22:50:49428
[email protected]bbfa9a12010-08-10 14:09:37429 url_fetcher_->set_privileged_mode(is_privileged_);
[email protected]f7817822009-09-24 05:11:58430 }
431
432 std::wstring chrome_extra_arguments;
433 std::wstring profile_name(GetHostProcessName(false));
434 if (is_privileged_) {
435 // Does the host want to provide extra arguments?
[email protected]ce0e72462010-10-16 03:46:05436 base::win::ScopedBstr extra_arguments_arg;
[email protected]f7817822009-09-24 05:11:58437 service_hr = service->GetChromeExtraArguments(
438 extra_arguments_arg.Receive());
439 if (S_OK == service_hr && extra_arguments_arg)
440 chrome_extra_arguments.assign(extra_arguments_arg,
441 extra_arguments_arg.Length());
442
[email protected]50f53162009-10-23 19:16:20443 ScopedBstr automated_functions_arg;
444 service_hr = service->GetExtensionApisToAutomate(
445 automated_functions_arg.Receive());
446 if (S_OK == service_hr && automated_functions_arg) {
447 std::string automated_functions(
448 WideToASCII(static_cast<BSTR>(automated_functions_arg)));
449 functions_enabled_.clear();
[email protected]76eb0242010-10-14 00:35:36450 // base::SplitString writes one empty entry for blank strings, so we
451 // need this to allow specifying zero automation of API functions.
[email protected]50f53162009-10-23 19:16:20452 if (!automated_functions.empty())
[email protected]76eb0242010-10-14 00:35:36453 base::SplitString(automated_functions, ',', &functions_enabled_);
[email protected]50f53162009-10-23 19:16:20454 }
455
[email protected]ce0e72462010-10-16 03:46:05456 base::win::ScopedBstr profile_name_arg;
[email protected]f7817822009-09-24 05:11:58457 service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
458 if (S_OK == service_hr && profile_name_arg)
459 profile_name.assign(profile_name_arg, profile_name_arg.Length());
460 }
461
[email protected]e150e822010-06-03 23:10:55462 std::string utf8_url;
463 if (url_.Length()) {
464 WideToUTF8(url_, url_.Length(), &utf8_url);
465 }
466
[email protected]9eeb35e2010-09-30 21:38:50467 InitializeAutomationSettings();
[email protected]e1081d92010-09-10 20:29:11468
[email protected]bbfa9a12010-08-10 14:09:37469 url_fetcher_->set_frame_busting(!is_privileged_);
470 automation_client_->SetUrlFetcher(url_fetcher_.get());
[email protected]f7817822009-09-24 05:11:58471 if (!InitializeAutomation(profile_name, chrome_extra_arguments,
[email protected]e150e822010-06-03 23:10:55472 IsIEInPrivate(), true, GURL(utf8_url),
[email protected]9eeb35e2010-09-30 21:38:50473 GURL(), false)) {
[email protected]4c4aae72010-07-30 05:54:21474 DLOG(ERROR) << "Failed to navigate to url:" << utf8_url;
[email protected]f7817822009-09-24 05:11:58475 return E_FAIL;
476 }
[email protected]d8e13512010-09-22 17:02:58477
478 // Log a metric that Chrome Frame is being used in Widget mode
479 THREAD_SAFE_UMA_LAUNCH_TYPE_COUNT(RENDERER_TYPE_CHROME_WIDGET);
[email protected]f7817822009-09-24 05:11:58480 }
481
482 return hr;
483}
484
485HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
486 BSTR* id) {
487 DCHECK(object_elem != NULL);
488 DCHECK(id != NULL);
489
490 HRESULT hr = E_FAIL;
491 if (object_elem) {
492 ScopedComPtr<IHTMLElement> elem;
493 hr = elem.QueryFrom(object_elem);
494 if (elem) {
495 hr = elem->get_id(id);
496 }
497 }
498
499 return hr;
500}
501
502HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
503 DCHECK(m_spClientSite);
504 if (!m_spClientSite)
505 return E_UNEXPECTED;
506
507 ScopedComPtr<IOleControlSite> site;
508 HRESULT hr = site.QueryFrom(m_spClientSite);
509 if (site) {
510 ScopedComPtr<IDispatch> disp;
511 hr = site->GetExtendedControl(disp.Receive());
512 if (disp) {
513 hr = disp.QueryInterface(element);
514 } else {
515 DCHECK(FAILED(hr));
516 }
517 }
518
519 return hr;
520}
521
522HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
523 IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
524 BSTR event_name) {
525 DCHECK(insert_after);
[email protected]efd4dfc22010-03-26 20:14:40526 DCHECK_GT(::SysStringLen(event_name), 0UL); // should always have this
[email protected]f7817822009-09-24 05:11:58527
528 // This might be 0 if not specified in the HTML document.
529 if (!::SysStringLen(instance_id)) {
530 // TODO(tommi): Should we give ourselves an ID if this happens?
531 NOTREACHED() << "Need to handle this";
532 return E_INVALIDARG;
533 }
534
535 ScopedComPtr<IHTMLDocument2> document;
536 HRESULT hr = GetContainingDocument(document.Receive());
537 if (SUCCEEDED(hr)) {
538 ScopedComPtr<IHTMLElement> element, new_element;
[email protected]d9dc4ad2010-10-16 04:01:00539 document->createElement(base::win::ScopedBstr(L"script"),
540 element.Receive());
[email protected]f7817822009-09-24 05:11:58541 if (element) {
542 ScopedComPtr<IHTMLScriptElement> script_element;
543 if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
544 script_element->put_htmlFor(instance_id);
545 script_element->put_event(event_name);
546 script_element->put_text(script);
547
[email protected]d9dc4ad2010-10-16 04:01:00548 hr = insert_after->insertAdjacentElement(
549 base::win::StackBstr(L"afterEnd"),
550 element,
551 new_element.Receive());
[email protected]f7817822009-09-24 05:11:58552 }
553 }
554 }
555
556 return hr;
557}
558
[email protected]f7817822009-09-24 05:11:58559void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
560 const std::string& arg) {
561 if (handlers.size()) {
562 ScopedComPtr<IDispatch> event;
563 if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
564 FireEvent(handlers, event);
565 }
566 }
567}
568
569void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
570 IDispatch* event) {
571 DCHECK(event != NULL);
572 VARIANT arg = { VT_DISPATCH };
573 arg.pdispVal = event;
574 DISPPARAMS params = { &arg, NULL, 1, 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)
[email protected]d3451d832010-10-01 11:17:37583 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
[email protected]f7817822009-09-24 05:11:58584 }
585}
586
587void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
588 IDispatch* event, BSTR target) {
589 DCHECK(event != NULL);
590 // Arguments in reverse order to event handler function declaration,
591 // because that's what DISPPARAMS requires.
592 VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
593 args[0].bstrVal = target;
594 args[1].pdispVal = event;
595 DISPPARAMS params = { args, NULL, arraysize(args), 0 };
596 for (EventHandlers::const_iterator it = handlers.begin();
597 it != handlers.end();
598 ++it) {
599 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
600 DISPATCH_METHOD, &params, NULL, NULL, NULL);
601 // 0x80020101 == SCRIPT_E_REPORTED.
602 // When the script we're invoking has an error, we get this error back.
603 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
[email protected]d3451d832010-10-01 11:17:37604 << base::StringPrintf(L"Failed to invoke script: 0x%08X", hr);
[email protected]f7817822009-09-24 05:11:58605 }
606}
[email protected]2b19e2fe2010-02-16 02:24:18607
608HRESULT ChromeFrameActivex::InstallTopLevelHook(IOleClientSite* client_site) {
609 // Get the parent window of the site, and install our hook on the topmost
610 // window of the parent.
611 ScopedComPtr<IOleWindow> ole_window;
612 HRESULT hr = ole_window.QueryFrom(client_site);
613 if (FAILED(hr))
614 return hr;
615
616 HWND parent_wnd;
617 hr = ole_window->GetWindow(&parent_wnd);
618 if (FAILED(hr))
619 return hr;
620
621 HWND top_window = ::GetAncestor(parent_wnd, GA_ROOT);
622 chrome_wndproc_hook_ = InstallLocalWindowHook(top_window);
623 if (chrome_wndproc_hook_)
624 TopLevelWindowMapping::instance()->AddMapping(top_window, m_hWnd);
625
626 return chrome_wndproc_hook_ ? S_OK : E_FAIL;
627}
[email protected]c442e9f2010-04-29 18:37:44628
[email protected]ca982ec42010-05-02 14:47:14629HRESULT ChromeFrameActivex::registerBhoIfNeeded() {
630 if (!m_spUnkSite) {
[email protected]c442e9f2010-04-29 18:37:44631 NOTREACHED() << "Invalid client site";
632 return E_FAIL;
633 }
634
635 if (NavigationManager::GetThreadInstance() != NULL) {
636 DLOG(INFO) << "BHO already loaded";
637 return S_OK;
638 }
639
640 ScopedComPtr<IWebBrowser2> web_browser2;
[email protected]ca982ec42010-05-02 14:47:14641 HRESULT hr = DoQueryService(SID_SWebBrowserApp, m_spUnkSite,
[email protected]c442e9f2010-04-29 18:37:44642 web_browser2.Receive());
643 if (FAILED(hr) || web_browser2.get() == NULL) {
644 DLOG(WARNING) << "Failed to get IWebBrowser2 from client site. Error:"
[email protected]d3451d832010-10-01 11:17:37645 << base::StringPrintf(" 0x%08X", hr);
[email protected]c442e9f2010-04-29 18:37:44646 return hr;
647 }
648
649 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
650 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
651 arraysize(bho_class_id_as_string));
652
653 ScopedComPtr<IObjectWithSite> bho;
654 hr = bho.CreateInstance(CLSID_ChromeFrameBHO, NULL, CLSCTX_INPROC_SERVER);
655 if (FAILED(hr)) {
656 NOTREACHED() << "Failed to register ChromeFrame BHO. Error:"
[email protected]d3451d832010-10-01 11:17:37657 << base::StringPrintf(" 0x%08X", hr);
[email protected]c442e9f2010-04-29 18:37:44658 return hr;
659 }
660
661 hr = bho->SetSite(web_browser2);
662 if (FAILED(hr)) {
663 NOTREACHED() << "ChromeFrame BHO SetSite failed. Error:"
[email protected]d3451d832010-10-01 11:17:37664 << base::StringPrintf(" 0x%08X", hr);
[email protected]c442e9f2010-04-29 18:37:44665 return hr;
666 }
667
[email protected]ce0e72462010-10-16 03:46:05668 web_browser2->PutProperty(base::win::ScopedBstr(bho_class_id_as_string),
[email protected]c442e9f2010-04-29 18:37:44669 ScopedVariant(bho));
670 return S_OK;
671}