1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_FRAME_TEST_IE_EVENT_SINK_H_
#define CHROME_FRAME_TEST_IE_EVENT_SINK_H_
#include <atlbase.h>
#include <atlwin.h>
#include <exdispid.h>
#include <string>
#include "base/win/scoped_comptr.h"
#include "chrome_frame/chrome_tab.h"
#include "chrome_frame/test/simulate_input.h"
#include "chrome_frame/test_utils.h"
namespace chrome_frame_test {
// Listener for all events from the IEEventSink, defined below. This includes
// IE and CF events. Unfortunately some of these events are unreliable or have
// strange behavior across different platforms/browsers. See notes besides
// each method.
class IEEventListener {
public:
virtual ~IEEventListener() {}
// IE callbacks
virtual void OnNavigateError(IDispatch* dispatch, VARIANT* url,
VARIANT* frame_name, VARIANT* status_code,
VARIANT* cancel) {}
// This does not occur in IE 6 in CF when navigating between fragments
// on the same page, although it does occur with back/forward across such.
virtual void OnBeforeNavigate2(IDispatch* dispatch, VARIANT* url,
VARIANT* flags, VARIANT* target_frame_name,
VARIANT* post_data, VARIANT* headers,
VARIANT_BOOL* cancel) {}
virtual void OnDownloadBegin() {}
virtual void OnNavigateComplete2(IDispatch* dispatch, VARIANT* url) {}
virtual void OnNewWindow2(IDispatch** dispatch, VARIANT_BOOL* cancel) {}
virtual void OnNewWindow3(IDispatch** dispatch, VARIANT_BOOL* cancel,
DWORD flags, BSTR url_context, BSTR url) {}
// This occurs twice on IE >= 7 after window.open calls.
virtual void OnDocumentComplete(IDispatch* dispatch, VARIANT* url_variant) {}
virtual void OnFileDownload(VARIANT_BOOL active_doc, VARIANT_BOOL* cancel) {}
virtual void OnQuit() {}
// CF callbacks
virtual void OnLoad(const wchar_t* url) {}
virtual void OnLoadError(const wchar_t* url) {}
virtual void OnMessage(const wchar_t* message, const wchar_t* origin,
const wchar_t* source) {}
virtual void OnNewBrowserWindow(IDispatch* new_window, const wchar_t* url) {}
};
// Listener for IPropertyNotifySink.
class PropertyNotifySinkListener {
public:
virtual ~PropertyNotifySinkListener() {}
virtual void OnChanged(DISPID dispid) {}
virtual void OnRequestEdit(DISPID dispid) {}
};
// This class sets up event sinks to the IWebBrowser interface. It forwards
// all events to its listener.
class IEEventSink
: public CComObjectRootEx<CComSingleThreadModel>,
public IDispEventSimpleImpl<0, IEEventSink,
&DIID_DWebBrowserEvents2>,
public IUnknown {
public:
// Needed to support PostTask.
static bool ImplementsThreadSafeReferenceCounting() {
return true;
}
typedef IDispEventSimpleImpl<0, IEEventSink,
&DIID_DWebBrowserEvents2> DispEventsImpl;
IEEventSink();
~IEEventSink();
// Launches IE, sets up the sink to forward events to the listener, and
// navigates to the given page.
HRESULT LaunchIEAndNavigate(const std::wstring& navigate_url,
IEEventListener* listener);
// Navigate to the given url.
HRESULT Navigate(const std::wstring& navigate_url);
// Listen to events from this |browser_disp|, which should be queryable for
// IWebBrowser2.
void Attach(IDispatch* browser_disp);
// Listen to events from the given browser.
HRESULT Attach(IWebBrowser2* browser);
// Stop listening to the associated web browser and possibly wait for it to
// close, if this browser has its own process.
void Uninitialize();
// Closes the web browser in such a way that the OnQuit notification will
// be fired when the window closes (async).
HRESULT CloseWebBrowser();
// Posts a message to the given target in ChromeFrame. |target| may be "*".
void PostMessageToCF(const std::wstring& message, const std::wstring& target);
// Set input focus to chrome frame window.
void SetFocusToRenderer();
// Send keyboard input to the renderer window hosted in chrome using
// SendInput API.
void SendKeys(const wchar_t* input_string);
// Send mouse click to the renderer window hosted in chrome using
// SendInput API.
void SendMouseClick(int x, int y, simulate_input::MouseButton button);
// Get the HWND for the browser's main window. Will fail test if window
// not found.
HWND GetBrowserWindow();
// Get the HWND for the browser's renderer window. Will fail test if
// renderer window not found.
HWND GetRendererWindow();
// Same as above, but does not fail the test if the window cannot be found.
// In that case, the returned handle will be NULL.
HWND GetRendererWindowSafe();
// Returns whether CF is rendering the current page.
bool IsCFRendering();
// Expect the renderer window to have focus.
void ExpectRendererWindowHasFocus();
// Expect the address bar to have |url|.
void ExpectAddressBarUrl(const std::wstring& url);
// These methods are just simple wrappers of the IWebBrowser2 methods.
// They are needed because you cannot post tasks to IWebBrowser2.
void GoBack() {
web_browser2_->GoBack();
}
void GoForward() {
web_browser2_->GoForward();
}
void Refresh();
void Exec(const GUID* cmd_group_guid, DWORD command_id,
DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args);
// Set the listener for this sink, which can be NULL.
void set_listener(IEEventListener* listener) { listener_ = listener; }
IWebBrowser2* web_browser2() { return web_browser2_.get(); }
// Used only for debugging/logging purposes.
bool reference_count() { return m_dwRef; }
static void SetAbnormalShutdown(bool abnormal_shutdown);
private:
void ConnectToChromeFrame();
void DisconnectFromChromeFrame();
void FindIEProcessId();
// IE callbacks.
BEGIN_COM_MAP(IEEventSink)
COM_INTERFACE_ENTRY(IUnknown)
END_COM_MAP()
BEGIN_SINK_MAP(IEEventSink)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2,
OnBeforeNavigate2, &kBeforeNavigate2Info)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN,
OnDownloadBegin, &kVoidMethodInfo)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2,
OnNavigateComplete2, &kNavigateComplete2Info)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR,
OnNavigateError, &kNavigateErrorInfo)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW2,
OnNewWindow2, &kNewWindow2Info)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3,
OnNewWindow3, &kNewWindow3Info)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE,
OnDocumentComplete, &kDocumentCompleteInfo)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_FILEDOWNLOAD,
OnFileDownload, &kFileDownloadInfo)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_ONQUIT,
OnQuit, &kVoidMethodInfo)
END_SINK_MAP()
STDMETHOD_(void, OnNavigateError)(IDispatch* dispatch, VARIANT* url,
VARIANT* frame_name, VARIANT* status_code,
VARIANT* cancel);
STDMETHOD(OnBeforeNavigate2)(IDispatch* dispatch, VARIANT* url,
VARIANT* flags, VARIANT* target_frame_name,
VARIANT* post_data, VARIANT* headers,
VARIANT_BOOL* cancel);
STDMETHOD_(void, OnDownloadBegin)();
STDMETHOD_(void, OnNavigateComplete2)(IDispatch* dispatch, VARIANT* url);
STDMETHOD_(void, OnNewWindow2)(IDispatch** dispatch, VARIANT_BOOL* cancel);
STDMETHOD_(void, OnNewWindow3)(IDispatch** dispatch, VARIANT_BOOL* cancel,
DWORD flags, BSTR url_context, BSTR url);
STDMETHOD_(void, OnDocumentComplete)(IDispatch* dispatch,
VARIANT* url_variant);
STDMETHOD_(void, OnFileDownload)(VARIANT_BOOL active_doc,
VARIANT_BOOL* cancel);
STDMETHOD_(void, OnQuit)();
STDMETHOD(Invoke)(DISPID dispid,
REFIID riid, LCID lcid,
WORD flags,
DISPPARAMS* params,
VARIANT* result,
EXCEPINFO* except_info,
UINT* arg_error);
// IChromeFrame callbacks
HRESULT OnLoad(const VARIANT* param);
HRESULT OnLoadError(const VARIANT* param);
HRESULT OnMessage(const VARIANT* param);
base::win::ScopedComPtr<IWebBrowser2> web_browser2_;
base::win::ScopedComPtr<IChromeFrame> chrome_frame_;
DispCallback<IEEventSink> onmessage_;
DispCallback<IEEventSink> onloaderror_;
DispCallback<IEEventSink> onload_;
IEEventListener* listener_;
base::ProcessId ie_process_id_;
bool did_receive_on_quit_;
static bool abnormal_shutdown_;
static _ATL_FUNC_INFO kBeforeNavigate2Info;
static _ATL_FUNC_INFO kNavigateComplete2Info;
static _ATL_FUNC_INFO kNavigateErrorInfo;
static _ATL_FUNC_INFO kNewWindow2Info;
static _ATL_FUNC_INFO kNewWindow3Info;
static _ATL_FUNC_INFO kVoidMethodInfo;
static _ATL_FUNC_INFO kDocumentCompleteInfo;
static _ATL_FUNC_INFO kFileDownloadInfo;
};
class PropertyNotifySinkImpl
: public CComObjectRootEx<CComSingleThreadModel>,
public IPropertyNotifySink {
public:
PropertyNotifySinkImpl() : listener_(NULL) {
}
BEGIN_COM_MAP(PropertyNotifySinkImpl)
COM_INTERFACE_ENTRY(IPropertyNotifySink)
END_COM_MAP()
STDMETHOD(OnChanged)(DISPID dispid) {
if (listener_)
listener_->OnChanged(dispid);
return S_OK;
}
STDMETHOD(OnRequestEdit)(DISPID dispid) {
if (listener_)
listener_->OnRequestEdit(dispid);
return S_OK;
}
void set_listener(PropertyNotifySinkListener* listener) {
DCHECK(listener_ == NULL || listener == NULL);
listener_ = listener;
}
protected:
PropertyNotifySinkListener* listener_;
};
} // namespace chrome_frame_test
#endif // CHROME_FRAME_TEST_IE_EVENT_SINK_H_
|