blob: b80caf1ef44c116bc94380c893ab6a5c9eb4adf8 [file] [log] [blame]
[email protected]6e58a952011-01-12 19:28:501// Copyright (c) 2011 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
[email protected]835d7c82010-10-14 04:38:3819#include "base/metrics/histogram.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]252cad62010-08-18 18:33:5722#include "base/utf_string_conversions.h"
[email protected]965722ff2010-10-20 15:50:3023#include "base/win/scoped_bstr.h"
24#include "base/win/scoped_comptr.h"
25#include "base/win/scoped_variant.h"
[email protected]f7817822009-09-24 05:11:5826#include "grit/chrome_frame_resources.h"
[email protected]bc73b4e52010-03-26 04:16:2027#include "chrome/common/url_constants.h"
[email protected]f7817822009-09-24 05:11:5828#include "chrome_frame/chrome_frame_plugin.h"
[email protected]a1800e82009-11-19 00:53:2329#include "chrome_frame/com_message_event.h"
[email protected]f7817822009-09-24 05:11:5830#include "chrome_frame/com_type_info_holder.h"
[email protected]3c6f8e12010-03-24 21:58:2131#include "chrome_frame/simple_resource_loader.h"
[email protected]f7817822009-09-24 05:11:5832#include "chrome_frame/urlmon_url_request.h"
[email protected]7ae80742010-03-25 22:02:2733#include "chrome_frame/urlmon_url_request_private.h"
[email protected]bc73b4e52010-03-26 04:16:2034#include "chrome_frame/utils.h"
[email protected]35f13ab2009-12-16 23:59:1735#include "grit/generated_resources.h"
[email protected]aeb9efc2010-01-08 05:55:5036#include "net/base/cookie_monster.h"
[email protected]f7817822009-09-24 05:11:5837
38// Include without path to make GYP build see it.
39#include "chrome_tab.h" // NOLINT
40
41// Connection point class to support firing IChromeFrameEvents (dispinterface).
42template<class T>
43class ATL_NO_VTABLE ProxyDIChromeFrameEvents
44 : public IConnectionPointImpl<T, &DIID_DIChromeFrameEvents> {
45 public:
46 void FireMethodWithParams(ChromeFrameEventDispId dispid,
47 const VARIANT* params, size_t num_params) {
48 T* me = static_cast<T*>(this);
[email protected]efd4dfc22010-03-26 20:14:4049 // We need to copy the whole vector and AddRef the sinks in case
50 // some would get disconnected as we fire methods. Note that this is not
51 // a threading issue, but a re-entrance issue, because the connection
52 // can be affected by the implementation of the sinks receiving the event.
53 me->Lock();
[email protected]965722ff2010-10-20 15:50:3054 std::vector< base::win::ScopedComPtr<IUnknown> > sink_array(
55 m_vec.GetSize());
[email protected]efd4dfc22010-03-26 20:14:4056 for (int connection = 0; connection < m_vec.GetSize(); ++connection)
57 sink_array[connection] = m_vec.GetAt(connection);
58 me->Unlock();
[email protected]f7817822009-09-24 05:11:5859
[email protected]efd4dfc22010-03-26 20:14:4060 for (size_t sink = 0; sink < sink_array.size(); ++sink) {
61 DIChromeFrameEvents* events =
62 static_cast<DIChromeFrameEvents*>(sink_array[sink].get());
[email protected]f7817822009-09-24 05:11:5863 if (events) {
64 DISPPARAMS disp_params = {
65 const_cast<VARIANT*>(params),
66 NULL,
67 num_params,
68 0};
69 HRESULT hr = events->Invoke(static_cast<DISPID>(dispid),
70 DIID_DIChromeFrameEvents,
71 LOCALE_USER_DEFAULT, DISPATCH_METHOD,
72 &disp_params, NULL, NULL, NULL);
73 DLOG_IF(ERROR, FAILED(hr)) << "invoke(" << dispid << ") failed" <<
[email protected]d3451d832010-10-01 11:17:3774 base::StringPrintf("0x%08X", hr);
[email protected]f7817822009-09-24 05:11:5875 }
76 }
77 }
78
79 void FireMethodWithParam(ChromeFrameEventDispId dispid,
80 const VARIANT& param) {
81 FireMethodWithParams(dispid, &param, 1);
82 }
83
84 void Fire_onload(IDispatch* event) {
85 VARIANT var = { VT_DISPATCH };
86 var.pdispVal = event;
87 FireMethodWithParam(CF_EVENT_DISPID_ONLOAD, var);
88 }
89
90 void Fire_onloaderror(IDispatch* event) {
91 VARIANT var = { VT_DISPATCH };
92 var.pdispVal = event;
93 FireMethodWithParam(CF_EVENT_DISPID_ONLOADERROR, var);
94 }
95
96 void Fire_onmessage(IDispatch* event) {
97 VARIANT var = { VT_DISPATCH };
98 var.pdispVal = event;
99 FireMethodWithParam(CF_EVENT_DISPID_ONMESSAGE, var);
100 }
101
[email protected]62bb18dc12009-11-25 01:34:08102 void Fire_onreadystatechanged(long readystate) { // NOLINT
[email protected]f7817822009-09-24 05:11:58103 VARIANT var = { VT_I4 };
104 var.lVal = readystate;
105 FireMethodWithParam(CF_EVENT_DISPID_ONREADYSTATECHANGED, var);
106 }
107
108 void Fire_onprivatemessage(IDispatch* event, BSTR target) {
109 // Arguments in reverse order to the function declaration, because
110 // that's what DISPPARAMS requires.
111 VARIANT args[2] = { { VT_BSTR, }, {VT_DISPATCH, } };
112 args[0].bstrVal = target;
113 args[1].pdispVal = event;
114
115 FireMethodWithParams(CF_EVENT_DISPID_ONPRIVATEMESSAGE,
116 args,
117 arraysize(args));
118 }
[email protected]00f6b772009-10-23 17:03:41119
[email protected]62bb18dc12009-11-25 01:34:08120 void Fire_onextensionready(BSTR path, long response) { // NOLINT
[email protected]00f6b772009-10-23 17:03:41121 // Arguments in reverse order to the function declaration, because
122 // that's what DISPPARAMS requires.
123 VARIANT args[2] = { { VT_I4, }, { VT_BSTR, } };
124 args[0].lVal = response;
125 args[1].bstrVal = path;
126
127 FireMethodWithParams(CF_EVENT_DISPID_ONEXTENSIONREADY,
128 args,
129 arraysize(args));
130 }
[email protected]a1e62d12010-03-16 02:18:43131
[email protected]efd4dfc22010-03-26 20:14:40132 void Fire_ongetenabledextensionscomplete(SAFEARRAY* extension_dirs) {
[email protected]a1e62d12010-03-16 02:18:43133 VARIANT args[1] = { { VT_ARRAY | VT_BSTR } };
134 args[0].parray = extension_dirs;
135
136 FireMethodWithParams(CF_EVENT_DISPID_ONGETENABLEDEXTENSIONSCOMPLETE,
137 args, arraysize(args));
138 }
[email protected]efd4dfc22010-03-26 20:14:40139
140 void Fire_onchannelerror() { // NOLINT
141 FireMethodWithParams(CF_EVENT_DISPID_ONCHANNELERROR, NULL, 0);
142 }
[email protected]2f1793ea2010-10-27 17:32:51143
144 void Fire_onclose() { // NOLINT
145 FireMethodWithParams(CF_EVENT_DISPID_ONCLOSE, NULL, 0);
146 }
[email protected]f7817822009-09-24 05:11:58147};
148
149extern bool g_first_launch_by_process_;
150
[email protected]a22f7e02011-02-09 07:15:35151namespace chrome_frame {
152// Implemented outside this file so that the header doesn't include
153// automation_messages.h.
154std::string ActiveXCreateUrl(const GURL& parsed_url,
155 const AttachExternalTabParams& params);
156int GetDisposition(const AttachExternalTabParams& params);
157void GetMiniContextMenuData(UINT cmd,
158 const MiniContextMenuParams& params,
159 GURL* referrer,
160 GURL* url);
161} // namespace chrome_frame
162
[email protected]f7817822009-09-24 05:11:58163// Common implementation for ActiveX and Active Document
164template <class T, const CLSID& class_id>
[email protected]62bb18dc12009-11-25 01:34:08165class ATL_NO_VTABLE ChromeFrameActivexBase : // NOLINT
[email protected]b0febbf2009-11-12 17:49:35166 public CComObjectRootEx<CComMultiThreadModel>,
[email protected]f7817822009-09-24 05:11:58167 public IOleControlImpl<T>,
168 public IOleObjectImpl<T>,
169 public IOleInPlaceActiveObjectImpl<T>,
170 public IViewObjectExImpl<T>,
171 public IOleInPlaceObjectWindowlessImpl<T>,
172 public ISupportErrorInfo,
173 public IQuickActivateImpl<T>,
174 public com_util::IProvideClassInfo2Impl<class_id,
175 DIID_DIChromeFrameEvents>,
176 public com_util::IDispatchImpl<IChromeFrame>,
[email protected]751bf4b2010-11-05 22:06:31177 public IChromeFrameInternal,
[email protected]f7817822009-09-24 05:11:58178 public IConnectionPointContainerImpl<T>,
179 public ProxyDIChromeFrameEvents<T>,
180 public IPropertyNotifySinkCP<T>,
181 public CComCoClass<T, &class_id>,
182 public CComControl<T>,
[email protected]0753db592010-12-15 14:45:05183 public ChromeFramePlugin<T> {
[email protected]f7817822009-09-24 05:11:58184 protected:
[email protected]965722ff2010-10-20 15:50:30185 typedef std::set<base::win::ScopedComPtr<IDispatch> > EventHandlers;
[email protected]97965e12010-04-09 00:51:10186 typedef ChromeFrameActivexBase<T, class_id> BasePlugin;
[email protected]f7817822009-09-24 05:11:58187
188 public:
189 ChromeFrameActivexBase()
[email protected]3eafbfb92010-08-02 16:54:22190 : ready_state_(READYSTATE_UNINITIALIZED),
[email protected]bbfa9a12010-08-10 14:09:37191 url_fetcher_(new UrlmonUrlRequestManager()),
192 failed_to_fetch_in_place_frame_(false),
[email protected]6e58a952011-01-12 19:28:50193 draw_sad_tab_(false) {
[email protected]f7817822009-09-24 05:11:58194 m_bWindowOnly = TRUE;
[email protected]bbfa9a12010-08-10 14:09:37195 url_fetcher_->set_container(static_cast<IDispatch*>(this));
[email protected]f7817822009-09-24 05:11:58196 }
197
198 ~ChromeFrameActivexBase() {
[email protected]bbfa9a12010-08-10 14:09:37199 url_fetcher_->set_container(NULL);
[email protected]f7817822009-09-24 05:11:58200 }
201
202DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | OLEMISC_CANTLINKINSIDE |
203 OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE |
204 OLEMISC_SETCLIENTSITEFIRST)
205
206DECLARE_NOT_AGGREGATABLE(T)
207
208BEGIN_COM_MAP(ChromeFrameActivexBase)
209 COM_INTERFACE_ENTRY(IChromeFrame)
210 COM_INTERFACE_ENTRY(IDispatch)
[email protected]751bf4b2010-11-05 22:06:31211 COM_INTERFACE_ENTRY(IChromeFrameInternal)
[email protected]f7817822009-09-24 05:11:58212 COM_INTERFACE_ENTRY(IViewObjectEx)
213 COM_INTERFACE_ENTRY(IViewObject2)
214 COM_INTERFACE_ENTRY(IViewObject)
215 COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
216 COM_INTERFACE_ENTRY(IOleInPlaceObject)
217 COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
218 COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
219 COM_INTERFACE_ENTRY(IOleControl)
220 COM_INTERFACE_ENTRY(IOleObject)
221 COM_INTERFACE_ENTRY(ISupportErrorInfo)
222 COM_INTERFACE_ENTRY(IQuickActivate)
223 COM_INTERFACE_ENTRY(IProvideClassInfo)
224 COM_INTERFACE_ENTRY(IProvideClassInfo2)
[email protected]bbfa9a12010-08-10 14:09:37225 COM_INTERFACE_ENTRY(IConnectionPointContainer)
[email protected]f7817822009-09-24 05:11:58226 COM_INTERFACE_ENTRY_FUNC_BLIND(0, InterfaceNotSupported)
227END_COM_MAP()
228
229BEGIN_CONNECTION_POINT_MAP(T)
230 CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
231 CONNECTION_POINT_ENTRY(DIID_DIChromeFrameEvents)
232END_CONNECTION_POINT_MAP()
233
234BEGIN_MSG_MAP(ChromeFrameActivexBase)
235 MESSAGE_HANDLER(WM_CREATE, OnCreate)
[email protected]7ae80742010-03-25 22:02:27236 MESSAGE_HANDLER(WM_DOWNLOAD_IN_HOST, OnDownloadRequestInHost)
[email protected]e9eb50c2009-10-24 16:26:46237 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
[email protected]f7817822009-09-24 05:11:58238 CHAIN_MSG_MAP(ChromeFramePlugin<T>)
239 CHAIN_MSG_MAP(CComControl<T>)
240 DEFAULT_REFLECTION_HANDLER()
241END_MSG_MAP()
242
243 // IViewObjectEx
244 DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)
245
[email protected]48e6bb62009-09-30 20:32:46246 inline HRESULT IViewObject_Draw(DWORD draw_aspect, LONG index,
247 void* aspect_info, DVTARGETDEVICE* ptd, HDC info_dc, HDC dc,
248 LPCRECTL bounds, LPCRECTL win_bounds) {
249 // ATL ASSERTs if dwDrawAspect is DVASPECT_DOCPRINT, so we cheat.
250 DWORD aspect = draw_aspect;
251 if (aspect == DVASPECT_DOCPRINT)
252 aspect = DVASPECT_CONTENT;
253
254 return CComControl<T>::IViewObject_Draw(aspect, index, aspect_info, ptd,
255 info_dc, dc, bounds, win_bounds);
256 }
[email protected]f7817822009-09-24 05:11:58257
258 DECLARE_PROTECT_FINAL_CONSTRUCT()
259
[email protected]3eb8a70492010-12-03 21:32:19260 void SetResourceModule() {
[email protected]8e8bb6d2010-12-13 08:18:55261 SimpleResourceLoader* loader_instance = SimpleResourceLoader::GetInstance();
[email protected]3c6f8e12010-03-24 21:58:21262 DCHECK(loader_instance);
[email protected]6ae3d492010-10-20 14:01:21263 HMODULE res_dll = loader_instance->GetResourceModuleHandle();
[email protected]3eb8a70492010-12-03 21:32:19264 _AtlBaseModule.SetResourceInstance(res_dll);
[email protected]3c6f8e12010-03-24 21:58:21265 }
266
[email protected]f7817822009-09-24 05:11:58267 HRESULT FinalConstruct() {
[email protected]3c6f8e12010-03-24 21:58:21268 SetResourceModule();
269
[email protected]f7817822009-09-24 05:11:58270 if (!Initialize())
271 return E_OUTOFMEMORY;
272
273 // Set to true if this is the first launch by this process.
274 // Used to perform one time tasks.
275 if (g_first_launch_by_process_) {
276 g_first_launch_by_process_ = false;
[email protected]333590002010-03-05 18:49:21277 THREAD_SAFE_UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.IEVersion",
278 GetIEVersion(),
279 IE_INVALID,
[email protected]d8e13512010-09-22 17:02:58280 IE_9,
281 IE_9 + 1);
[email protected]f7817822009-09-24 05:11:58282 }
[email protected]8103c7f2010-09-08 22:36:09283
[email protected]f7817822009-09-24 05:11:58284 return S_OK;
285 }
286
287 void FinalRelease() {
[email protected]89f19542010-01-05 21:55:11288 Uninitialize();
[email protected]f7817822009-09-24 05:11:58289 }
290
[email protected]bbfa9a12010-08-10 14:09:37291 void ResetUrlRequestManager() {
292 url_fetcher_.reset(new UrlmonUrlRequestManager());
293 }
294
[email protected]f7817822009-09-24 05:11:58295 static HRESULT WINAPI InterfaceNotSupported(void* pv, REFIID riid, void** ppv,
296 DWORD dw) {
297#ifndef NDEBUG
298 wchar_t buffer[64] = {0};
299 ::StringFromGUID2(riid, buffer, arraysize(buffer));
[email protected]2b9a9f162010-10-19 20:30:45300 DVLOG(1) << "E_NOINTERFACE: " << buffer;
[email protected]f7817822009-09-24 05:11:58301#endif
302 return E_NOINTERFACE;
303 }
304
305 // ISupportsErrorInfo
306 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) {
307 static const IID* interfaces[] = {
308 &IID_IChromeFrame,
309 &IID_IDispatch
310 };
311
312 for (int i = 0; i < arraysize(interfaces); ++i) {
313 if (InlineIsEqualGUID(*interfaces[i], riid))
314 return S_OK;
315 }
316 return S_FALSE;
317 }
318
319 // Called to draw our control when chrome hasn't been initialized.
[email protected]62bb18dc12009-11-25 01:34:08320 virtual HRESULT OnDraw(ATL_DRAWINFO& draw_info) { // NOLINT
[email protected]f7817822009-09-24 05:11:58321 if (NULL == draw_info.prcBounds) {
322 NOTREACHED();
323 return E_FAIL;
324 }
[email protected]bbfa9a12010-08-10 14:09:37325
326 if (draw_sad_tab_) {
327 // TODO(tommi): Draw a proper sad tab.
328 RECT rc = {0};
329 if (draw_info.prcBounds) {
330 rc.top = draw_info.prcBounds->top;
331 rc.bottom = draw_info.prcBounds->bottom;
332 rc.left = draw_info.prcBounds->left;
333 rc.right = draw_info.prcBounds->right;
334 } else {
335 GetClientRect(&rc);
336 }
337 ::DrawTextA(draw_info.hdcDraw, ":-(", -1, &rc,
338 DT_CENTER | DT_VCENTER | DT_SINGLELINE);
339 } else {
340 // Don't draw anything.
341 }
[email protected]f7817822009-09-24 05:11:58342 return S_OK;
343 }
344
[email protected]f7817822009-09-24 05:11:58345 // Used to setup the document_url_ member needed for completing navigation.
346 // Create external tab (possibly in incognito mode).
347 HRESULT IOleObject_SetClientSite(IOleClientSite* client_site) {
348 // If we currently have a document site pointer, release it.
349 doc_site_.Release();
350 if (client_site) {
351 doc_site_.QueryFrom(client_site);
352 }
353
[email protected]3eafbfb92010-08-02 16:54:22354 if (client_site == NULL) {
355 in_place_frame_.Release();
356 }
357
[email protected]f7817822009-09-24 05:11:58358 return CComControlBase::IOleObject_SetClientSite(client_site);
359 }
360
[email protected]f5494d42010-12-23 22:15:34361 bool HandleContextMenuCommand(UINT cmd, const MiniContextMenuParams& params) {
[email protected]f7817822009-09-24 05:11:58362 if (cmd == IDC_ABOUT_CHROME_FRAME) {
363 int tab_handle = automation_client_->tab()->handle();
[email protected]b1c55638612010-03-08 16:26:11364 HostNavigate(GURL("about:version"), GURL(), NEW_WINDOW);
[email protected]f7817822009-09-24 05:11:58365 return true;
[email protected]35f13ab2009-12-16 23:59:17366 } else {
367 switch (cmd) {
368 case IDS_CONTENT_CONTEXT_SAVEAUDIOAS:
369 case IDS_CONTENT_CONTEXT_SAVEVIDEOAS:
370 case IDS_CONTENT_CONTEXT_SAVEIMAGEAS:
371 case IDS_CONTENT_CONTEXT_SAVELINKAS: {
[email protected]a22f7e02011-02-09 07:15:35372 GURL referrer, url;
373 chrome_frame::GetMiniContextMenuData(cmd, params, &referrer, &url);
[email protected]35f13ab2009-12-16 23:59:17374 DoFileDownloadInIE(UTF8ToWide(url.spec()).c_str());
375 return true;
376 }
377 }
[email protected]f7817822009-09-24 05:11:58378 }
379
380 return false;
381 }
382
[email protected]10bf1a72009-10-01 16:00:21383 // Should connections initiated by this class try to block
384 // responses served with the X-Frame-Options header?
385 // ActiveX controls genereally will want to do this,
386 // returning true, while true top-level documents
387 // (ActiveDocument servers) will not. Your specialization
388 // of this template should implement this method based on how
389 // it "feels" from a security perspective. If it's hosted in another
[email protected]f7817822009-09-24 05:11:58390 // scriptable document, return true, else false.
[email protected]2ce57c782009-11-17 18:15:40391 //
392 // The base implementation returns true unless we are in privileged
393 // mode, in which case we always trust our container so we return false.
[email protected]5778de6e2009-10-24 01:29:20394 bool is_frame_busting_enabled() const {
[email protected]0753db592010-12-15 14:45:05395 return !is_privileged();
[email protected]f7817822009-09-24 05:11:58396 }
397
[email protected]5778de6e2009-10-24 01:29:20398 // Needed to support PostTask.
399 static bool ImplementsThreadSafeReferenceCounting() {
400 return true;
401 }
402
[email protected]f7817822009-09-24 05:11:58403 protected:
[email protected]bc73b4e52010-03-26 04:16:20404 virtual void GetProfilePath(const std::wstring& profile_name,
405 FilePath* profile_path) {
406 bool is_IE = (lstrcmpi(profile_name.c_str(), kIexploreProfileName) == 0) ||
407 (lstrcmpi(profile_name.c_str(), kRundllProfileName) == 0);
408 // Browsers without IDeleteBrowsingHistory in non-priv mode
409 // have their profiles moved into "Temporary Internet Files".
[email protected]d9ca776c2011-01-31 21:44:26410 if (is_IE && GetIEVersion() < IE_8) {
[email protected]bc73b4e52010-03-26 04:16:20411 *profile_path = GetIETemporaryFilesFolder();
412 *profile_path = profile_path->Append(L"Google Chrome Frame");
413 } else {
414 ChromeFramePlugin::GetProfilePath(profile_name, profile_path);
415 }
[email protected]2b9a9f162010-10-19 20:30:45416 DVLOG(1) << __FUNCTION__ << ": " << profile_path->value();
[email protected]bc73b4e52010-03-26 04:16:20417 }
418
[email protected]f5494d42010-12-23 22:15:34419 void OnLoad(const GURL& url) {
[email protected]a1800e82009-11-19 00:53:23420 if (ready_state_ < READYSTATE_COMPLETE) {
421 ready_state_ = READYSTATE_COMPLETE;
422 FireOnChanged(DISPID_READYSTATE);
423 }
424
425 HRESULT hr = InvokeScriptFunction(onload_handler_, url.spec());
426 }
427
428 void OnLoadFailed(int error_code, const std::string& url) {
429 HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
430 }
431
[email protected]f5494d42010-12-23 22:15:34432 void OnMessageFromChromeFrame(const std::string& message,
[email protected]a1800e82009-11-19 00:53:23433 const std::string& origin,
434 const std::string& target) {
[email protected]965722ff2010-10-20 15:50:30435 base::win::ScopedComPtr<IDispatch> message_event;
[email protected]a1800e82009-11-19 00:53:23436 if (SUCCEEDED(CreateDomEvent("message", message, origin,
437 message_event.Receive()))) {
[email protected]965722ff2010-10-20 15:50:30438 base::win::ScopedVariant event_var;
[email protected]a1800e82009-11-19 00:53:23439 event_var.Set(static_cast<IDispatch*>(message_event));
440 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
441 }
442 }
443
[email protected]f5494d42010-12-23 22:15:34444 virtual void OnTabbedOut(bool reverse) {
[email protected]f7817822009-09-24 05:11:58445 DCHECK(m_bInPlaceActive);
446
447 HWND parent = ::GetParent(m_hWnd);
448 ::SetFocus(parent);
[email protected]965722ff2010-10-20 15:50:30449 base::win::ScopedComPtr<IOleControlSite> control_site;
[email protected]f7817822009-09-24 05:11:58450 control_site.QueryFrom(m_spClientSite);
451 if (control_site)
452 control_site->OnFocus(FALSE);
453 }
454
[email protected]f5494d42010-12-23 22:15:34455 virtual void OnOpenURL(const GURL& url_to_open,
[email protected]b36a9f92009-10-19 17:34:57456 const GURL& referrer, int open_disposition) {
[email protected]b1c55638612010-03-08 16:26:11457 HostNavigate(url_to_open, referrer, open_disposition);
[email protected]f7817822009-09-24 05:11:58458 }
459
[email protected]7ae80742010-03-25 22:02:27460 // Called when Chrome has decided that a request needs to be treated as a
461 // download. The caller will be the UrlRequest worker thread.
462 // The worker thread will block while we process the request and take
463 // ownership of the request object.
464 // There's room for improvement here and also see todo below.
465 LPARAM OnDownloadRequestInHost(UINT message, WPARAM wparam, LPARAM lparam,
466 BOOL& handled) {
[email protected]f4fbae682011-02-28 22:18:33467 DownloadInHostParams* download_params =
468 reinterpret_cast<DownloadInHostParams*>(wparam);
469 DCHECK(download_params);
[email protected]7ae80742010-03-25 22:02:27470 // TODO(tommi): It looks like we might have to switch the request object
471 // into a pass-through request object and serve up any thus far received
472 // content and headers to IE in order to prevent what can currently happen
473 // which is reissuing requests and turning POST into GET.
[email protected]f4fbae682011-02-28 22:18:33474 if (download_params->moniker) {
475 NavigateBrowserToMoniker(
476 doc_site_, download_params->moniker,
477 UTF8ToWide(download_params->request_headers).c_str(),
478 download_params->bind_ctx, NULL, download_params->post_data);
[email protected]62bb18dc12009-11-25 01:34:08479 }
[email protected]7ae80742010-03-25 22:02:27480 return TRUE;
[email protected]f7817822009-09-24 05:11:58481 }
482
[email protected]f5494d42010-12-23 22:15:34483 virtual void OnAttachExternalTab(const AttachExternalTabParams& params) {
[email protected]c4e45b32010-07-28 21:15:15484 std::wstring wide_url = url_;
485 GURL parsed_url(WideToUTF8(wide_url));
486
[email protected]e1081d92010-09-10 20:29:11487 // If Chrome-Frame is presently navigated to an extension page, navigating
488 // the host to a url with scheme chrome-extension will fail, so we
489 // point the host at http:local_host. Note that this is NOT the URL
490 // to which the host is directed. It is only used as a temporary message
491 // passing mechanism between this CF instance, and the BHO that will
492 // be constructed in the new IE tab.
493 if (parsed_url.SchemeIs("chrome-extension") &&
[email protected]0753db592010-12-15 14:45:05494 is_privileged()) {
[email protected]5b811ad2010-11-24 15:24:05495 const char kScheme[] = "http";
496 const char kHost[] = "local_host";
497
498 GURL::Replacements r;
499 r.SetScheme(kScheme, url_parse::Component(0, sizeof(kScheme) -1));
500 r.SetHost(kHost, url_parse::Component(0, sizeof(kHost) - 1));
501 parsed_url = parsed_url.ReplaceComponents(r);
[email protected]e1081d92010-09-10 20:29:11502 }
503
[email protected]a22f7e02011-02-09 07:15:35504 std::string url = chrome_frame::ActiveXCreateUrl(parsed_url, params);
505 HostNavigate(GURL(url), GURL(), chrome_frame::GetDisposition(params));
[email protected]f7817822009-09-24 05:11:58506 }
507
[email protected]f5494d42010-12-23 22:15:34508 virtual void OnHandleContextMenu(HANDLE menu_handle,
[email protected]045229a72010-03-03 22:11:19509 int align_flags,
[email protected]f5494d42010-12-23 22:15:34510 const MiniContextMenuParams& params) {
[email protected]97965e12010-04-09 00:51:10511 scoped_refptr<BasePlugin> ref(this);
[email protected]f5494d42010-12-23 22:15:34512 ChromeFramePlugin<T>::OnHandleContextMenu(menu_handle, align_flags, params);
[email protected]045229a72010-03-03 22:11:19513 }
514
[email protected]f7817822009-09-24 05:11:58515 LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
516 BOOL& handled) { // NO_LINT
517 ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
[email protected]bbfa9a12010-08-10 14:09:37518 url_fetcher_->put_notification_window(m_hWnd);
[email protected]dd4beb522010-07-13 18:18:14519 if (automation_client_.get()) {
520 automation_client_->SetParentWindow(m_hWnd);
521 } else {
522 NOTREACHED() << "No automation server";
523 return -1;
524 }
[email protected]f7817822009-09-24 05:11:58525 // Only fire the 'interactive' ready state if we aren't there already.
526 if (ready_state_ < READYSTATE_INTERACTIVE) {
527 ready_state_ = READYSTATE_INTERACTIVE;
528 FireOnChanged(DISPID_READYSTATE);
529 }
530 return 0;
531 }
532
[email protected]e9eb50c2009-10-24 16:26:46533 LRESULT OnDestroy(UINT message, WPARAM wparam, LPARAM lparam,
534 BOOL& handled) { // NO_LINT
[email protected]2b9a9f162010-10-19 20:30:45535 DVLOG(1) << __FUNCTION__;
[email protected]e9eb50c2009-10-24 16:26:46536 return 0;
537 }
538
[email protected]f7817822009-09-24 05:11:58539 // ChromeFrameDelegate override
540 virtual void OnAutomationServerReady() {
[email protected]bbfa9a12010-08-10 14:09:37541 draw_sad_tab_ = false;
[email protected]f7817822009-09-24 05:11:58542 ChromeFramePlugin<T>::OnAutomationServerReady();
543
544 ready_state_ = READYSTATE_COMPLETE;
545 FireOnChanged(DISPID_READYSTATE);
546 }
547
548 // ChromeFrameDelegate override
549 virtual void OnAutomationServerLaunchFailed(
550 AutomationLaunchResult reason, const std::string& server_version) {
[email protected]2b9a9f162010-10-19 20:30:45551 DVLOG(1) << __FUNCTION__;
[email protected]bbfa9a12010-08-10 14:09:37552 if (reason == AUTOMATION_SERVER_CRASHED)
553 draw_sad_tab_ = true;
554
[email protected]f7817822009-09-24 05:11:58555 ready_state_ = READYSTATE_UNINITIALIZED;
556 FireOnChanged(DISPID_READYSTATE);
557 }
558
[email protected]f5494d42010-12-23 22:15:34559 virtual void OnCloseTab() {
[email protected]2f1793ea2010-10-27 17:32:51560 Fire_onclose();
561 }
562
[email protected]f7817822009-09-24 05:11:58563 // Overridden to take advantage of readystate prop changes and send those
564 // to potential listeners.
565 HRESULT FireOnChanged(DISPID dispid) {
566 if (dispid == DISPID_READYSTATE) {
567 Fire_onreadystatechanged(ready_state_);
568 }
569 return __super::FireOnChanged(dispid);
570 }
571
572 // IChromeFrame
573 // Property getter/setters for the src attribute, which contains a URL.
574 // The ChromeFrameActivex control initiates navigation to this URL
575 // when instantiated.
576 STDMETHOD(get_src)(BSTR* src) {
577 if (NULL == src) {
578 return E_POINTER;
579 }
580
581 *src = SysAllocString(url_);
582 return S_OK;
583 }
584
585 STDMETHOD(put_src)(BSTR src) {
586 if (src == NULL)
587 return E_INVALIDARG;
588
589 // Switch the src to UTF8 and try to expand to full URL
590 std::string src_utf8;
591 WideToUTF8(src, SysStringLen(src), &src_utf8);
592 std::string full_url = ResolveURL(GetDocumentUrl(), src_utf8);
[email protected]f7817822009-09-24 05:11:58593
594 // We can initiate navigation here even if ready_state is not complete.
595 // We do not have to set proxy, and AutomationClient will take care
596 // of navigation just after CreateExternalTab is done.
[email protected]b36a9f92009-10-19 17:34:57597 if (!automation_client_->InitiateNavigation(full_url,
598 GetDocumentUrl(),
[email protected]354bcba2010-12-14 04:34:43599 this)) {
[email protected]f7817822009-09-24 05:11:58600 // TODO(robertshield): Make InitiateNavigation return more useful
601 // error information.
602 return E_INVALIDARG;
603 }
604
605 // Save full URL in BSTR member
606 url_.Reset(::SysAllocString(UTF8ToWide(full_url).c_str()));
607
608 return S_OK;
609 }
610
611 STDMETHOD(get_onload)(VARIANT* onload_handler) {
612 if (NULL == onload_handler)
613 return E_INVALIDARG;
614
615 *onload_handler = onload_handler_.Copy();
616
617 return S_OK;
618 }
619
620 // Property setter for the onload attribute, which contains a
621 // javascript function to be invoked on successful navigation.
622 STDMETHOD(put_onload)(VARIANT onload_handler) {
623 if (V_VT(&onload_handler) != VT_DISPATCH) {
624 DLOG(WARNING) << "Invalid onload handler type: "
625 << onload_handler.vt
626 << " specified";
627 return E_INVALIDARG;
628 }
629
630 onload_handler_ = onload_handler;
631
632 return S_OK;
633 }
634
635 // Property getter/setters for the onloaderror attribute, which contains a
636 // javascript function to be invoked on navigation failure.
637 STDMETHOD(get_onloaderror)(VARIANT* onerror_handler) {
638 if (NULL == onerror_handler)
639 return E_INVALIDARG;
640
641 *onerror_handler = onerror_handler_.Copy();
642
643 return S_OK;
644 }
645
646 STDMETHOD(put_onloaderror)(VARIANT onerror_handler) {
647 if (V_VT(&onerror_handler) != VT_DISPATCH) {
648 DLOG(WARNING) << "Invalid onloaderror handler type: "
649 << onerror_handler.vt
650 << " specified";
651 return E_INVALIDARG;
652 }
653
654 onerror_handler_ = onerror_handler;
655
656 return S_OK;
657 }
658
659 // Property getter/setters for the onmessage attribute, which contains a
660 // javascript function to be invoked when we receive a message from the
661 // chrome frame.
662 STDMETHOD(put_onmessage)(VARIANT onmessage_handler) {
663 if (V_VT(&onmessage_handler) != VT_DISPATCH) {
664 DLOG(WARNING) << "Invalid onmessage handler type: "
665 << onmessage_handler.vt
666 << " specified";
667 return E_INVALIDARG;
668 }
669
670 onmessage_handler_ = onmessage_handler;
671
672 return S_OK;
673 }
674
675 STDMETHOD(get_onmessage)(VARIANT* onmessage_handler) {
676 if (NULL == onmessage_handler)
677 return E_INVALIDARG;
678
679 *onmessage_handler = onmessage_handler_.Copy();
680
681 return S_OK;
682 }
683
684 STDMETHOD(get_readyState)(long* ready_state) { // NOLINT
[email protected]2b9a9f162010-10-19 20:30:45685 DVLOG(1) << __FUNCTION__;
[email protected]f7817822009-09-24 05:11:58686 DCHECK(ready_state);
687
688 if (!ready_state)
689 return E_INVALIDARG;
690
691 *ready_state = ready_state_;
692
693 return S_OK;
694 }
695
696 // Property getter/setters for use_chrome_network flag. This flag
697 // indicates if chrome network stack is to be used for fetching
698 // network requests.
699 STDMETHOD(get_useChromeNetwork)(VARIANT_BOOL* use_chrome_network) {
700 if (!use_chrome_network)
701 return E_INVALIDARG;
702
703 *use_chrome_network =
704 automation_client_->use_chrome_network() ? VARIANT_TRUE : VARIANT_FALSE;
705 return S_OK;
706 }
707
708 STDMETHOD(put_useChromeNetwork)(VARIANT_BOOL use_chrome_network) {
[email protected]0753db592010-12-15 14:45:05709 if (!is_privileged()) {
[email protected]f7817822009-09-24 05:11:58710 DLOG(ERROR) << "Attempt to set useChromeNetwork in non-privileged mode";
711 return E_ACCESSDENIED;
712 }
713
714 automation_client_->set_use_chrome_network(
715 (VARIANT_FALSE != use_chrome_network));
716 return S_OK;
717 }
718
719 // Posts a message to the chrome frame.
720 STDMETHOD(postMessage)(BSTR message, VARIANT target) {
721 if (NULL == message) {
722 return E_INVALIDARG;
723 }
724
725 if (!automation_client_.get())
726 return E_FAIL;
727
728 std::string utf8_target;
729 if (target.vt == VT_BSTR) {
730 int len = ::SysStringLen(target.bstrVal);
731 if (len == 1 && target.bstrVal[0] == L'*') {
732 utf8_target = "*";
733 } else {
734 GURL resolved(target.bstrVal);
735 if (!resolved.is_valid()) {
736 Error(L"Unable to parse the specified target URL.");
737 return E_INVALIDARG;
738 }
739
740 utf8_target = resolved.spec();
741 }
742 } else {
743 utf8_target = "*";
744 }
745
746 std::string utf8_message;
747 WideToUTF8(message, ::SysStringLen(message), &utf8_message);
748
749 GURL url(GURL(document_url_).GetOrigin());
750 std::string origin(url.is_empty() ? "null" : url.spec());
751 if (!automation_client_->ForwardMessageFromExternalHost(utf8_message,
752 origin,
753 utf8_target)) {
754 Error(L"Failed to post message to chrome frame");
755 return E_FAIL;
756 }
757
758 return S_OK;
759 }
760
761 STDMETHOD(addEventListener)(BSTR event_type, IDispatch* listener,
762 VARIANT use_capture) {
763 EventHandlers* handlers = NULL;
764 HRESULT hr = GetHandlersForEvent(event_type, &handlers);
765 if (FAILED(hr))
766 return hr;
767
768 DCHECK(handlers != NULL);
769
[email protected]965722ff2010-10-20 15:50:30770 handlers->insert(base::win::ScopedComPtr<IDispatch>(listener));
[email protected]f7817822009-09-24 05:11:58771
772 return hr;
773 }
774
775 STDMETHOD(removeEventListener)(BSTR event_type, IDispatch* listener,
776 VARIANT use_capture) {
777 EventHandlers* handlers = NULL;
778 HRESULT hr = GetHandlersForEvent(event_type, &handlers);
779 if (FAILED(hr))
780 return hr;
781
782 DCHECK(handlers != NULL);
[email protected]c90d8492011-01-30 22:47:42783 handlers->erase(base::win::ScopedComPtr<IDispatch>(listener));
[email protected]f7817822009-09-24 05:11:58784
785 return hr;
786 }
787
788 STDMETHOD(get_version)(BSTR* version) {
789 if (!automation_client_.get()) {
790 NOTREACHED();
791 return E_FAIL;
792 }
793
794 if (version == NULL) {
795 return E_INVALIDARG;
796 }
797
798 *version = SysAllocString(automation_client_->GetVersion().c_str());
799 return S_OK;
800 }
801
802 STDMETHOD(postPrivateMessage)(BSTR message, BSTR origin, BSTR target) {
803 if (NULL == message)
804 return E_INVALIDARG;
805
[email protected]0753db592010-12-15 14:45:05806 if (!is_privileged()) {
[email protected]f7817822009-09-24 05:11:58807 DLOG(ERROR) << "Attempt to postPrivateMessage in non-privileged mode";
808 return E_ACCESSDENIED;
809 }
810
811 DCHECK(automation_client_.get());
812 std::string utf8_message, utf8_origin, utf8_target;
813 WideToUTF8(message, ::SysStringLen(message), &utf8_message);
814 WideToUTF8(origin, ::SysStringLen(origin), &utf8_origin);
815 WideToUTF8(target, ::SysStringLen(target), &utf8_target);
816
817 if (!automation_client_->ForwardMessageFromExternalHost(utf8_message,
818 utf8_origin,
819 utf8_target)) {
820 Error(L"Failed to post message to chrome frame");
821 return E_FAIL;
822 }
823
824 return S_OK;
825 }
826
[email protected]00f6b772009-10-23 17:03:41827 STDMETHOD(installExtension)(BSTR crx_path) {
828 DCHECK(automation_client_.get());
829
830 if (NULL == crx_path) {
831 NOTREACHED();
832 return E_INVALIDARG;
833 }
834
[email protected]0753db592010-12-15 14:45:05835 if (!is_privileged()) {
[email protected]00f6b772009-10-23 17:03:41836 DLOG(ERROR) << "Attempt to installExtension in non-privileged mode";
837 return E_ACCESSDENIED;
838 }
839
840 FilePath::StringType crx_path_str(crx_path);
841 FilePath crx_file_path(crx_path_str);
842
843 automation_client_->InstallExtension(crx_file_path, NULL);
844 return S_OK;
845 }
846
847 STDMETHOD(loadExtension)(BSTR path) {
848 DCHECK(automation_client_.get());
849
850 if (NULL == path) {
851 NOTREACHED();
852 return E_INVALIDARG;
853 }
854
[email protected]0753db592010-12-15 14:45:05855 if (!is_privileged()) {
[email protected]00f6b772009-10-23 17:03:41856 DLOG(ERROR) << "Attempt to loadExtension in non-privileged mode";
857 return E_ACCESSDENIED;
858 }
859
860 FilePath::StringType path_str(path);
861 FilePath file_path(path_str);
862
863 automation_client_->LoadExpandedExtension(file_path, NULL);
864 return S_OK;
865 }
866
[email protected]a1e62d12010-03-16 02:18:43867 STDMETHOD(getEnabledExtensions)() {
868 DCHECK(automation_client_.get());
869
[email protected]0753db592010-12-15 14:45:05870 if (!is_privileged()) {
[email protected]a1e62d12010-03-16 02:18:43871 DLOG(ERROR) << "Attempt to getEnabledExtensions in non-privileged mode";
872 return E_ACCESSDENIED;
873 }
874
875 automation_client_->GetEnabledExtensions(NULL);
876 return S_OK;
877 }
878
[email protected]751bf4b2010-11-05 22:06:31879 STDMETHOD(getSessionId)(int* session_id) {
880 DCHECK(automation_client_.get());
881 DCHECK(session_id);
882
[email protected]0753db592010-12-15 14:45:05883 if (!is_privileged()) {
[email protected]751bf4b2010-11-05 22:06:31884 DLOG(ERROR) << "Attempt to getSessionId in non-privileged mode";
885 return E_ACCESSDENIED;
886 }
887
888 *session_id = automation_client_->GetSessionId();
889 return (*session_id) == -1 ? S_FALSE : S_OK;
890 }
891
[email protected]ca982ec42010-05-02 14:47:14892 STDMETHOD(registerBhoIfNeeded)() {
[email protected]e12a3b82010-05-01 00:06:00893 return E_NOTIMPL;
894 }
895
[email protected]f7817822009-09-24 05:11:58896 // Returns the vector of event handlers for a given event (e.g. "load").
897 // If the event type isn't recognized, the function fills in a descriptive
898 // error (IErrorInfo) and returns E_INVALIDARG.
899 HRESULT GetHandlersForEvent(BSTR event_type, EventHandlers** handlers) {
900 DCHECK(handlers != NULL);
901
[email protected]00f6b772009-10-23 17:03:41902 // TODO(tommi): make these if() statements data-driven.
[email protected]f7817822009-09-24 05:11:58903 HRESULT hr = S_OK;
904 const wchar_t* event_type_end = event_type + ::SysStringLen(event_type);
905 if (LowerCaseEqualsASCII(event_type, event_type_end, "message")) {
906 *handlers = &onmessage_;
907 } else if (LowerCaseEqualsASCII(event_type, event_type_end, "load")) {
908 *handlers = &onload_;
909 } else if (LowerCaseEqualsASCII(event_type, event_type_end, "loaderror")) {
910 *handlers = &onloaderror_;
911 } else if (LowerCaseEqualsASCII(event_type, event_type_end,
912 "readystatechanged")) {
913 *handlers = &onreadystatechanged_;
914 } else if (LowerCaseEqualsASCII(event_type, event_type_end,
[email protected]00f6b772009-10-23 17:03:41915 "privatemessage")) {
[email protected]f7817822009-09-24 05:11:58916 // This event handler is only available in privileged mode.
[email protected]0753db592010-12-15 14:45:05917 if (is_privileged()) {
[email protected]00f6b772009-10-23 17:03:41918 *handlers = &onprivatemessage_;
919 } else {
[email protected]f7817822009-09-24 05:11:58920 Error("Event type 'privatemessage' is privileged");
[email protected]00f6b772009-10-23 17:03:41921 hr = E_ACCESSDENIED;
[email protected]f7817822009-09-24 05:11:58922 }
[email protected]00f6b772009-10-23 17:03:41923 } else if (LowerCaseEqualsASCII(event_type, event_type_end,
924 "extensionready")) {
925 // This event handler is only available in privileged mode.
[email protected]0753db592010-12-15 14:45:05926 if (is_privileged()) {
[email protected]00f6b772009-10-23 17:03:41927 *handlers = &onextensionready_;
928 } else {
929 Error("Event type 'extensionready' is privileged");
930 hr = E_ACCESSDENIED;
931 }
[email protected]f7817822009-09-24 05:11:58932 } else {
[email protected]d3451d832010-10-01 11:17:37933 Error(base::StringPrintf(
934 "Event type '%ls' not found", event_type).c_str());
[email protected]f7817822009-09-24 05:11:58935 hr = E_INVALIDARG;
936 }
937
938 return hr;
939 }
940
[email protected]a1800e82009-11-19 00:53:23941 // Creates a new event object that supports the |data| property.
942 // Note: you should supply an empty string for |origin| unless you're
943 // creating a "message" event.
944 HRESULT CreateDomEvent(const std::string& event_type, const std::string& data,
945 const std::string& origin, IDispatch** event) {
[email protected]62bb18dc12009-11-25 01:34:08946 DCHECK(event_type.length() > 0); // NOLINT
[email protected]a1800e82009-11-19 00:53:23947 DCHECK(event != NULL);
948
949 CComObject<ComMessageEvent>* ev = NULL;
950 HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
951 if (SUCCEEDED(hr)) {
952 ev->AddRef();
953
[email protected]965722ff2010-10-20 15:50:30954 base::win::ScopedComPtr<IOleContainer> container;
[email protected]a1800e82009-11-19 00:53:23955 m_spClientSite->GetContainer(container.Receive());
956 if (ev->Initialize(container, data, origin, event_type)) {
957 *event = ev;
958 } else {
959 NOTREACHED() << "event->Initialize";
960 ev->Release();
961 hr = E_UNEXPECTED;
962 }
963 }
964
965 return hr;
966 }
967
968 // Helper function to execute a function on a script IDispatch interface.
969 HRESULT InvokeScriptFunction(const VARIANT& script_object,
970 const std::string& param) {
[email protected]965722ff2010-10-20 15:50:30971 base::win::ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
[email protected]a1800e82009-11-19 00:53:23972 return InvokeScriptFunction(script_object, script_arg.AsInput());
973 }
974
975 HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* param) {
976 return InvokeScriptFunction(script_object, param, 1);
977 }
978
979 HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* params,
980 int param_count) {
[email protected]62bb18dc12009-11-25 01:34:08981 DCHECK_GE(param_count, 0);
[email protected]a1800e82009-11-19 00:53:23982 DCHECK(params);
983
[email protected]086f367d52010-04-23 21:01:50984 if (V_VT(&script_object) != VT_DISPATCH ||
985 script_object.pdispVal == NULL) {
[email protected]a1800e82009-11-19 00:53:23986 return S_FALSE;
987 }
988
989 CComPtr<IDispatch> script(script_object.pdispVal);
990 HRESULT hr = script.InvokeN(static_cast<DISPID>(DISPID_VALUE),
991 params,
992 param_count);
993 // 0x80020101 == SCRIPT_E_REPORTED.
994 // When the script we're invoking has an error, we get this error back.
995 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
996 return hr;
997 }
998
[email protected]f7817822009-09-24 05:11:58999 // Gives the browser a chance to handle an accelerator that was
1000 // sent to the out of proc chromium instance.
1001 // Returns S_OK iff the accelerator was handled by the browser.
1002 HRESULT AllowFrameToTranslateAccelerator(const MSG& msg) {
[email protected]84415812010-05-19 23:12:421003 static const int kMayTranslateAcceleratorOffset = 0x5c;
[email protected]f7817822009-09-24 05:11:581004 // Although IBrowserService2 is officially deprecated, it's still alive
1005 // and well in IE7 and earlier. We have to use it here to correctly give
1006 // the browser a chance to handle keyboard shortcuts.
1007 // This happens automatically for activex components that have windows that
1008 // belong to the current thread. In that circumstance IE owns the message
1009 // loop and can walk the line of components allowing each participant the
1010 // chance to handle the keystroke and eventually falls back to
1011 // v_MayTranslateAccelerator. However in our case, the message loop is
1012 // owned by the out-of-proc chromium instance so IE doesn't have a chance to
1013 // fall back on its default behavior. Instead we give IE a chance to
1014 // handle the shortcut here.
[email protected]01dba672010-02-12 21:55:481015 MSG accel_message = msg;
1016 accel_message.hwnd = ::GetParent(m_hWnd);
[email protected]f7817822009-09-24 05:11:581017 HRESULT hr = S_FALSE;
[email protected]965722ff2010-10-20 15:50:301018 base::win::ScopedComPtr<IBrowserService2> bs2;
[email protected]3eafbfb92010-08-02 16:54:221019
1020 // For non-IE containers, we use the standard IOleInPlaceFrame contract
1021 // (which IE does not support). For IE, we try to use IBrowserService2,
1022 // but need special handling for IE8 (see below).
1023 //
1024 // We try to cache an IOleInPlaceFrame for our site. If we fail, we don't
1025 // retry, and we fall back to the IBrowserService2 and PostMessage
1026 // approaches below.
1027 if (!in_place_frame_ && !failed_to_fetch_in_place_frame_) {
[email protected]965722ff2010-10-20 15:50:301028 base::win::ScopedComPtr<IOleInPlaceUIWindow> dummy_ui_window;
[email protected]3eafbfb92010-08-02 16:54:221029 RECT dummy_pos_rect = {0};
1030 RECT dummy_clip_rect = {0};
1031 OLEINPLACEFRAMEINFO dummy_frame_info = {0};
[email protected]58640fa2011-02-15 00:05:221032 if (!m_spInPlaceSite ||
1033 FAILED(m_spInPlaceSite->GetWindowContext(in_place_frame_.Receive(),
[email protected]3eafbfb92010-08-02 16:54:221034 dummy_ui_window.Receive(),
1035 &dummy_pos_rect,
1036 &dummy_clip_rect,
1037 &dummy_frame_info))) {
1038 failed_to_fetch_in_place_frame_ = true;
1039 }
1040 }
1041
1042 // The IBrowserService2 code below (second conditional) explicitly checks
1043 // for whether the IBrowserService2::v_MayTranslateAccelerator function is
1044 // valid. On IE8 there is one vtable ieframe!c_ImpostorBrowserService2Vtbl
1045 // where this function entry is NULL which leads to a crash. We don't know
1046 // under what circumstances this vtable is actually used though.
1047 if (in_place_frame_) {
1048 hr = in_place_frame_->TranslateAccelerator(&accel_message, 0);
1049 } else if (S_OK == DoQueryService(
1050 SID_STopLevelBrowser, m_spInPlaceSite,
1051 bs2.Receive()) && bs2.get() &&
1052 *(*(reinterpret_cast<void***>(bs2.get())) +
1053 kMayTranslateAcceleratorOffset)) {
[email protected]01dba672010-02-12 21:55:481054 hr = bs2->v_MayTranslateAccelerator(&accel_message);
[email protected]f7817822009-09-24 05:11:581055 } else {
1056 // IE8 doesn't support IBrowserService2 unless you enable a special,
1057 // undocumented flag with CoInternetSetFeatureEnabled and even then,
1058 // the object you get back implements only a couple of methods of
1059 // that interface... all the other entries in the vtable are NULL.
1060 // In addition, the class that implements it is called
1061 // ImpostorBrowserService2 :)
1062 // IE8 does have a new interface though, presumably called
1063 // ITabBrowserService or something that can be abbreviated to TBS.
1064 // That interface has a method, TranslateAcceleratorTBS that does
1065 // call the root MayTranslateAccelerator function, but alas the
1066 // first argument to MayTranslateAccelerator is hard coded to FALSE
1067 // which means that global accelerators are not handled and we're
1068 // out of luck.
1069 // A third thing that's notable with regards to IE8 is that
1070 // none of the *MayTranslate* functions exist in a vtable inside
1071 // ieframe.dll. I checked this by scanning for the address of
1072 // those functions inside the dll and found none, which means that
1073 // all calls to those functions are relative.
[email protected]3eafbfb92010-08-02 16:54:221074 // So, for IE8 in certain cases, and for other containers that may
1075 // support neither IOleInPlaceFrame or IBrowserService2 our approach
1076 // is very simple. Just post the message to our parent window and IE
1077 // will pick it up if it's an accelerator. We won't know for sure if
1078 // the browser handled the keystroke or not.
[email protected]01dba672010-02-12 21:55:481079 ::PostMessage(accel_message.hwnd, accel_message.message,
1080 accel_message.wParam, accel_message.lParam);
[email protected]f7817822009-09-24 05:11:581081 }
1082
1083 return hr;
1084 }
1085
[email protected]f5494d42010-12-23 22:15:341086 virtual void OnAcceleratorPressed(const MSG& accel_message) {
[email protected]2b8fd322009-10-02 00:00:591087 DCHECK(m_spInPlaceSite != NULL);
1088 // Allow our host a chance to handle the accelerator.
1089 // This catches things like Ctrl+F, Ctrl+O etc, but not browser
1090 // accelerators such as F11, Ctrl+T etc.
1091 // (see AllowFrameToTranslateAccelerator for those).
1092 HRESULT hr = TranslateAccelerator(const_cast<MSG*>(&accel_message));
1093 if (hr != S_OK)
1094 hr = AllowFrameToTranslateAccelerator(accel_message);
1095
[email protected]2b9a9f162010-10-19 20:30:451096 DVLOG(1) << __FUNCTION__ << " browser response: "
1097 << base::StringPrintf("0x%08x", hr);
[email protected]2b8fd322009-10-02 00:00:591098
1099 if (hr != S_OK) {
[email protected]4e964792010-11-30 23:27:481100 // The WM_SYSKEYDOWN/WM_SYSKEYUP messages are not processed by the
1101 // IOleControlSite and IBrowserService2::v_MayTranslateAccelerator
1102 // implementations. We need to understand this better. That is for
1103 // another day. For now we just post these messages back to the parent
1104 // which forwards it off to the frame. This should not cause major
1105 // grief for Chrome as it does not need to handle WM_SYSKEY* messages in
1106 // in ChromeFrame mode.
[email protected]2b8fd322009-10-02 00:00:591107 // TODO(iyengar)
1108 // Understand and fix WM_SYSCHAR handling
1109 // We should probably unify the accelerator handling for the active
1110 // document and the activex.
[email protected]4e964792010-11-30 23:27:481111 if (accel_message.message == WM_SYSCHAR ||
1112 accel_message.message == WM_SYSKEYDOWN ||
1113 accel_message.message == WM_SYSKEYUP) {
1114 ::PostMessage(GetParent(), accel_message.message, accel_message.wParam,
[email protected]2b8fd322009-10-02 00:00:591115 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) {
[email protected]965722ff2010-10-20 15:50:301135 base::win::ScopedComPtr<IWebBrowser2> web_browser2;
[email protected]b1c55638612010-03-08 16:26:111136 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]965722ff2010-10-20 15:50:301141 base::win::ScopedVariant url;
[email protected]b1c55638612010-03-08 16:26:111142 // 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
[email protected]965722ff2010-10-20 15:50:301210 VARIANT empty = base::win::ScopedVariant::kEmptyVariant;
1211 base::win::ScopedVariant http_headers;
[email protected]b1c55638612010-03-08 16:26:111212
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
[email protected]52622ca12011-01-06 22:53:061220 HRESULT hr = web_browser2->Navigate2(url.AsInput(), &flags, &empty, &empty,
1221 http_headers.AsInput());
1222 // If the current window is a popup window then attempting to open a new
1223 // tab for the navigation will fail. We attempt to issue the navigation in
1224 // a new window in this case.
1225 // http://msdn.microsoft.com/en-us/library/aa752133(v=vs.85).aspx
1226 if (FAILED(hr) && V_I4(&flags) != navOpenInNewWindow) {
1227 V_I4(&flags) = navOpenInNewWindow;
1228 hr = web_browser2->Navigate2(url.AsInput(), &flags, &empty, &empty,
1229 http_headers.AsInput());
1230
1231 DLOG_IF(ERROR, FAILED(hr))
1232 << "Navigate2 failed with error: "
1233 << base::StringPrintf("0x%08X", hr);
1234 }
[email protected]b1c55638612010-03-08 16:26:111235 }
1236
[email protected]e1081d92010-09-10 20:29:111237 void InitializeAutomationSettings() {
1238 static const wchar_t kHandleTopLevelRequests[] = L"HandleTopLevelRequests";
1239 static const wchar_t kUseChromeNetworking[] = L"UseChromeNetworking";
1240
1241 // Query and assign the top-level-request routing, and host networking
1242 // settings from the registry.
1243 bool top_level_requests = GetConfigBool(true, kHandleTopLevelRequests);
1244 bool chrome_network = GetConfigBool(false, kUseChromeNetworking);
1245 automation_client_->set_handle_top_level_requests(top_level_requests);
1246 automation_client_->set_use_chrome_network(chrome_network);
1247 }
1248
[email protected]965722ff2010-10-20 15:50:301249 base::win::ScopedBstr url_;
1250 base::win::ScopedComPtr<IOleDocumentSite> doc_site_;
[email protected]f7817822009-09-24 05:11:581251
[email protected]3eafbfb92010-08-02 16:54:221252 // If false, we tried but failed to fetch an IOleInPlaceFrame from our host.
1253 // Cached here so we don't try to fetch it every time if we keep failing.
1254 bool failed_to_fetch_in_place_frame_;
[email protected]bbfa9a12010-08-10 14:09:371255 bool draw_sad_tab_;
1256
[email protected]965722ff2010-10-20 15:50:301257 base::win::ScopedComPtr<IOleInPlaceFrame> in_place_frame_;
[email protected]3eafbfb92010-08-02 16:54:221258
[email protected]f7817822009-09-24 05:11:581259 // For more information on the ready_state_ property see:
1260 // http://msdn.microsoft.com/en-us/library/aa768179(VS.85).aspx#
1261 READYSTATE ready_state_;
1262
1263 // The following members contain IDispatch interfaces representing the
1264 // onload/onerror/onmessage handlers on the page.
[email protected]965722ff2010-10-20 15:50:301265 base::win::ScopedVariant onload_handler_;
1266 base::win::ScopedVariant onerror_handler_;
1267 base::win::ScopedVariant onmessage_handler_;
[email protected]f7817822009-09-24 05:11:581268
1269 EventHandlers onmessage_;
1270 EventHandlers onloaderror_;
1271 EventHandlers onload_;
1272 EventHandlers onreadystatechanged_;
1273 EventHandlers onprivatemessage_;
[email protected]00f6b772009-10-23 17:03:411274 EventHandlers onextensionready_;
[email protected]f7817822009-09-24 05:11:581275
[email protected]3eb07da2010-02-01 19:48:361276 // Handle network requests when host network stack is used. Passed to the
1277 // automation client on initialization.
[email protected]bbfa9a12010-08-10 14:09:371278 scoped_ptr<UrlmonUrlRequestManager> url_fetcher_;
[email protected]f7817822009-09-24 05:11:581279};
1280
1281#endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_