Home | History | Annotate | Download | only in test
      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