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