blob: c5ec65e600a8d997ac8b0abd78e8451a12ff7c88 [file] [log] [blame]
[email protected]bc73b4e52010-03-26 04:16:201// 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#ifndef CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_
6#define CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_
7
8#include <atlbase.h>
9#include <atlcom.h>
10#include <atlctl.h>
[email protected]ea9ed97d2010-01-05 19:16:2311#include <wininet.h>
[email protected]f7817822009-09-24 05:11:5812#include <shdeprecated.h> // for IBrowserService2
13#include <shlguid.h>
14
15#include <set>
16#include <string>
[email protected]efd4dfc22010-03-26 20:14:4017#include <vector>
[email protected]f7817822009-09-24 05:11:5818
19#include "base/histogram.h"
20#include "base/scoped_bstr_win.h"
21#include "base/scoped_comptr_win.h"
22#include "base/scoped_variant_win.h"
23#include "base/string_util.h"
[email protected]252cad62010-08-18 18:33:5724#include "base/utf_string_conversions.h"
[email protected]f7817822009-09-24 05:11:5825#include "grit/chrome_frame_resources.h"
[email protected]bc73b4e52010-03-26 04:16:2026#include "chrome/common/url_constants.h"
[email protected]f7817822009-09-24 05:11:5827#include "chrome_frame/chrome_frame_plugin.h"
[email protected]a1800e82009-11-19 00:53:2328#include "chrome_frame/com_message_event.h"
[email protected]f7817822009-09-24 05:11:5829#include "chrome_frame/com_type_info_holder.h"
[email protected]3c6f8e12010-03-24 21:58:2130#include "chrome_frame/simple_resource_loader.h"
[email protected]f7817822009-09-24 05:11:5831#include "chrome_frame/urlmon_url_request.h"
[email protected]7ae80742010-03-25 22:02:2732#include "chrome_frame/urlmon_url_request_private.h"
[email protected]bc73b4e52010-03-26 04:16:2033#include "chrome_frame/utils.h"
[email protected]35f13ab2009-12-16 23:59:1734#include "grit/generated_resources.h"
[email protected]aeb9efc2010-01-08 05:55:5035#include "net/base/cookie_monster.h"
[email protected]f7817822009-09-24 05:11:5836
37// Include without path to make GYP build see it.
38#include "chrome_tab.h" // NOLINT
39
[email protected]bc73b4e52010-03-26 04:16:2040static const wchar_t kIexploreProfileName[] = L"iexplore";
41static const wchar_t kRundllProfileName[] = L"rundll32";
42
[email protected]f7817822009-09-24 05:11:5843// Connection point class to support firing IChromeFrameEvents (dispinterface).
44template<class T>
45class ATL_NO_VTABLE ProxyDIChromeFrameEvents
46 : public IConnectionPointImpl<T, &DIID_DIChromeFrameEvents> {
47 public:
48 void FireMethodWithParams(ChromeFrameEventDispId dispid,
49 const VARIANT* params, size_t num_params) {
50 T* me = static_cast<T*>(this);
[email protected]efd4dfc22010-03-26 20:14:4051 // We need to copy the whole vector and AddRef the sinks in case
52 // some would get disconnected as we fire methods. Note that this is not
53 // a threading issue, but a re-entrance issue, because the connection
54 // can be affected by the implementation of the sinks receiving the event.
55 me->Lock();
56 std::vector< ScopedComPtr<IUnknown> > sink_array(m_vec.GetSize());
57 for (int connection = 0; connection < m_vec.GetSize(); ++connection)
58 sink_array[connection] = m_vec.GetAt(connection);
59 me->Unlock();
[email protected]f7817822009-09-24 05:11:5860
[email protected]efd4dfc22010-03-26 20:14:4061 for (size_t sink = 0; sink < sink_array.size(); ++sink) {
62 DIChromeFrameEvents* events =
63 static_cast<DIChromeFrameEvents*>(sink_array[sink].get());
[email protected]f7817822009-09-24 05:11:5864 if (events) {
65 DISPPARAMS disp_params = {
66 const_cast<VARIANT*>(params),
67 NULL,
68 num_params,
69 0};
70 HRESULT hr = events->Invoke(static_cast<DISPID>(dispid),
71 DIID_DIChromeFrameEvents,
72 LOCALE_USER_DEFAULT, DISPATCH_METHOD,
73 &disp_params, NULL, NULL, NULL);
74 DLOG_IF(ERROR, FAILED(hr)) << "invoke(" << dispid << ") failed" <<
75 StringPrintf("0x%08X", hr);
76 }
77 }
78 }
79
80 void FireMethodWithParam(ChromeFrameEventDispId dispid,
81 const VARIANT& param) {
82 FireMethodWithParams(dispid, &param, 1);
83 }
84
85 void Fire_onload(IDispatch* event) {
86 VARIANT var = { VT_DISPATCH };
87 var.pdispVal = event;
88 FireMethodWithParam(CF_EVENT_DISPID_ONLOAD, var);
89 }
90
91 void Fire_onloaderror(IDispatch* event) {
92 VARIANT var = { VT_DISPATCH };
93 var.pdispVal = event;
94 FireMethodWithParam(CF_EVENT_DISPID_ONLOADERROR, var);
95 }
96
97 void Fire_onmessage(IDispatch* event) {
98 VARIANT var = { VT_DISPATCH };
99 var.pdispVal = event;
100 FireMethodWithParam(CF_EVENT_DISPID_ONMESSAGE, var);
101 }
102
[email protected]62bb18dc12009-11-25 01:34:08103 void Fire_onreadystatechanged(long readystate) { // NOLINT
[email protected]f7817822009-09-24 05:11:58104 VARIANT var = { VT_I4 };
105 var.lVal = readystate;
106 FireMethodWithParam(CF_EVENT_DISPID_ONREADYSTATECHANGED, var);
107 }
108
109 void Fire_onprivatemessage(IDispatch* event, BSTR target) {
110 // Arguments in reverse order to the function declaration, because
111 // that's what DISPPARAMS requires.
112 VARIANT args[2] = { { VT_BSTR, }, {VT_DISPATCH, } };
113 args[0].bstrVal = target;
114 args[1].pdispVal = event;
115
116 FireMethodWithParams(CF_EVENT_DISPID_ONPRIVATEMESSAGE,
117 args,
118 arraysize(args));
119 }
[email protected]00f6b772009-10-23 17:03:41120
[email protected]62bb18dc12009-11-25 01:34:08121 void Fire_onextensionready(BSTR path, long response) { // NOLINT
[email protected]00f6b772009-10-23 17:03:41122 // Arguments in reverse order to the function declaration, because
123 // that's what DISPPARAMS requires.
124 VARIANT args[2] = { { VT_I4, }, { VT_BSTR, } };
125 args[0].lVal = response;
126 args[1].bstrVal = path;
127
128 FireMethodWithParams(CF_EVENT_DISPID_ONEXTENSIONREADY,
129 args,
130 arraysize(args));
131 }
[email protected]a1e62d12010-03-16 02:18:43132
[email protected]efd4dfc22010-03-26 20:14:40133 void Fire_ongetenabledextensionscomplete(SAFEARRAY* extension_dirs) {
[email protected]a1e62d12010-03-16 02:18:43134 VARIANT args[1] = { { VT_ARRAY | VT_BSTR } };
135 args[0].parray = extension_dirs;
136
137 FireMethodWithParams(CF_EVENT_DISPID_ONGETENABLEDEXTENSIONSCOMPLETE,
138 args, arraysize(args));
139 }
[email protected]efd4dfc22010-03-26 20:14:40140
141 void Fire_onchannelerror() { // NOLINT
142 FireMethodWithParams(CF_EVENT_DISPID_ONCHANNELERROR, NULL, 0);
143 }
[email protected]f7817822009-09-24 05:11:58144};
145
146extern bool g_first_launch_by_process_;
147
[email protected]41a61cc2010-01-04 19:12:10148// Posted when the worker thread used for handling URL requests in IE finishes
149// uninitialization.
150#define WM_WORKER_THREAD_UNINITIALIZED_MSG (WM_APP + 1)
151
[email protected]f7817822009-09-24 05:11:58152// Common implementation for ActiveX and Active Document
153template <class T, const CLSID& class_id>
[email protected]62bb18dc12009-11-25 01:34:08154class ATL_NO_VTABLE ChromeFrameActivexBase : // NOLINT
[email protected]b0febbf2009-11-12 17:49:35155 public CComObjectRootEx<CComMultiThreadModel>,
[email protected]f7817822009-09-24 05:11:58156 public IOleControlImpl<T>,
157 public IOleObjectImpl<T>,
158 public IOleInPlaceActiveObjectImpl<T>,
159 public IViewObjectExImpl<T>,
160 public IOleInPlaceObjectWindowlessImpl<T>,
161 public ISupportErrorInfo,
162 public IQuickActivateImpl<T>,
163 public com_util::IProvideClassInfo2Impl<class_id,
164 DIID_DIChromeFrameEvents>,
165 public com_util::IDispatchImpl<IChromeFrame>,
166 public IConnectionPointContainerImpl<T>,
167 public ProxyDIChromeFrameEvents<T>,
168 public IPropertyNotifySinkCP<T>,
169 public CComCoClass<T, &class_id>,
170 public CComControl<T>,
[email protected]dda7d9c2009-11-11 23:01:47171 public ChromeFramePlugin<T> {
[email protected]f7817822009-09-24 05:11:58172 protected:
173 typedef std::set<ScopedComPtr<IDispatch> > EventHandlers;
[email protected]97965e12010-04-09 00:51:10174 typedef ChromeFrameActivexBase<T, class_id> BasePlugin;
[email protected]f7817822009-09-24 05:11:58175
176 public:
177 ChromeFrameActivexBase()
[email protected]3eafbfb92010-08-02 16:54:22178 : ready_state_(READYSTATE_UNINITIALIZED),
[email protected]bbfa9a12010-08-10 14:09:37179 url_fetcher_(new UrlmonUrlRequestManager()),
180 failed_to_fetch_in_place_frame_(false),
181 draw_sad_tab_(false) {
[email protected]f7817822009-09-24 05:11:58182 m_bWindowOnly = TRUE;
[email protected]bbfa9a12010-08-10 14:09:37183 url_fetcher_->set_container(static_cast<IDispatch*>(this));
[email protected]f7817822009-09-24 05:11:58184 }
185
186 ~ChromeFrameActivexBase() {
[email protected]bbfa9a12010-08-10 14:09:37187 url_fetcher_->set_container(NULL);
[email protected]f7817822009-09-24 05:11:58188 }
189
190DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | OLEMISC_CANTLINKINSIDE |
191 OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE |
192 OLEMISC_SETCLIENTSITEFIRST)
193
194DECLARE_NOT_AGGREGATABLE(T)
195
196BEGIN_COM_MAP(ChromeFrameActivexBase)
197 COM_INTERFACE_ENTRY(IChromeFrame)
198 COM_INTERFACE_ENTRY(IDispatch)
199 COM_INTERFACE_ENTRY(IViewObjectEx)
200 COM_INTERFACE_ENTRY(IViewObject2)
201 COM_INTERFACE_ENTRY(IViewObject)
202 COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
203 COM_INTERFACE_ENTRY(IOleInPlaceObject)
204 COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
205 COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
206 COM_INTERFACE_ENTRY(IOleControl)
207 COM_INTERFACE_ENTRY(IOleObject)
208 COM_INTERFACE_ENTRY(ISupportErrorInfo)
209 COM_INTERFACE_ENTRY(IQuickActivate)
210 COM_INTERFACE_ENTRY(IProvideClassInfo)
211 COM_INTERFACE_ENTRY(IProvideClassInfo2)
[email protected]bbfa9a12010-08-10 14:09:37212 COM_INTERFACE_ENTRY(IConnectionPointContainer)
[email protected]f7817822009-09-24 05:11:58213 COM_INTERFACE_ENTRY_FUNC_BLIND(0, InterfaceNotSupported)
214END_COM_MAP()
215
216BEGIN_CONNECTION_POINT_MAP(T)
217 CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
218 CONNECTION_POINT_ENTRY(DIID_DIChromeFrameEvents)
219END_CONNECTION_POINT_MAP()
220
221BEGIN_MSG_MAP(ChromeFrameActivexBase)
222 MESSAGE_HANDLER(WM_CREATE, OnCreate)
[email protected]7ae80742010-03-25 22:02:27223 MESSAGE_HANDLER(WM_DOWNLOAD_IN_HOST, OnDownloadRequestInHost)
[email protected]e9eb50c2009-10-24 16:26:46224 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
[email protected]f7817822009-09-24 05:11:58225 CHAIN_MSG_MAP(ChromeFramePlugin<T>)
226 CHAIN_MSG_MAP(CComControl<T>)
227 DEFAULT_REFLECTION_HANDLER()
228END_MSG_MAP()
229
230 // IViewObjectEx
231 DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)
232
[email protected]48e6bb62009-09-30 20:32:46233 inline HRESULT IViewObject_Draw(DWORD draw_aspect, LONG index,
234 void* aspect_info, DVTARGETDEVICE* ptd, HDC info_dc, HDC dc,
235 LPCRECTL bounds, LPCRECTL win_bounds) {
236 // ATL ASSERTs if dwDrawAspect is DVASPECT_DOCPRINT, so we cheat.
237 DWORD aspect = draw_aspect;
238 if (aspect == DVASPECT_DOCPRINT)
239 aspect = DVASPECT_CONTENT;
240
241 return CComControl<T>::IViewObject_Draw(aspect, index, aspect_info, ptd,
242 info_dc, dc, bounds, win_bounds);
243 }
[email protected]f7817822009-09-24 05:11:58244
245 DECLARE_PROTECT_FINAL_CONSTRUCT()
246
[email protected]3c6f8e12010-03-24 21:58:21247 virtual void SetResourceModule() {
248 SimpleResourceLoader* loader_instance = SimpleResourceLoader::instance();
249 DCHECK(loader_instance);
250 HINSTANCE res_dll = loader_instance->GetResourceModuleHandle();
251 _AtlBaseModule.SetResourceInstance(res_dll);
252 }
253
[email protected]f7817822009-09-24 05:11:58254 HRESULT FinalConstruct() {
[email protected]3c6f8e12010-03-24 21:58:21255 SetResourceModule();
256
[email protected]f7817822009-09-24 05:11:58257 if (!Initialize())
258 return E_OUTOFMEMORY;
259
260 // Set to true if this is the first launch by this process.
261 // Used to perform one time tasks.
262 if (g_first_launch_by_process_) {
263 g_first_launch_by_process_ = false;
[email protected]333590002010-03-05 18:49:21264 THREAD_SAFE_UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.IEVersion",
265 GetIEVersion(),
266 IE_INVALID,
267 IE_8,
268 IE_8 + 1);
[email protected]f7817822009-09-24 05:11:58269 }
270 return S_OK;
271 }
272
273 void FinalRelease() {
[email protected]89f19542010-01-05 21:55:11274 Uninitialize();
[email protected]f7817822009-09-24 05:11:58275 }
276
[email protected]bbfa9a12010-08-10 14:09:37277 void ResetUrlRequestManager() {
278 url_fetcher_.reset(new UrlmonUrlRequestManager());
279 }
280
[email protected]f7817822009-09-24 05:11:58281 static HRESULT WINAPI InterfaceNotSupported(void* pv, REFIID riid, void** ppv,
282 DWORD dw) {
283#ifndef NDEBUG
284 wchar_t buffer[64] = {0};
285 ::StringFromGUID2(riid, buffer, arraysize(buffer));
286 DLOG(INFO) << "E_NOINTERFACE: " << buffer;
287#endif
288 return E_NOINTERFACE;
289 }
290
291 // ISupportsErrorInfo
292 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) {
293 static const IID* interfaces[] = {
294 &IID_IChromeFrame,
295 &IID_IDispatch
296 };
297
298 for (int i = 0; i < arraysize(interfaces); ++i) {
299 if (InlineIsEqualGUID(*interfaces[i], riid))
300 return S_OK;
301 }
302 return S_FALSE;
303 }
304
305 // Called to draw our control when chrome hasn't been initialized.
[email protected]62bb18dc12009-11-25 01:34:08306 virtual HRESULT OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
[email protected]f7817822009-09-24 05:11:58307 if (NULL == draw_info.prcBounds) {
308 NOTREACHED();
309 return E_FAIL;
310 }
[email protected]bbfa9a12010-08-10 14:09:37311
312 if (draw_sad_tab_) {
313 // TODO(tommi): Draw a proper sad tab.
314 RECT rc = {0};
315 if (draw_info.prcBounds) {
316 rc.top = draw_info.prcBounds->top;
317 rc.bottom = draw_info.prcBounds->bottom;
318 rc.left = draw_info.prcBounds->left;
319 rc.right = draw_info.prcBounds->right;
320 } else {
321 GetClientRect(&rc);
322 }
323 ::DrawTextA(draw_info.hdcDraw, ":-(", -1, &rc,
324 DT_CENTER | DT_VCENTER | DT_SINGLELINE);
325 } else {
326 // Don't draw anything.
327 }
[email protected]f7817822009-09-24 05:11:58328 return S_OK;
329 }
330
331
332 // Used to setup the document_url_ member needed for completing navigation.
333 // Create external tab (possibly in incognito mode).
334 HRESULT IOleObject_SetClientSite(IOleClientSite* client_site) {
335 // If we currently have a document site pointer, release it.
336 doc_site_.Release();
337 if (client_site) {
338 doc_site_.QueryFrom(client_site);
339 }
340
[email protected]3eafbfb92010-08-02 16:54:22341 if (client_site == NULL) {
342 in_place_frame_.Release();
343 }
344
[email protected]f7817822009-09-24 05:11:58345 return CComControlBase::IOleObject_SetClientSite(client_site);
346 }
347
[email protected]35f13ab2009-12-16 23:59:17348 bool HandleContextMenuCommand(UINT cmd,
349 const IPC::ContextMenuParams& params) {
[email protected]f7817822009-09-24 05:11:58350 if (cmd == IDC_ABOUT_CHROME_FRAME) {
351 int tab_handle = automation_client_->tab()->handle();
[email protected]b1c55638612010-03-08 16:26:11352 HostNavigate(GURL("about:version"), GURL(), NEW_WINDOW);
[email protected]f7817822009-09-24 05:11:58353 return true;
[email protected]35f13ab2009-12-16 23:59:17354 } else {
355 switch (cmd) {
356 case IDS_CONTENT_CONTEXT_SAVEAUDIOAS:
357 case IDS_CONTENT_CONTEXT_SAVEVIDEOAS:
358 case IDS_CONTENT_CONTEXT_SAVEIMAGEAS:
359 case IDS_CONTENT_CONTEXT_SAVELINKAS: {
360 const GURL& referrer = params.frame_url.is_empty() ?
361 params.page_url : params.frame_url;
362 const GURL& url = (cmd == IDS_CONTENT_CONTEXT_SAVELINKAS ?
363 params.link_url : params.src_url);
364 DoFileDownloadInIE(UTF8ToWide(url.spec()).c_str());
365 return true;
366 }
367 }
[email protected]f7817822009-09-24 05:11:58368 }
369
370 return false;
371 }
372
[email protected]10bf1a72009-10-01 16:00:21373 // Should connections initiated by this class try to block
374 // responses served with the X-Frame-Options header?
375 // ActiveX controls genereally will want to do this,
376 // returning true, while true top-level documents
377 // (ActiveDocument servers) will not. Your specialization
378 // of this template should implement this method based on how
379 // it "feels" from a security perspective. If it's hosted in another
[email protected]f7817822009-09-24 05:11:58380 // scriptable document, return true, else false.
[email protected]2ce57c782009-11-17 18:15:40381 //
382 // The base implementation returns true unless we are in privileged
383 // mode, in which case we always trust our container so we return false.
[email protected]5778de6e2009-10-24 01:29:20384 bool is_frame_busting_enabled() const {
[email protected]2ce57c782009-11-17 18:15:40385 return !is_privileged_;
[email protected]f7817822009-09-24 05:11:58386 }
387
[email protected]5778de6e2009-10-24 01:29:20388 // Needed to support PostTask.
389 static bool ImplementsThreadSafeReferenceCounting() {
390 return true;
391 }
392
[email protected]1f71d5882010-07-15 20:39:07393 // IOleInPlaceObject overrides.
394 STDMETHOD(InPlaceDeactivate)(void) {
395 static UINT onload_handlers_done_msg =
396 RegisterWindowMessage(L"ChromeFrame_OnloadHandlersDone");
397
398 if (m_bInPlaceActive && IsWindow() && IsValid()) {
399 static const int kChromeFrameUnloadEventTimerId = 0xdeadbeef;
400 static const int kChromeFrameUnloadEventTimeout = 1000;
401
402 // To prevent us from indefinitely waiting for an acknowledgement from
403 // Chrome indicating that unload handlers have been run, we set a 1
404 // second timer and exit the loop when it fires.
405 ::SetTimer(m_hWnd, kChromeFrameUnloadEventTimerId,
406 kChromeFrameUnloadEventTimeout, NULL);
407
408 automation_client_->RunUnloadHandlers(m_hWnd, onload_handlers_done_msg);
409
410 MSG msg = {0};
411 while (GetMessage(&msg, NULL, 0, 0)) {
412 if (msg.message == onload_handlers_done_msg &&
413 msg.hwnd == m_hWnd) {
414 break;
415 }
416
417 if (msg.message == WM_TIMER &&
418 msg.wParam == kChromeFrameUnloadEventTimerId) {
419 break;
420 }
421 TranslateMessage(&msg);
422 DispatchMessage(&msg);
423 }
424
425 ::KillTimer(m_hWnd, kChromeFrameUnloadEventTimerId);
426 }
427 return IOleInPlaceObjectWindowlessImpl<T>::InPlaceDeactivate();
428 }
429
[email protected]f7817822009-09-24 05:11:58430 protected:
[email protected]bc73b4e52010-03-26 04:16:20431 virtual void GetProfilePath(const std::wstring& profile_name,
432 FilePath* profile_path) {
433 bool is_IE = (lstrcmpi(profile_name.c_str(), kIexploreProfileName) == 0) ||
434 (lstrcmpi(profile_name.c_str(), kRundllProfileName) == 0);
435 // Browsers without IDeleteBrowsingHistory in non-priv mode
436 // have their profiles moved into "Temporary Internet Files".
437 if (is_IE && GetIEVersion() < IE_8 && !is_privileged_) {
438 *profile_path = GetIETemporaryFilesFolder();
439 *profile_path = profile_path->Append(L"Google Chrome Frame");
440 } else {
441 ChromeFramePlugin::GetProfilePath(profile_name, profile_path);
442 }
443 DLOG(INFO) << __FUNCTION__ << ": " << profile_path->value();
444 }
445
446
[email protected]a1800e82009-11-19 00:53:23447 void OnLoad(int tab_handle, const GURL& url) {
448 if (ready_state_ < READYSTATE_COMPLETE) {
449 ready_state_ = READYSTATE_COMPLETE;
450 FireOnChanged(DISPID_READYSTATE);
451 }
452
453 HRESULT hr = InvokeScriptFunction(onload_handler_, url.spec());
454 }
455
456 void OnLoadFailed(int error_code, const std::string& url) {
457 HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
458 }
459
460 void OnMessageFromChromeFrame(int tab_handle, const std::string& message,
461 const std::string& origin,
462 const std::string& target) {
463 ScopedComPtr<IDispatch> message_event;
464 if (SUCCEEDED(CreateDomEvent("message", message, origin,
465 message_event.Receive()))) {
466 ScopedVariant event_var;
467 event_var.Set(static_cast<IDispatch*>(message_event));
468 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
469 }
470 }
471
[email protected]f7817822009-09-24 05:11:58472 virtual void OnTabbedOut(int tab_handle, bool reverse) {
473 DCHECK(m_bInPlaceActive);
474
475 HWND parent = ::GetParent(m_hWnd);
476 ::SetFocus(parent);
477 ScopedComPtr<IOleControlSite> control_site;
478 control_site.QueryFrom(m_spClientSite);
479 if (control_site)
480 control_site->OnFocus(FALSE);
481 }
482
483 virtual void OnOpenURL(int tab_handle, const GURL& url_to_open,
[email protected]b36a9f92009-10-19 17:34:57484 const GURL& referrer, int open_disposition) {
[email protected]b1c55638612010-03-08 16:26:11485 HostNavigate(url_to_open, referrer, open_disposition);
[email protected]f7817822009-09-24 05:11:58486 }
487
[email protected]7ae80742010-03-25 22:02:27488 // Called when Chrome has decided that a request needs to be treated as a
489 // download. The caller will be the UrlRequest worker thread.
490 // The worker thread will block while we process the request and take
491 // ownership of the request object.
492 // There's room for improvement here and also see todo below.
493 LPARAM OnDownloadRequestInHost(UINT message, WPARAM wparam, LPARAM lparam,
494 BOOL& handled) {
495 ScopedComPtr<IMoniker> moniker(reinterpret_cast<IMoniker*>(lparam));
496 DCHECK(moniker);
[email protected]0ce46402010-04-08 16:53:57497 ScopedComPtr<IBindCtx> bind_context(reinterpret_cast<IBindCtx*>(wparam));
498
[email protected]7ae80742010-03-25 22:02:27499 // TODO(tommi): It looks like we might have to switch the request object
500 // into a pass-through request object and serve up any thus far received
501 // content and headers to IE in order to prevent what can currently happen
502 // which is reissuing requests and turning POST into GET.
[email protected]3eb07da2010-02-01 19:48:36503 if (moniker) {
[email protected]3eb07da2010-02-01 19:48:36504 NavigateBrowserToMoniker(doc_site_, moniker, NULL, bind_context, NULL);
[email protected]62bb18dc12009-11-25 01:34:08505 }
[email protected]7ae80742010-03-25 22:02:27506
507 return TRUE;
[email protected]f7817822009-09-24 05:11:58508 }
509
[email protected]f7817822009-09-24 05:11:58510 virtual void OnAttachExternalTab(int tab_handle,
[email protected]b1c55638612010-03-08 16:26:11511 const IPC::AttachExternalTabParams& params) {
[email protected]c4e45b32010-07-28 21:15:15512 std::wstring wide_url = url_;
513 GURL parsed_url(WideToUTF8(wide_url));
514
515 std::string url =
516 StringPrintf("%hs:%hs?attach_external_tab&%I64u&%d&%d&%d&%d&%d",
517 parsed_url.scheme().c_str(),
518 parsed_url.host().c_str(),
519 params.cookie,
520 params.disposition,
521 params.dimensions.x(),
522 params.dimensions.y(),
523 params.dimensions.width(),
524 params.dimensions.height());
[email protected]b1c55638612010-03-08 16:26:11525 HostNavigate(GURL(url), GURL(), params.disposition);
[email protected]f7817822009-09-24 05:11:58526 }
527
[email protected]045229a72010-03-03 22:11:19528 virtual void OnHandleContextMenu(int tab_handle, HANDLE menu_handle,
529 int align_flags,
530 const IPC::ContextMenuParams& params) {
[email protected]97965e12010-04-09 00:51:10531 scoped_refptr<BasePlugin> ref(this);
[email protected]045229a72010-03-03 22:11:19532 ChromeFramePlugin<T>::OnHandleContextMenu(tab_handle, menu_handle,
533 align_flags, params);
534 }
535
[email protected]f7817822009-09-24 05:11:58536 LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
537 BOOL& handled) { // NO_LINT
538 ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
[email protected]bbfa9a12010-08-10 14:09:37539 url_fetcher_->put_notification_window(m_hWnd);
[email protected]dd4beb522010-07-13 18:18:14540 if (automation_client_.get()) {
541 automation_client_->SetParentWindow(m_hWnd);
542 } else {
543 NOTREACHED() << "No automation server";
544 return -1;
545 }
[email protected]f7817822009-09-24 05:11:58546 // Only fire the 'interactive' ready state if we aren't there already.
547 if (ready_state_ < READYSTATE_INTERACTIVE) {
548 ready_state_ = READYSTATE_INTERACTIVE;
549 FireOnChanged(DISPID_READYSTATE);
550 }
551 return 0;
552 }
553
[email protected]e9eb50c2009-10-24 16:26:46554 LRESULT OnDestroy(UINT message, WPARAM wparam, LPARAM lparam,
555 BOOL& handled) { // NO_LINT
[email protected]3eb07da2010-02-01 19:48:36556 DLOG(INFO) << __FUNCTION__;
[email protected]e9eb50c2009-10-24 16:26:46557 return 0;
558 }
559
[email protected]f7817822009-09-24 05:11:58560 // ChromeFrameDelegate override
561 virtual void OnAutomationServerReady() {
[email protected]bbfa9a12010-08-10 14:09:37562 draw_sad_tab_ = false;
[email protected]f7817822009-09-24 05:11:58563 ChromeFramePlugin<T>::OnAutomationServerReady();
564
565 ready_state_ = READYSTATE_COMPLETE;
566 FireOnChanged(DISPID_READYSTATE);
567 }
568
569 // ChromeFrameDelegate override
570 virtual void OnAutomationServerLaunchFailed(
571 AutomationLaunchResult reason, const std::string& server_version) {
[email protected]bbfa9a12010-08-10 14:09:37572 DLOG(INFO) << __FUNCTION__;
573 if (reason == AUTOMATION_SERVER_CRASHED)
574 draw_sad_tab_ = true;
575
[email protected]f7817822009-09-24 05:11:58576 ready_state_ = READYSTATE_UNINITIALIZED;
577 FireOnChanged(DISPID_READYSTATE);
578 }
579
580 // Overridden to take advantage of readystate prop changes and send those
581 // to potential listeners.
582 HRESULT FireOnChanged(DISPID dispid) {
583 if (dispid == DISPID_READYSTATE) {
584 Fire_onreadystatechanged(ready_state_);
585 }
586 return __super::FireOnChanged(dispid);
587 }
588
589 // IChromeFrame
590 // Property getter/setters for the src attribute, which contains a URL.
591 // The ChromeFrameActivex control initiates navigation to this URL
592 // when instantiated.
593 STDMETHOD(get_src)(BSTR* src) {
594 if (NULL == src) {
595 return E_POINTER;
596 }
597
598 *src = SysAllocString(url_);
599 return S_OK;
600 }
601
602 STDMETHOD(put_src)(BSTR src) {
603 if (src == NULL)
604 return E_INVALIDARG;
605
606 // Switch the src to UTF8 and try to expand to full URL
607 std::string src_utf8;
608 WideToUTF8(src, SysStringLen(src), &src_utf8);
609 std::string full_url = ResolveURL(GetDocumentUrl(), src_utf8);
[email protected]f7817822009-09-24 05:11:58610
611 // We can initiate navigation here even if ready_state is not complete.
612 // We do not have to set proxy, and AutomationClient will take care
613 // of navigation just after CreateExternalTab is done.
[email protected]b36a9f92009-10-19 17:34:57614 if (!automation_client_->InitiateNavigation(full_url,
615 GetDocumentUrl(),
616 is_privileged_)) {
[email protected]f7817822009-09-24 05:11:58617 // TODO(robertshield): Make InitiateNavigation return more useful
618 // error information.
619 return E_INVALIDARG;
620 }
621
622 // Save full URL in BSTR member
623 url_.Reset(::SysAllocString(UTF8ToWide(full_url).c_str()));
624
625 return S_OK;
626 }
627
628 STDMETHOD(get_onload)(VARIANT* onload_handler) {
629 if (NULL == onload_handler)
630 return E_INVALIDARG;
631
632 *onload_handler = onload_handler_.Copy();
633
634 return S_OK;
635 }
636
637 // Property setter for the onload attribute, which contains a
638 // javascript function to be invoked on successful navigation.
639 STDMETHOD(put_onload)(VARIANT onload_handler) {
640 if (V_VT(&onload_handler) != VT_DISPATCH) {
641 DLOG(WARNING) << "Invalid onload handler type: "
642 << onload_handler.vt
643 << " specified";
644 return E_INVALIDARG;
645 }
646
647 onload_handler_ = onload_handler;
648
649 return S_OK;
650 }
651
652 // Property getter/setters for the onloaderror attribute, which contains a
653 // javascript function to be invoked on navigation failure.
654 STDMETHOD(get_onloaderror)(VARIANT* onerror_handler) {
655 if (NULL == onerror_handler)
656 return E_INVALIDARG;
657
658 *onerror_handler = onerror_handler_.Copy();
659
660 return S_OK;
661 }
662
663 STDMETHOD(put_onloaderror)(VARIANT onerror_handler) {
664 if (V_VT(&onerror_handler) != VT_DISPATCH) {
665 DLOG(WARNING) << "Invalid onloaderror handler type: "
666 << onerror_handler.vt
667 << " specified";
668 return E_INVALIDARG;
669 }
670
671 onerror_handler_ = onerror_handler;
672
673 return S_OK;
674 }
675
676 // Property getter/setters for the onmessage attribute, which contains a
677 // javascript function to be invoked when we receive a message from the
678 // chrome frame.
679 STDMETHOD(put_onmessage)(VARIANT onmessage_handler) {
680 if (V_VT(&onmessage_handler) != VT_DISPATCH) {
681 DLOG(WARNING) << "Invalid onmessage handler type: "
682 << onmessage_handler.vt
683 << " specified";
684 return E_INVALIDARG;
685 }
686
687 onmessage_handler_ = onmessage_handler;
688
689 return S_OK;
690 }
691
692 STDMETHOD(get_onmessage)(VARIANT* onmessage_handler) {
693 if (NULL == onmessage_handler)
694 return E_INVALIDARG;
695
696 *onmessage_handler = onmessage_handler_.Copy();
697
698 return S_OK;
699 }
700
701 STDMETHOD(get_readyState)(long* ready_state) { // NOLINT
702 DLOG(INFO) << __FUNCTION__;
703 DCHECK(ready_state);
704
705 if (!ready_state)
706 return E_INVALIDARG;
707
708 *ready_state = ready_state_;
709
710 return S_OK;
711 }
712
713 // Property getter/setters for use_chrome_network flag. This flag
714 // indicates if chrome network stack is to be used for fetching
715 // network requests.
716 STDMETHOD(get_useChromeNetwork)(VARIANT_BOOL* use_chrome_network) {
717 if (!use_chrome_network)
718 return E_INVALIDARG;
719
720 *use_chrome_network =
721 automation_client_->use_chrome_network() ? VARIANT_TRUE : VARIANT_FALSE;
722 return S_OK;
723 }
724
725 STDMETHOD(put_useChromeNetwork)(VARIANT_BOOL use_chrome_network) {
726 if (!is_privileged_) {
727 DLOG(ERROR) << "Attempt to set useChromeNetwork in non-privileged mode";
728 return E_ACCESSDENIED;
729 }
730
731 automation_client_->set_use_chrome_network(
732 (VARIANT_FALSE != use_chrome_network));
733 return S_OK;
734 }
735
736 // Posts a message to the chrome frame.
737 STDMETHOD(postMessage)(BSTR message, VARIANT target) {
738 if (NULL == message) {
739 return E_INVALIDARG;
740 }
741
742 if (!automation_client_.get())
743 return E_FAIL;
744
745 std::string utf8_target;
746 if (target.vt == VT_BSTR) {
747 int len = ::SysStringLen(target.bstrVal);
748 if (len == 1 && target.bstrVal[0] == L'*') {
749 utf8_target = "*";
750 } else {
751 GURL resolved(target.bstrVal);
752 if (!resolved.is_valid()) {
753 Error(L"Unable to parse the specified target URL.");
754 return E_INVALIDARG;
755 }
756
757 utf8_target = resolved.spec();
758 }
759 } else {
760 utf8_target = "*";
761 }
762
763 std::string utf8_message;
764 WideToUTF8(message, ::SysStringLen(message), &utf8_message);
765
766 GURL url(GURL(document_url_).GetOrigin());
767 std::string origin(url.is_empty() ? "null" : url.spec());
768 if (!automation_client_->ForwardMessageFromExternalHost(utf8_message,
769 origin,
770 utf8_target)) {
771 Error(L"Failed to post message to chrome frame");
772 return E_FAIL;
773 }
774
775 return S_OK;
776 }
777
778 STDMETHOD(addEventListener)(BSTR event_type, IDispatch* listener,
779 VARIANT use_capture) {
780 EventHandlers* handlers = NULL;
781 HRESULT hr = GetHandlersForEvent(event_type, &handlers);
782 if (FAILED(hr))
783 return hr;
784
785 DCHECK(handlers != NULL);
786
787 handlers->insert(ScopedComPtr<IDispatch>(listener));
788
789 return hr;
790 }
791
792 STDMETHOD(removeEventListener)(BSTR event_type, IDispatch* listener,
793 VARIANT use_capture) {
794 EventHandlers* handlers = NULL;
795 HRESULT hr = GetHandlersForEvent(event_type, &handlers);
796 if (FAILED(hr))
797 return hr;
798
799 DCHECK(handlers != NULL);
800 std::remove(handlers->begin(), handlers->end(), listener);
801
802 return hr;
803 }
804
805 STDMETHOD(get_version)(BSTR* version) {
806 if (!automation_client_.get()) {
807 NOTREACHED();
808 return E_FAIL;
809 }
810
811 if (version == NULL) {
812 return E_INVALIDARG;
813 }
814
815 *version = SysAllocString(automation_client_->GetVersion().c_str());
816 return S_OK;
817 }
818
819 STDMETHOD(postPrivateMessage)(BSTR message, BSTR origin, BSTR target) {
820 if (NULL == message)
821 return E_INVALIDARG;
822
823 if (!is_privileged_) {
824 DLOG(ERROR) << "Attempt to postPrivateMessage in non-privileged mode";
825 return E_ACCESSDENIED;
826 }
827
828 DCHECK(automation_client_.get());
829 std::string utf8_message, utf8_origin, utf8_target;
830 WideToUTF8(message, ::SysStringLen(message), &utf8_message);
831 WideToUTF8(origin, ::SysStringLen(origin), &utf8_origin);
832 WideToUTF8(target, ::SysStringLen(target), &utf8_target);
833
834 if (!automation_client_->ForwardMessageFromExternalHost(utf8_message,
835 utf8_origin,
836 utf8_target)) {
837 Error(L"Failed to post message to chrome frame");
838 return E_FAIL;
839 }
840
841 return S_OK;
842 }
843
[email protected]00f6b772009-10-23 17:03:41844 STDMETHOD(installExtension)(BSTR crx_path) {
845 DCHECK(automation_client_.get());
846
847 if (NULL == crx_path) {
848 NOTREACHED();
849 return E_INVALIDARG;
850 }
851
852 if (!is_privileged_) {
853 DLOG(ERROR) << "Attempt to installExtension in non-privileged mode";
854 return E_ACCESSDENIED;
855 }
856
857 FilePath::StringType crx_path_str(crx_path);
858 FilePath crx_file_path(crx_path_str);
859
860 automation_client_->InstallExtension(crx_file_path, NULL);
861 return S_OK;
862 }
863
864 STDMETHOD(loadExtension)(BSTR path) {
865 DCHECK(automation_client_.get());
866
867 if (NULL == path) {
868 NOTREACHED();
869 return E_INVALIDARG;
870 }
871
872 if (!is_privileged_) {
873 DLOG(ERROR) << "Attempt to loadExtension in non-privileged mode";
874 return E_ACCESSDENIED;
875 }
876
877 FilePath::StringType path_str(path);
878 FilePath file_path(path_str);
879
880 automation_client_->LoadExpandedExtension(file_path, NULL);
881 return S_OK;
882 }
883
[email protected]a1e62d12010-03-16 02:18:43884 STDMETHOD(getEnabledExtensions)() {
885 DCHECK(automation_client_.get());
886
887 if (!is_privileged_) {
888 DLOG(ERROR) << "Attempt to getEnabledExtensions in non-privileged mode";
889 return E_ACCESSDENIED;
890 }
891
892 automation_client_->GetEnabledExtensions(NULL);
893 return S_OK;
894 }
895
[email protected]ca982ec42010-05-02 14:47:14896 STDMETHOD(registerBhoIfNeeded)() {
[email protected]e12a3b82010-05-01 00:06:00897 return E_NOTIMPL;
898 }
899
[email protected]f7817822009-09-24 05:11:58900 // Returns the vector of event handlers for a given event (e.g. "load").
901 // If the event type isn't recognized, the function fills in a descriptive
902 // error (IErrorInfo) and returns E_INVALIDARG.
903 HRESULT GetHandlersForEvent(BSTR event_type, EventHandlers** handlers) {
904 DCHECK(handlers != NULL);
905
[email protected]00f6b772009-10-23 17:03:41906 // TODO(tommi): make these if() statements data-driven.
[email protected]f7817822009-09-24 05:11:58907 HRESULT hr = S_OK;
908 const wchar_t* event_type_end = event_type + ::SysStringLen(event_type);
909 if (LowerCaseEqualsASCII(event_type, event_type_end, "message")) {
910 *handlers = &onmessage_;
911 } else if (LowerCaseEqualsASCII(event_type, event_type_end, "load")) {
912 *handlers = &onload_;
913 } else if (LowerCaseEqualsASCII(event_type, event_type_end, "loaderror")) {
914 *handlers = &onloaderror_;
915 } else if (LowerCaseEqualsASCII(event_type, event_type_end,
916 "readystatechanged")) {
917 *handlers = &onreadystatechanged_;
918 } else if (LowerCaseEqualsASCII(event_type, event_type_end,
[email protected]00f6b772009-10-23 17:03:41919 "privatemessage")) {
[email protected]f7817822009-09-24 05:11:58920 // This event handler is only available in privileged mode.
[email protected]00f6b772009-10-23 17:03:41921 if (is_privileged_) {
922 *handlers = &onprivatemessage_;
923 } else {
[email protected]f7817822009-09-24 05:11:58924 Error("Event type 'privatemessage' is privileged");
[email protected]00f6b772009-10-23 17:03:41925 hr = E_ACCESSDENIED;
[email protected]f7817822009-09-24 05:11:58926 }
[email protected]00f6b772009-10-23 17:03:41927 } else if (LowerCaseEqualsASCII(event_type, event_type_end,
928 "extensionready")) {
929 // This event handler is only available in privileged mode.
930 if (is_privileged_) {
931 *handlers = &onextensionready_;
932 } else {
933 Error("Event type 'extensionready' is privileged");
934 hr = E_ACCESSDENIED;
935 }
[email protected]f7817822009-09-24 05:11:58936 } else {
937 Error(StringPrintf("Event type '%ls' not found", event_type).c_str());
938 hr = E_INVALIDARG;
939 }
940
941 return hr;
942 }
943
[email protected]a1800e82009-11-19 00:53:23944 // Creates a new event object that supports the |data| property.
945 // Note: you should supply an empty string for |origin| unless you're
946 // creating a "message" event.
947 HRESULT CreateDomEvent(const std::string& event_type, const std::string& data,
948 const std::string& origin, IDispatch** event) {
[email protected]62bb18dc12009-11-25 01:34:08949 DCHECK(event_type.length() > 0); // NOLINT
[email protected]a1800e82009-11-19 00:53:23950 DCHECK(event != NULL);
951
952 CComObject<ComMessageEvent>* ev = NULL;
953 HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
954 if (SUCCEEDED(hr)) {
955 ev->AddRef();
956
957 ScopedComPtr<IOleContainer> container;
958 m_spClientSite->GetContainer(container.Receive());
959 if (ev->Initialize(container, data, origin, event_type)) {
960 *event = ev;
961 } else {
962 NOTREACHED() << "event->Initialize";
963 ev->Release();
964 hr = E_UNEXPECTED;
965 }
966 }
967
968 return hr;
969 }
970
971 // Helper function to execute a function on a script IDispatch interface.
972 HRESULT InvokeScriptFunction(const VARIANT& script_object,
973 const std::string& param) {
974 ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
975 return InvokeScriptFunction(script_object, script_arg.AsInput());
976 }
977
978 HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* param) {
979 return InvokeScriptFunction(script_object, param, 1);
980 }
981
982 HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* params,
983 int param_count) {
[email protected]62bb18dc12009-11-25 01:34:08984 DCHECK_GE(param_count, 0);
[email protected]a1800e82009-11-19 00:53:23985 DCHECK(params);
986
[email protected]086f367d52010-04-23 21:01:50987 if (V_VT(&script_object) != VT_DISPATCH ||
988 script_object.pdispVal == NULL) {
[email protected]a1800e82009-11-19 00:53:23989 return S_FALSE;
990 }
991
992 CComPtr<IDispatch> script(script_object.pdispVal);
993 HRESULT hr = script.InvokeN(static_cast<DISPID>(DISPID_VALUE),
994 params,
995 param_count);
996 // 0x80020101 == SCRIPT_E_REPORTED.
997 // When the script we're invoking has an error, we get this error back.
998 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
999 return hr;
1000 }
1001
[email protected]f7817822009-09-24 05:11:581002 // Gives the browser a chance to handle an accelerator that was
1003 // sent to the out of proc chromium instance.
1004 // Returns S_OK iff the accelerator was handled by the browser.
1005 HRESULT AllowFrameToTranslateAccelerator(const MSG& msg) {
[email protected]84415812010-05-19 23:12:421006 static const int kMayTranslateAcceleratorOffset = 0x5c;
[email protected]f7817822009-09-24 05:11:581007 // Although IBrowserService2 is officially deprecated, it's still alive
1008 // and well in IE7 and earlier. We have to use it here to correctly give
1009 // the browser a chance to handle keyboard shortcuts.
1010 // This happens automatically for activex components that have windows that
1011 // belong to the current thread. In that circumstance IE owns the message
1012 // loop and can walk the line of components allowing each participant the
1013 // chance to handle the keystroke and eventually falls back to
1014 // v_MayTranslateAccelerator. However in our case, the message loop is
1015 // owned by the out-of-proc chromium instance so IE doesn't have a chance to
1016 // fall back on its default behavior. Instead we give IE a chance to
1017 // handle the shortcut here.
[email protected]01dba672010-02-12 21:55:481018 MSG accel_message = msg;
1019 accel_message.hwnd = ::GetParent(m_hWnd);
[email protected]f7817822009-09-24 05:11:581020 HRESULT hr = S_FALSE;
1021 ScopedComPtr<IBrowserService2> bs2;
[email protected]3eafbfb92010-08-02 16:54:221022
1023 // For non-IE containers, we use the standard IOleInPlaceFrame contract
1024 // (which IE does not support). For IE, we try to use IBrowserService2,
1025 // but need special handling for IE8 (see below).
1026 //
1027 // We try to cache an IOleInPlaceFrame for our site. If we fail, we don't
1028 // retry, and we fall back to the IBrowserService2 and PostMessage
1029 // approaches below.
1030 if (!in_place_frame_ && !failed_to_fetch_in_place_frame_) {
1031 ScopedComPtr<IOleInPlaceUIWindow> dummy_ui_window;
1032 RECT dummy_pos_rect = {0};
1033 RECT dummy_clip_rect = {0};
1034 OLEINPLACEFRAMEINFO dummy_frame_info = {0};
1035 if (FAILED(m_spInPlaceSite->GetWindowContext(in_place_frame_.Receive(),
1036 dummy_ui_window.Receive(),
1037 &dummy_pos_rect,
1038 &dummy_clip_rect,
1039 &dummy_frame_info))) {
1040 failed_to_fetch_in_place_frame_ = true;
1041 }
1042 }
1043
1044 // The IBrowserService2 code below (second conditional) explicitly checks
1045 // for whether the IBrowserService2::v_MayTranslateAccelerator function is
1046 // valid. On IE8 there is one vtable ieframe!c_ImpostorBrowserService2Vtbl
1047 // where this function entry is NULL which leads to a crash. We don't know
1048 // under what circumstances this vtable is actually used though.
1049 if (in_place_frame_) {
1050 hr = in_place_frame_->TranslateAccelerator(&accel_message, 0);
1051 } else if (S_OK == DoQueryService(
1052 SID_STopLevelBrowser, m_spInPlaceSite,
1053 bs2.Receive()) && bs2.get() &&
1054 *(*(reinterpret_cast<void***>(bs2.get())) +
1055 kMayTranslateAcceleratorOffset)) {
[email protected]01dba672010-02-12 21:55:481056 hr = bs2->v_MayTranslateAccelerator(&accel_message);
[email protected]f7817822009-09-24 05:11:581057 } else {
1058 // IE8 doesn't support IBrowserService2 unless you enable a special,
1059 // undocumented flag with CoInternetSetFeatureEnabled and even then,
1060 // the object you get back implements only a couple of methods of
1061 // that interface... all the other entries in the vtable are NULL.
1062 // In addition, the class that implements it is called
1063 // ImpostorBrowserService2 :)
1064 // IE8 does have a new interface though, presumably called
1065 // ITabBrowserService or something that can be abbreviated to TBS.
1066 // That interface has a method, TranslateAcceleratorTBS that does
1067 // call the root MayTranslateAccelerator function, but alas the
1068 // first argument to MayTranslateAccelerator is hard coded to FALSE
1069 // which means that global accelerators are not handled and we're
1070 // out of luck.
1071 // A third thing that's notable with regards to IE8 is that
1072 // none of the *MayTranslate* functions exist in a vtable inside
1073 // ieframe.dll. I checked this by scanning for the address of
1074 // those functions inside the dll and found none, which means that
1075 // all calls to those functions are relative.
[email protected]3eafbfb92010-08-02 16:54:221076 // So, for IE8 in certain cases, and for other containers that may
1077 // support neither IOleInPlaceFrame or IBrowserService2 our approach
1078 // is very simple. Just post the message to our parent window and IE
1079 // will pick it up if it's an accelerator. We won't know for sure if
1080 // the browser handled the keystroke or not.
[email protected]01dba672010-02-12 21:55:481081 ::PostMessage(accel_message.hwnd, accel_message.message,
1082 accel_message.wParam, accel_message.lParam);
[email protected]f7817822009-09-24 05:11:581083 }
1084
1085 return hr;
1086 }
1087
[email protected]2b8fd322009-10-02 00:00:591088 virtual void OnAcceleratorPressed(int tab_handle, const MSG& accel_message) {
1089 DCHECK(m_spInPlaceSite != NULL);
1090 // Allow our host a chance to handle the accelerator.
1091 // This catches things like Ctrl+F, Ctrl+O etc, but not browser
1092 // accelerators such as F11, Ctrl+T etc.
1093 // (see AllowFrameToTranslateAccelerator for those).
1094 HRESULT hr = TranslateAccelerator(const_cast<MSG*>(&accel_message));
1095 if (hr != S_OK)
1096 hr = AllowFrameToTranslateAccelerator(accel_message);
1097
1098 DLOG(INFO) << __FUNCTION__ << " browser response: "
1099 << StringPrintf("0x%08x", hr);
1100
1101 if (hr != S_OK) {
1102 // The WM_SYSCHAR message is not processed by the IOleControlSite
1103 // implementation and the IBrowserService2::v_MayTranslateAccelerator
1104 // implementation. We need to understand this better. That is for
1105 // another day. For now we just post the WM_SYSCHAR message back to our
1106 // parent which forwards it off to the frame. This should not cause major
1107 // grief for Chrome as it does not need to handle WM_SYSCHAR accelerators
1108 // when running in ChromeFrame mode.
1109 // TODO(iyengar)
1110 // Understand and fix WM_SYSCHAR handling
1111 // We should probably unify the accelerator handling for the active
1112 // document and the activex.
1113 if (accel_message.message == WM_SYSCHAR) {
1114 ::PostMessage(GetParent(), WM_SYSCHAR, accel_message.wParam,
1115 accel_message.lParam);
1116 return;
1117 }
1118 }
1119
1120 // Last chance to handle the keystroke is to pass it to chromium.
1121 // We do this last partially because there's no way for us to tell if
1122 // chromium actually handled the keystroke, but also since the browser
1123 // should have first dibs anyway.
1124 if (hr != S_OK && automation_client_.get()) {
1125 TabProxy* tab = automation_client_->tab();
1126 if (tab) {
1127 tab->ProcessUnhandledAccelerator(accel_message);
1128 }
1129 }
1130 }
1131
[email protected]f7817822009-09-24 05:11:581132 protected:
[email protected]b1c55638612010-03-08 16:26:111133 void HostNavigate(const GURL& url_to_open,
1134 const GURL& referrer, int open_disposition) {
1135 ScopedComPtr<IWebBrowser2> web_browser2;
1136 DoQueryService(SID_SWebBrowserApp, m_spClientSite, web_browser2.Receive());
[email protected]8e33c8f5282010-04-02 05:59:551137 if (!web_browser2) {
1138 NOTREACHED() << "Failed to retrieve IWebBrowser2 interface";
1139 return;
1140 }
[email protected]b1c55638612010-03-08 16:26:111141 ScopedVariant url;
1142 // Check to see if the URL uses a "view-source:" prefix, if so, open it
1143 // using chrome frame full tab mode by using 'cf:' protocol handler.
1144 // Also change the disposition to NEW_WINDOW since IE6 doesn't have tabs.
1145 if (url_to_open.has_scheme() &&
1146 (url_to_open.SchemeIs(chrome::kViewSourceScheme) ||
1147 url_to_open.SchemeIs(chrome::kAboutScheme))) {
1148 std::wstring chrome_url;
1149 chrome_url.append(kChromeProtocolPrefix);
1150 chrome_url.append(UTF8ToWide(url_to_open.spec()));
1151 url.Set(chrome_url.c_str());
1152 open_disposition = NEW_WINDOW;
1153 } else {
1154 url.Set(UTF8ToWide(url_to_open.spec()).c_str());
1155 }
1156
1157 VARIANT flags = { VT_I4 };
1158 V_I4(&flags) = 0;
1159
1160 IEVersion ie_version = GetIEVersion();
1161 DCHECK(ie_version != NON_IE && ie_version != IE_UNSUPPORTED);
1162 // Since IE6 doesn't support tabs, so we just use window instead.
1163 if (ie_version == IE_6) {
1164 if (open_disposition == NEW_FOREGROUND_TAB ||
1165 open_disposition == NEW_BACKGROUND_TAB ||
1166 open_disposition == NEW_WINDOW ||
1167 open_disposition == NEW_POPUP) {
1168 V_I4(&flags) = navOpenInNewWindow;
1169 } else if (open_disposition != CURRENT_TAB) {
1170 NOTREACHED() << "Unsupported open disposition in IE6";
1171 }
1172 } else {
1173 switch (open_disposition) {
1174 case NEW_FOREGROUND_TAB:
1175 V_I4(&flags) = navOpenInNewTab;
1176 break;
1177 case NEW_BACKGROUND_TAB:
1178 V_I4(&flags) = navOpenInBackgroundTab;
1179 break;
1180 case NEW_WINDOW:
1181 case NEW_POPUP:
1182 V_I4(&flags) = navOpenInNewWindow;
1183 break;
1184 default:
1185 break;
1186 }
1187 }
1188
1189 // TODO(sanjeevr): The navOpenInNewWindow flag causes IE to open this
1190 // in a new window ONLY if the user has specified
1191 // "Always open popups in a new window". Otherwise it opens in a new tab.
1192 // We need to investigate more and see if we can force IE to display the
1193 // link in a new window. MSHTML uses the below code to force an open in a
1194 // new window. But this logic also fails for us. Perhaps this flag is not
1195 // honoured if the ActiveDoc is not MSHTML.
1196 // Even the HLNF_DISABLEWINDOWRESTRICTIONS flag did not work.
1197 // Start of MSHTML-like logic.
1198 // CComQIPtr<ITargetFramePriv2> target_frame = web_browser2;
1199 // if (target_frame) {
1200 // CComPtr<IUri> uri;
1201 // CreateUri(UTF8ToWide(open_url_command->url_.spec()).c_str(),
1202 // Uri_CREATE_IE_SETTINGS, 0, &uri);
1203 // CComPtr<IBindCtx> bind_ctx;
1204 // CreateBindCtx(0, &bind_ctx);
1205 // target_frame->AggregatedNavigation2(
1206 // HLNF_TRUSTFIRSTDOWNLOAD|HLNF_OPENINNEWWINDOW, bind_ctx, NULL,
1207 // L"No_Name", uri, L"");
1208 // }
1209 // End of MSHTML-like logic
1210 VARIANT empty = ScopedVariant::kEmptyVariant;
1211 ScopedVariant http_headers;
1212
1213 if (referrer.is_valid()) {
1214 std::wstring referrer_header = L"Referer: ";
1215 referrer_header += UTF8ToWide(referrer.spec());
1216 referrer_header += L"\r\n\r\n";
1217 http_headers.Set(referrer_header.c_str());
1218 }
1219
1220 web_browser2->Navigate2(url.AsInput(), &flags, &empty, &empty,
1221 http_headers.AsInput());
[email protected]b1c55638612010-03-08 16:26:111222 }
1223
[email protected]f7817822009-09-24 05:11:581224 ScopedBstr url_;
1225 ScopedComPtr<IOleDocumentSite> doc_site_;
1226
[email protected]3eafbfb92010-08-02 16:54:221227 // If false, we tried but failed to fetch an IOleInPlaceFrame from our host.
1228 // Cached here so we don't try to fetch it every time if we keep failing.
1229 bool failed_to_fetch_in_place_frame_;
[email protected]bbfa9a12010-08-10 14:09:371230 bool draw_sad_tab_;
1231
[email protected]3eafbfb92010-08-02 16:54:221232 ScopedComPtr<IOleInPlaceFrame> in_place_frame_;
1233
[email protected]f7817822009-09-24 05:11:581234 // For more information on the ready_state_ property see:
1235 // http://msdn.microsoft.com/en-us/library/aa768179(VS.85).aspx#
1236 READYSTATE ready_state_;
1237
1238 // The following members contain IDispatch interfaces representing the
1239 // onload/onerror/onmessage handlers on the page.
1240 ScopedVariant onload_handler_;
1241 ScopedVariant onerror_handler_;
1242 ScopedVariant onmessage_handler_;
1243
1244 EventHandlers onmessage_;
1245 EventHandlers onloaderror_;
1246 EventHandlers onload_;
1247 EventHandlers onreadystatechanged_;
1248 EventHandlers onprivatemessage_;
[email protected]00f6b772009-10-23 17:03:411249 EventHandlers onextensionready_;
[email protected]f7817822009-09-24 05:11:581250
[email protected]3eb07da2010-02-01 19:48:361251 // Handle network requests when host network stack is used. Passed to the
1252 // automation client on initialization.
[email protected]bbfa9a12010-08-10 14:09:371253 scoped_ptr<UrlmonUrlRequestManager> url_fetcher_;
[email protected]f7817822009-09-24 05:11:581254};
1255
1256#endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_