zoukankan      html  css  js  c++  java
  • 使用C++实现SDK之WebBrowser容器

    转自http://blog.csdn.net/norsd/article/details/2921389

    一.由来

             我还记还得当自认为学习完了C++语法后, 兴致勃勃的打开MFC向导,开始所谓"MFC高级自动化编程"时, 我不由喊道: 这他妈的都是些什么乱七八糟的东西啊.诚然,MFC为了方便愚蠢的程序员,的确是让人瞬间高级编程, 可是愚蠢的我们还是会用CString strTest;写出(PWSTR)strTest.GetBuffer() 这种自作聪明的用法,结果就是整个程序好像发了疯.
             终于有一天,我大喊一声: 滚蛋吧,MFC!
             太阳当空照,上帝对 我笑:  你Y去写个有WebBrowser控件的窗口吧
    二.结构
              MFC的HTMLDialog 是一个魔盒, 他容易上手,可是却很难深入,究其缘由, 私以为无外乎MFC包装的太好, 不识庐山真面目,只缘身在此山中.  总是以为作为C类型的程序员,喜欢深入原理是职业特性.
            于是首先看到有强人写的纯C实现WebBrowser控件,他在这里: http://www.codeproject.com/KB/COM/cwebpage.aspx 这位同志很好的展示了在没有C++的支持下,支持ActiveX是多么痛苦的一件事情...........汗. 在下觉得,撇开C++的类的特性,虚拟特性,重载特性,而去用纯C实现,实在有点过犹不及,当然这种练习修炼内功很好,但是实际应用上显得麻烦.毕竟,ActiveX很好的使用了C++的特性,而不是C的特性.
            接着,开始使用纯SDK编写容器. 读者可以搜索csdn中关于SDK实现WebBrowser容器的帖子, 许多人说那是非常繁琐复杂.所谓人云亦云,各位看官不妨跟着我一试,且看到底何如?
           WebBrowser容器的实现需要许多接口, 也许正是这吓退了许多人, 实际情况是,许多接口的方法没几个需要实现,大部分只需要直接返回E_NOTIMPL和S_OK, E_FAIL.
           让我们命名我们编写的容器叫 WebBrowser (可能名字有点糊涂,但是因为源代码中就是这个名字,所以就不改了,大家只需要注意,这个是一个WebBrowser控件的容器 ),   在实现这个容器后, 我们把他作为一个窗口类的父类,这样 就能实现WebBrowser的页面窗口.
          首先一个WB( WebBrowser) 容器需要以下接口:
    1.     public IDispatch
    2.     public IOleClientSite
    3.     public IOleInPlaceSite
    4.     public IOleInPlaceFrame
           每个接口需要实现的方法分别是:
    1.         // IUnknown methods
    2.     virtual STDMETHODIMP QueryInterface(REFIID iid,void**ppvObject);
    3.     virtual STDMETHODIMP_(ULONG) AddRef();
    4.     virtual STDMETHODIMP_(ULONG) Release();
    5.     // IDispatch Methods
    6.     HRESULT _stdcall GetTypeInfoCount(unsigned int * pctinfo);
    7.     HRESULT _stdcall GetTypeInfo(unsigned int iTInfo,LCID lcid,ITypeInfo FAR* FAR* ppTInfo);
    8.     HRESULT _stdcall GetIDsOfNames(REFIID riid,OLECHAR FAR* FAR* rgszNames,unsigned int cNames,LCID lcid,DISPID FAR* rgDispId);
    9.     HRESULT _stdcall Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS FAR* pDispParams,VARIANT FAR* pVarResult,EXCEPINFO FAR* pExcepInfo,unsigned int FAR* puArgErr);
    10.     // IOleClientSite methods
    11.     virtual STDMETHODIMP SaveObject();
    12.     virtual STDMETHODIMP GetMoniker(DWORD dwA,DWORD dwW,IMoniker**pm);
    13.     virtual STDMETHODIMP GetContainer(IOleContainer**pc);
    14.     virtual STDMETHODIMP ShowObject();
    15.     virtual STDMETHODIMP OnShowWindow(BOOL f);
    16.     virtual STDMETHODIMP RequestNewObjectLayout();
    17.     // IOleInPlaceSite methods
    18.     virtual STDMETHODIMP GetWindow(HWND *p);
    19.     virtual STDMETHODIMP ContextSensitiveHelp(BOOL);
    20.     virtual STDMETHODIMP CanInPlaceActivate();
    21.     virtual STDMETHODIMP OnInPlaceActivate();
    22.     virtual STDMETHODIMP OnUIActivate();
    23.     virtual STDMETHODIMP GetWindowContext(IOleInPlaceFrame** ppFrame,IOleInPlaceUIWindow **ppDoc,LPRECT r1,LPRECT r2,LPOLEINPLACEFRAMEINFO o);
    24.     virtual STDMETHODIMP Scroll(SIZE s);
    25.     virtual STDMETHODIMP OnUIDeactivate(int);
    26.     virtual STDMETHODIMP OnInPlaceDeactivate();
    27.     virtual STDMETHODIMP DiscardUndoState();
    28.     virtual STDMETHODIMP DeactivateAndUndo();
    29.     virtual STDMETHODIMP OnPosRectChange(LPCRECT);
    30.     // IOleInPlaceFrame methods
    31.     virtual STDMETHODIMP GetBorder(LPRECT l);
    32.     virtual STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS);
    33.     virtual STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS w);
    34.     virtual STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTR s);
    35.     virtual STDMETHODIMP InsertMenus(HMENU h,LPOLEMENUGROUPWIDTHS x);
    36.     virtual STDMETHODIMP SetMenu(HMENU h,HOLEMENU hO,HWND hw);
    37.     virtual STDMETHODIMP RemoveMenus(HMENU h);
    38.     virtual STDMETHODIMP SetStatusText(LPCOLESTR t);
    39.     virtual STDMETHODIMP EnableModeless(BOOL f);
    40.     virtual STDMETHODIMP TranslateAccelerator(LPMSG,WORD);
       这里插几句题外话, 我讨厌看文章, 因为萝莉罗嗦也没看到那个爆炸点, 就是你看到他,一下子思路有了头绪, 不再是一头雾水了.可惜,我看到的大部分文章都不是这样, 为了避免这个问题, 我在这里放个屁, 嗯,也算是一个小小的爆破吧.
          好,上面已经罗列了需要的接口和接口的方法.  
          要想实现WB的容器,你必须有这段代码:
    1. WebBrowser::WebBrowser()
    2. {
    3.   //初始化OLE
    4.   OleInitialize(0);
    5.   //创建IStorage对象,其中_pStorage是WebBrowser的私有变量
    6.   StgCreateDocfile(0,STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_CREATE,0,&_pStorage);
    7.   //创建IOleObject对象,我们看到,短短的一条语句,已经几乎创建完成了WebBrowser!
    8.   //this在这里时表示当前类(即WebBrowser)作为容器,承载_pOleObj这个控件 
    9.   //这里就是放屁现场了,大家好好看看哈.   
    10.  OleCreate( CLSID_WebBrowser,IID_IOleObject,OLERENDER_DRAW, 0 , this, _pStorage, (void**)&_pOleObj );
    11.   //获得IOleInPlaceObject对象
    12.   _pOleObj->QueryInterface(IID_IOleInPlaceObject,(LPVOID*)&_pInPlaceObj);
    13. }
    上面一段代码已经创建了wb的Ole对象, 接下来,你只需要打开WB,然后打开网页.我们用两个函数实现,他们是OpenWebBrowser() 和 OpenURL( VARIANT* pVarUrl )
     
    OpenWebBrowser:
    1. BOOL    
    2. WebBrowser::OpenWebBrowser()
    3. {
    4.     BOOL bRet = FALSE;
    5.     // RECTWIDTH 和 RECTHEIGHT 是计算RECT长宽的宏函数
    6.     // _rcWebWnd 是WebBrowser的私有RECT成员,就是GetHWND()的大小.
    7.     // 下面的语句就是关联两者
    8.     // GetHWND()获取容器的框架窗口句柄,就是我们创建的窗口,关于这个函数,下面会单独讲
    9.     if( (RECTWIDTH(_rcWebWnd) && RECTHEIGHT(_rcWebWnd)) == 0 )
    10.     ::GetClientRect( GetHWND() ,&_rcWebWnd);//设置WebBrowser的大小为窗口的客户区大小.
    11.     
    12.     // _bInPlaced 是WebBrowser的一个私有BOOL成员,初始为false
    13.     // 一旦执行了OLEIVERB_INPLACEACTIVATE (就是下面的操作)后,立即设置为true,防止控件被多次放置在容器中
    14.     // _GetOleObject()是WebBrowser的一个保护函数成员,他只是简单的返回_pOleObj
    15.     // _pOleObj就是WB控件本身. 考虑到WebBrowser是一个基本类,以后必然被其他类继承,所以使用_GetOleObject()来返回_pOleObject,来实现防止_pOleObject本身不被修改的意外.
    16.     if( _bInPlaced == false )// Activate In Place
    17.     {
    18.       _bInPlaced = true;//_bInPlaced must be set as true, before INPLACEACTIVATE, otherwise, once DoVerb, it would return error;
    19.       _bExternalPlace = 0;//lParam;
    20.       _GetOleObject()->DoVerb(OLEIVERB_INPLACEACTIVATE,0,this,0, GetHWND(),&_rcWebWnd);
    21.       _bInPlaced = true;
    22.     }
    23.     bRet = TRUE;
    24. RETURN:
    25.     return bRet;
    26. }
     
    OpenURL(...)
    1. BOOL    
    2. WebBrowser::OpenURL(VARIANT* pVarUrl)
    3. {
    4.     BOOL bRet = FALSE;
    5.         //GetWebBrowser2 返回IWebBrowser2
    6.         //他的实现是这样的:
    7.         //if( _pWB2 != NULL )//_pWB2是WebBrowser的私有IWebBrowser2指针
    8.     //   return _pWB2;//如果_pWB2已经不是NULL,即已经获取过内容,则直接返回
    9.         ////否则使用WB控件对象枚举IWebBrowser2指针
    10.     //_pOleObj->QueryInterface(IID_IWebBrowser2,(void**)&_pWB2);
    11.         //return _pWB2;
    12.     GetWebBrowser2()->Navigate2( pVarUrl,0,0,0,0);//打开网页
    13.     bRet = TRUE;
    14. RETURN:
    15.     return bRet;
    16. }

     
    三.细节
             前面说过,那几个接口的方法,大部分都是直接返回E_NOTIMPL和S_OK, E_FAIL.,我说大部分,说明必然有些函数需要做一些事情,而且其作用很不小, 请看官别马虎了这段. :)
            IDispatch 接口中的 IUnknown 的实现实在是不必多言, 稍微说一下接口枚举:
    1. STDMETHODIMP WebBrowser::QueryInterface(REFIID iid,void**ppvObject)
    2. {
    3.     *ppvObject = 0;
    4.     if ( iid == IID_IOleClientSite )
    5.         *ppvObject = (IOleClientSite*)this;
    6.     if ( iid == IID_IUnknown )
    7.         *ppvObject = this;
    8.     if ( iid == IID_IDispatch )
    9.         *ppvObject = (IDispatch*)this;
    10.     if ( _bExternalPlace == false)
    11.     {
    12.         if ( iid == IID_IOleInPlaceSite )
    13.             *ppvObject = (IOleInPlaceSite*)this;
    14.         if ( iid == IID_IOleInPlaceFrame )
    15.             *ppvObject = (IOleInPlaceFrame*)this;
    16.         if ( iid == IID_IOleInPlaceUIWindow )
    17.             *ppvObject = (IOleInPlaceUIWindow*)this;
    18.     }
    19.     if ( iid == DIID_DWebBrowserEvents2 )
    20.         *ppvObject = (DWebBrowserEvents2 *)this;
    21.     if ( iid == IID_IDocHostUIHandler)
    22.         *ppvObject = (IDocHostUIHandler*)this;
    23.     if ( *ppvObject )
    24.     {
    25.         AddRef();
    26.         return S_OK;
    27.     }
    28.     return E_NOINTERFACE;
    29. }
     
     
            下面先说GetWindow
    1. //IOleInPlaceSite methods
    2. STDMETHODIMP WebBrowser::GetWindow(HWND *p)
    3. {
    4.     *p = GetHWND();//需要设置p为当前框架的窗口,否则Ole对象不知道框架
    5.     return S_OK;
    6. }
           再来说: CanInPlaceActivate(); Ole对象会询问容器,我能不能插进来(脸红中~)? 得到准许后才能温柔的插入,粗暴是不行的哦!
    1. //IOleInPlaceSite methods
    2. STDMETHODIMP WebBrowser::CanInPlaceActivate()//If this function return S_FALSE, AX cannot activate in place!
    3. {
    4.     if ( _bInPlaced )//Does WebBrowser Control already in placed?
    5.     {
    6.         _bCalledCanInPlace = true;
    7.         return S_OK;
    8.     }
    9.     return S_FALSE;
    10. }
             WebBrowser::GetWindowContext(...) 获取窗口上下文(内容)
    1. STDMETHODIMP WebBrowser::GetWindowContext(IOleInPlaceFrame** ppFrame,IOleInPlaceUIWindow **ppDoc,LPRECT r1,LPRECT r2,LPOLEINPLACEFRAMEINFO o)
    2. {
    3.     //因为IOleInPlaceFrame接口已经被我们的WebBrowser实现
    4.         //所以直接设置为this
    5.     *ppFrame = (IOleInPlaceFrame*)this;
    6.     AddRef();
    7.     *ppDoc = NULL;
    8.         // r1, r2设置为框架的大小, 让WB充满整个窗口
    9.     ::GetClientRect(  GetHWND() ,&_rcWebWnd );
    10.     *r1 = _rcWebWnd;
    11.     *r2 = _rcWebWnd;
    12.         //我们没有这方面的要求,所以仅仅初始化.
    13.     o->cb = sizeof(OLEINPLACEFRAMEINFO);
    14.     o->fMDIApp = false;
    15.     o->hwndFrame = GetParent( GetHWND() );
    16.     o->haccel = 0;
    17.     o->cAccelEntries = 0;
    18.     
    19.     return S_OK;
    20. }
            好了,下面是最后一个需要加料的函数了: IOleInPlaceFrame 接口的方法: GetBorder
            注意这个接口正是上面说过的函数GetWindowContent 传递给OleObj对象的
    1. //IOleInPlaceFrame methods|
    2. STDMETHODIMP WebBrowser::GetBorder(LPRECT l)
    3. {
    4.     ::GetClientRect(  GetHWND() ,&_rcWebWnd );
    5.     *l = _rcWebWnd;
    6.     return S_OK;
    7. }
            到现在为止,对于容器本身的实现已经全部完成了, 但是细心的读者会问到, GetHWND(void)还没有实现那!?
            实际上,WebBrowser 作为一个基本类,不应当实现GetHWND(), 相反地, 他应当作为一个纯虚函数,要求其子类实现.
            然后,我做了一个实验, 发现作为纯虚函数, 不能在类的构造函数中被调用, 或者间接调用. 而我们在WebBrowser::WebBrowser()中已经间接调用了GetHWND(),所以会有问题, 于是我们耍赖,把GetHWND(){return NULL;}
    这样可以解决虚函数的问题.
     
    四. 所有实现
     
    WebBroser.h
    1. class WebBrowser:
    2.     public IDispatch,
    3.     public IOleClientSite,
    4.     public IOleInPlaceSite,
    5.     public IOleInPlaceFrame,
    6.     public IDocHostUIHandler
    7. {
    8. public:
    9.     WebBrowser();
    10.     ~WebBrowser(void);
    11.     public:
    12.     // IUnknown methods
    13.     virtual STDMETHODIMP QueryInterface(REFIID iid,void**ppvObject);
    14.     virtual STDMETHODIMP_(ULONG) AddRef();
    15.     virtual STDMETHODIMP_(ULONG) Release();
    16.     // IDispatch Methods
    17.     HRESULT _stdcall GetTypeInfoCount(unsigned int * pctinfo);
    18.     HRESULT _stdcall GetTypeInfo(unsigned int iTInfo,LCID lcid,ITypeInfo FAR* FAR* ppTInfo);
    19.     HRESULT _stdcall GetIDsOfNames(REFIID riid,OLECHAR FAR* FAR* rgszNames,unsigned int cNames,LCID lcid,DISPID FAR* rgDispId);
    20.     HRESULT _stdcall Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS FAR* pDispParams,VARIANT FAR* pVarResult,EXCEPINFO FAR* pExcepInfo,unsigned int FAR* puArgErr);
    21.     // IOleClientSite methods
    22.     virtual STDMETHODIMP SaveObject();
    23.     virtual STDMETHODIMP GetMoniker(DWORD dwA,DWORD dwW,IMoniker**pm);
    24.     virtual STDMETHODIMP GetContainer(IOleContainer**pc);
    25.     virtual STDMETHODIMP ShowObject();
    26.     virtual STDMETHODIMP OnShowWindow(BOOL f);
    27.     virtual STDMETHODIMP RequestNewObjectLayout();
    28.     // IOleInPlaceSite methods
    29.     virtual STDMETHODIMP GetWindow(HWND *p);
    30.     virtual STDMETHODIMP ContextSensitiveHelp(BOOL);
    31.     virtual STDMETHODIMP CanInPlaceActivate();
    32.     virtual STDMETHODIMP OnInPlaceActivate();
    33.     virtual STDMETHODIMP OnUIActivate();
    34.     virtual STDMETHODIMP GetWindowContext(IOleInPlaceFrame** ppFrame,IOleInPlaceUIWindow **ppDoc,LPRECT r1,LPRECT r2,LPOLEINPLACEFRAMEINFO o);
    35.     virtual STDMETHODIMP Scroll(SIZE s);
    36.     virtual STDMETHODIMP OnUIDeactivate(int);
    37.     virtual STDMETHODIMP OnInPlaceDeactivate();
    38.     virtual STDMETHODIMP DiscardUndoState();
    39.     virtual STDMETHODIMP DeactivateAndUndo();
    40.     virtual STDMETHODIMP OnPosRectChange(LPCRECT);
    41.     // IOleInPlaceFrame methods
    42.     virtual STDMETHODIMP GetBorder(LPRECT l);
    43.     virtual STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS);
    44.     virtual STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS w);
    45.     virtual STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTR s);
    46.     virtual STDMETHODIMP InsertMenus(HMENU h,LPOLEMENUGROUPWIDTHS x);
    47.     virtual STDMETHODIMP SetMenu(HMENU h,HOLEMENU hO,HWND hw);
    48.     virtual STDMETHODIMP RemoveMenus(HMENU h);
    49.     virtual STDMETHODIMP SetStatusText(LPCOLESTR t);
    50.     virtual STDMETHODIMP EnableModeless(BOOL f);
    51.     virtual STDMETHODIMP TranslateAccelerator(LPMSG,WORD);
    52. protected:
    53.     virtual HWND GetHWND(){return NULL;};//继承的类应该实现这个方法,告诉WebBrowser,到底用哪一个HWND放置WebBrowser
    54.     // 内部工具函数
    55. private:
    56.     inline IOleObject* _GetOleObject(){return _pOleObj;};
    57.     inline IOleInPlaceObject* _GetInPlaceObject(){return _pInPlaceObj;};
    58.     //外部方法
    59. public:
    60.     IWebBrowser2*      GetWebBrowser2();
    61.     IHTMLDocument2*    GetHTMLDocument2();
    62.     IHTMLDocument3*    GetHTMLDocument3();
    63.     IHTMLWindow2*      GetHTMLWindow2();
    64.     IHTMLEventObj*     GetHTMLEventObject();
    65.     
    66.     BOOL       SetWebRect(LPRECT lprc);
    67.     BOOL       OpenWebBrowser();
    68.         BOOL       OpenURL(VARIANT* pVarUrl);
    69.     
    70.     // 内部数据
    71. protected:
    72.     long   _refNum;
    73. private:
    74.     RECT  _rcWebWnd;
    75.     bool  _bInPlaced;
    76.     bool  _bExternalPlace;
    77.     bool  _bCalledCanInPlace;
    78.     bool  _bWebWndInited;
    79. private:
    80.     //指针
    81.     IOleObject*                 _pOleObj; 
    82.     IOleInPlaceObject*          _pInPlaceObj;
    83.     IStorage*                   _pStorage;
    84.     IWebBrowser2*               _pWB2;
    85.     IHTMLDocument2*             _pHtmlDoc2;
    86.     IHTMLDocument3*             _pHtmlDoc3;
    87.     IHTMLWindow2*               _pHtmlWnd2;
    88.     IHTMLEventObj*              _pHtmlEvent;
    89. };
    WebBrowser.cpp
    注意: 里面有许多讨厌的东西,  是我加的饲料. 解释一下,我个人很喜欢这种错误处理方式.
     
    读者可以简单的认为: (因为实际上我的实现不是那么简单,因为这个再说就有点复杂,所以简单化)
    NULLTEST_SE( fn , wstr ) ;          如果 fn == 0 , 则显示 wstr, 并且跳转到RETURN
    HRTEST_SE( fn, wstr);                  如果 fn!=S_OK ,则显示wstr,并且跳转到RETURN
     
    另外,考虑到WebBrowser以后总是作为另外一个类的父类,所以他完全不会因为计数器归零而自删除.
     
    1. #include "WebBrowser.h"
    2. /*
    3. ==================
    4. |   构造和析构   |
    5. ==================
    6. */
    7. WebBrowser::WebBrowser(void):
    8. _refNum(0),
    9. //_rcWebWnd(0),
    10. _bInPlaced(false),
    11. _bExternalPlace(false),
    12. _bCalledCanInPlace(false),
    13. _bWebWndInited(false),
    14. _pOleObj(NULL), 
    15. _pInPlaceObj(NULL), 
    16. _pStorage(NULL), 
    17. _pWB2(NULL), 
    18. _pHtmlDoc2(NULL), 
    19. _pHtmlDoc3(NULL), 
    20. _pHtmlWnd2(NULL), 
    21. _pHtmlEvent(NULL)
    22. {
    23.     ::memset( (PVOID)&_rcWebWnd,0,sizeof(_rcWebWnd));
    24.     HRTEST_SE( OleInitialize(0),L"Ole初始化错误");
    25.     HRTEST_SE( StgCreateDocfile(0,STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_CREATE,0,&_pStorage),L"StgCreateDocfile错误");
    26.     HRTEST_SE( OleCreate(CLSID_WebBrowser,IID_IOleObject,OLERENDER_DRAW,0,this,_pStorage,(void**)&_pOleObj),L"Ole创建失败");
    27.     HRTEST_SE( _pOleObj->QueryInterface(IID_IOleInPlaceObject,(LPVOID*)&_pInPlaceObj),L"OleInPlaceObject创建失败");
    28. RETURN:
    29.     return;
    30. }
    31. WebBrowser::~WebBrowser(void)
    32. {
    33. }
    34. /*
    35. ==================
    36. |IUnknown methods|
    37. ==================
    38. */
    39. STDMETHODIMP WebBrowser::QueryInterface(REFIID iid,void**ppvObject)
    40. {
    41.     *ppvObject = 0;
    42.     if ( iid == IID_IOleClientSite )
    43.         *ppvObject = (IOleClientSite*)this;
    44.     if ( iid == IID_IUnknown )
    45.         *ppvObject = this;
    46.     if ( iid == IID_IDispatch )
    47.         *ppvObject = (IDispatch*)this;
    48.     if ( _bExternalPlace == false)
    49.     {
    50.         if ( iid == IID_IOleInPlaceSite )
    51.             *ppvObject = (IOleInPlaceSite*)this;
    52.         if ( iid == IID_IOleInPlaceFrame )
    53.             *ppvObject = (IOleInPlaceFrame*)this;
    54.         if ( iid == IID_IOleInPlaceUIWindow )
    55.             *ppvObject = (IOleInPlaceUIWindow*)this;
    56.     }
    57.         /*
    58.         这里是一点走私货, 留在以后讲,如果有机会,你可以发现,原来如此简单.
    59.     if ( iid == DIID_DWebBrowserEvents2 )
    60.         *ppvObject = (DWebBrowserEvents2 *)this;
    61.     if ( iid == IID_IDocHostUIHandler)
    62.         *ppvObject = (IDocHostUIHandler*)this;
    63.         */
    64.     if ( *ppvObject )
    65.     {
    66.         AddRef();
    67.         return S_OK;
    68.     }
    69.     return E_NOINTERFACE;
    70. }
    71. STDMETHODIMP_(ULONG)  WebBrowser::AddRef()
    72. {
    73.     return ::InterlockedIncrement( &_refNum );
    74. }
    75. STDMETHODIMP_(ULONG)  WebBrowser::Release()
    76. {
    77.     return ::InterlockedDecrement( &_refNum );
    78. }
    79. /*
    80. =====================
    81. | IDispatch Methods |
    82. =====================
    83. */
    84. HRESULT _stdcall WebBrowser::GetTypeInfoCount(
    85.     unsigned int * pctinfo) 
    86. {
    87.     return E_NOTIMPL;
    88. }
    89. HRESULT _stdcall WebBrowser::GetTypeInfo(
    90.     unsigned int iTInfo,
    91.     LCID lcid,
    92.     ITypeInfo FAR* FAR* ppTInfo) 
    93. {
    94.     return E_NOTIMPL;
    95. }
    96. HRESULT _stdcall WebBrowser::GetIDsOfNames(REFIID riid, 
    97.   OLECHAR FAR* FAR* rgszNames, 
    98.   unsigned int cNames, 
    99.   LCID lcid, 
    100.   DISPID FAR* rgDispId )
    101. {
    102.     return E_NOTIMPL;
    103. }
    104. HRESULT _stdcall WebBrowser::Invoke(
    105.     DISPID dispIdMember,
    106.     REFIID riid,
    107.     LCID lcid,
    108.     WORD wFlags,
    109.     DISPPARAMS* pDispParams,
    110.     VARIANT* pVarResult,
    111.     EXCEPINFO* pExcepInfo,
    112.     unsigned int* puArgErr)
    113. {
    114.         /*走私货,留在以后讲,是关于DWebBrowserEvents2让人激动的实现,而且简单.
    115.     // DWebBrowserEvents2
    116.     if( dispIdMember == DISPID_DOCUMENTCOMPLETE)
    117.     {
    118.         DocumentComplete(pDispParams->rgvarg[1].pdispVal,pDispParams->rgvarg[0].pvarVal);
    119.         return S_OK;
    120.     }
    121.     if( dispIdMember == DISPID_BEFORENAVIGATE2)
    122.     {
    123.         BeforeNavigate2( pDispParams->rgvarg[6].pdispVal,
    124.                          pDispParams->rgvarg[5].pvarVal,
    125.                          pDispParams->rgvarg[4].pvarVal,
    126.                          pDispParams->rgvarg[3].pvarVal,
    127.                          pDispParams->rgvarg[2].pvarVal,
    128.                          pDispParams->rgvarg[1].pvarVal,
    129.                          pDispParams->rgvarg[0].pboolVal);
    130.         return S_OK;
    131.     }
    132.         */
    133.     return E_NOTIMPL;
    134. }
    135. /*
    136. ========================
    137. |IOleClientSite methods|
    138. ========================
    139. */
    140. STDMETHODIMP WebBrowser::SaveObject()
    141. {
    142.     return S_OK;
    143. }
    144. STDMETHODIMP WebBrowser::GetMoniker(DWORD dwA,DWORD dwW,IMoniker**pm)
    145. {
    146.     *pm = 0;
    147.     return E_NOTIMPL;
    148. }
    149. STDMETHODIMP WebBrowser::GetContainer(IOleContainer**pc)
    150. {
    151.     *pc = 0;
    152.     return E_FAIL;
    153. }
    154. STDMETHODIMP WebBrowser::ShowObject()
    155. {
    156.     return S_OK;
    157. }
    158. STDMETHODIMP WebBrowser::OnShowWindow(BOOL f)
    159. {
    160.     return S_OK;
    161. }
    162. STDMETHODIMP WebBrowser::RequestNewObjectLayout()
    163. {
    164.     return S_OK;
    165. }
    166. /*
    167. =========================
    168. |IOleInPlaceSite methods|
    169. =========================
    170. */
    171. STDMETHODIMP WebBrowser::GetWindow(HWND *p)
    172. {
    173.     *p = GetHWND();
    174.     return S_OK;
    175. }
    176. STDMETHODIMP WebBrowser::ContextSensitiveHelp(BOOL)
    177. {
    178.     return E_NOTIMPL;
    179. }
    180. STDMETHODIMP WebBrowser::CanInPlaceActivate()//If this function return S_FALSE, AX cannot activate in place!
    181. {
    182.     if ( _bInPlaced )//Does WebBrowser Control already in placed?
    183.     {
    184.         _bCalledCanInPlace = true;
    185.         return S_OK;
    186.     }
    187.     return S_FALSE;
    188. }
    189. STDMETHODIMP WebBrowser::OnInPlaceActivate()
    190. {
    191.     return S_OK;
    192. }
    193. STDMETHODIMP WebBrowser::OnUIActivate()
    194. {
    195.     return S_OK;
    196. }
    197. STDMETHODIMP WebBrowser::GetWindowContext(IOleInPlaceFrame** ppFrame,IOleInPlaceUIWindow **ppDoc,LPRECT r1,LPRECT r2,LPOLEINPLACEFRAMEINFO o)
    198. {
    199.     
    200.     *ppFrame = (IOleInPlaceFrame*)this;
    201.     AddRef();
    202.     *ppDoc = NULL;
    203.     ::GetClientRect(  GetHWND() ,&_rcWebWnd );
    204.     *r1 = _rcWebWnd;
    205.     *r2 = _rcWebWnd;
    206.     o->cb = sizeof(OLEINPLACEFRAMEINFO);
    207.     o->fMDIApp = false;
    208.     o->hwndFrame = GetParent( GetHWND() );
    209.     o->haccel = 0;
    210.     o->cAccelEntries = 0;
    211.     
    212.     return S_OK;
    213. }
    214. STDMETHODIMP WebBrowser::Scroll(SIZE s)
    215. {
    216.     return E_NOTIMPL;
    217. }
    218. STDMETHODIMP WebBrowser::OnUIDeactivate(int)
    219. {
    220.     return S_OK;
    221. }
    222. STDMETHODIMP WebBrowser::OnInPlaceDeactivate()
    223. {
    224.     return S_OK;
    225. }
    226. STDMETHODIMP WebBrowser::DiscardUndoState()
    227. {
    228.     return S_OK;
    229. }
    230. STDMETHODIMP WebBrowser::DeactivateAndUndo()
    231. {
    232.     return S_OK;
    233. }
    234. STDMETHODIMP WebBrowser::OnPosRectChange(LPCRECT)
    235. {
    236.     return S_OK;
    237. }
    238. /*
    239. ==========================
    240. |IOleInPlaceFrame methods|
    241. ==========================
    242. */
    243. STDMETHODIMP WebBrowser::GetBorder(LPRECT l)
    244. {
    245.     ::GetClientRect(  GetHWND() ,&_rcWebWnd );
    246.     *l = _rcWebWnd;
    247.     return S_OK;
    248. }
    249. STDMETHODIMP WebBrowser::RequestBorderSpace(LPCBORDERWIDTHS b)
    250. {
    251.     return S_OK;
    252. }
    253. STDMETHODIMP WebBrowser::SetBorderSpace(LPCBORDERWIDTHS b)
    254. {
    255.     return S_OK;
    256. }
    257. STDMETHODIMP WebBrowser::SetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTR s)
    258. {
    259.     return S_OK;
    260. }
    261. STDMETHODIMP WebBrowser::SetStatusText(LPCOLESTR t)
    262. {
    263.     return E_NOTIMPL;
    264. }
    265. STDMETHODIMP WebBrowser::EnableModeless(BOOL f)
    266. {
    267.     return E_NOTIMPL;
    268. }
    269. STDMETHODIMP WebBrowser::TranslateAccelerator(LPMSG,WORD)
    270. {
    271.     return E_NOTIMPL;
    272. }
    273. HRESULT _stdcall WebBrowser::RemoveMenus(HMENU h)
    274. {
    275.     return E_NOTIMPL;
    276. }
    277. HRESULT _stdcall WebBrowser::InsertMenus(HMENU h,LPOLEMENUGROUPWIDTHS x)
    278. {
    279.     return E_NOTIMPL;
    280. }
    281. HRESULT _stdcall WebBrowser::SetMenu(HMENU h,HOLEMENU hO,HWND hw)
    282. {
    283.     return E_NOTIMPL;
    284. }
    285. /*
    286. ====================
    287. |DWebBrowserEvents2|
    288. ====================
    289. */
    290. /* 走私货,以后再讲
    291. void 
    292. WebBrowser::DocumentComplete( IDispatch *pDisp,VARIANT *URL)
    293. {
    294.         //老天保佑,多好的函数啊.
    295.     return ;
    296. }
    297. void 
    298. WebBrowser::BeforeNavigate2( IDispatch *pDisp,VARIANT *&url,VARIANT *&Flags,VARIANT *&TargetFrameName,VARIANT *&PostData,VARIANT *&Headers,VARIANT_BOOL *&Cancel)
    299. {
    300.     PCWSTR pcwApp = L"app:";
    301.     if( url->vt != VT_BSTR )
    302.         return;
    303.     if( 0 == _wcsnicmp( pcwApp, url->bstrVal,wcslen(pcwApp)) )
    304.     {
    305.         *Cancel = VARIANT_TRUE;
    306.         _OnHtmlCmd( url->bstrVal+wcslen(pcwApp) );
    307.         return;
    308.     }
    309.     *Cancel = VARIANT_FALSE;
    310. }
    311. */
    312. /*
    313. =====================
    314. | IDocHostUIHandler |
    315. =====================
    316. */
    317. /*
    318. 传说中的IDocHostUIHanler,同样留在以后讲
    319. HRESULT WebBrowser:: ShowContextMenu( 
    320.     DWORD dwID,
    321.     POINT *ppt,
    322.     IUnknown *pcmdtReserved,
    323.     IDispatch *pdispReserved){return E_NOTIMPL;}
    324. HRESULT WebBrowser:: GetHostInfo( 
    325.                                         DOCHOSTUIINFO *pInfo){return E_NOTIMPL;}
    326. HRESULT WebBrowser:: ShowUI( 
    327.                                    DWORD dwID,
    328.                                    IOleInPlaceActiveObject *pActiveObject,
    329.                                    IOleCommandTarget *pCommandTarget,
    330.                                    IOleInPlaceFrame *pFrame,
    331.                                    IOleInPlaceUIWindow *pDoc){return E_NOTIMPL;}
    332. HRESULT WebBrowser:: HideUI( void){return E_NOTIMPL;}
    333. HRESULT WebBrowser:: UpdateUI( void){return E_NOTIMPL;}
    334. //HRESULT WebBrowser:: EnableModeless( 
    335. //  BOOL fEnable){return E_NOTIMPL;}
    336. HRESULT WebBrowser:: OnDocWindowActivate( 
    337.     BOOL fActivate){return E_NOTIMPL;}
    338. HRESULT WebBrowser:: OnFrameWindowActivate( 
    339.     BOOL fActivate){return E_NOTIMPL;}
    340. HRESULT WebBrowser:: ResizeBorder( 
    341.     LPCRECT prcBorder,
    342.     IOleInPlaceUIWindow *pUIWindow,
    343.     BOOL fRameWindow){return E_NOTIMPL;}
    344. HRESULT WebBrowser:: TranslateAccelerator( 
    345.     LPMSG lpMsg,
    346.     const GUID *pguidCmdGroup,
    347.     DWORD nCmdID){return E_NOTIMPL;}
    348. HRESULT WebBrowser:: GetOptionKeyPath( 
    349.     LPOLESTR *pchKey,
    350.     DWORD dw){return E_NOTIMPL;}
    351. HRESULT WebBrowser:: GetDropTarget( 
    352.     IDropTarget *pDropTarget,
    353.     IDropTarget **ppDropTarget)
    354. {
    355.     return E_NOTIMPL;//使用默认拖拽
    356.     //return S_OK;//自定义拖拽
    357. }
    358. HRESULT WebBrowser:: GetExternal( IDispatch **ppDispatch)
    359. {
    360.     return E_NOTIMPL;
    361. }
    362. HRESULT WebBrowser:: TranslateUrl( 
    363.     DWORD dwTranslate,
    364.     OLECHAR *pchURLIn,
    365.     OLECHAR **ppchURLOut){return E_NOTIMPL;}
    366. HRESULT WebBrowser:: FilterDataObject( 
    367.     IDataObject *pDO,
    368.     IDataObject **ppDORet){return E_NOTIMPL;}
    369. */
    370. /*
    371. ===============
    372. |Other Methods|
    373. ===============
    374. */
    375. IWebBrowser2* 
    376. WebBrowser::GetWebBrowser2()
    377. {
    378.     if( _pWB2 != NULL )
    379.         return _pWB2;
    380.     NULLTEST_SE( _pOleObj,L"Ole对象为空");
    381.     HRTEST_SE( _pOleObj->QueryInterface(IID_IWebBrowser2,(void**)&_pWB2),L"QueryInterface IID_IWebBrowser2 失败");
    382.     return _pWB2;
    383. RETURN:
    384.     return NULL;
    385. }
    386. IHTMLDocument2*    
    387. WebBrowser::GetHTMLDocument2()
    388. {
    389.     if( _pHtmlDoc2 != NULL )
    390.         return _pHtmlDoc2;
    391.     IWebBrowser2* pWB2 = NULL;
    392.     NULLTEST(pWB2 = GetWebBrowser2());//GetWebBrowser2已经将错误原因交给LastError.
    393.     IDispatch* pDp =  NULL;
    394.     HRTEST_SE(pWB2->get_Document(&pDp),L"DWebBrowser2::get_Document 错误");
    395.     HRTEST_SE(pDp->QueryInterface(IID_IHTMLDocument2,(void**)&_pHtmlDoc2),L"QueryInterface IID_IHTMLDocument2 失败");
    396.     return _pHtmlDoc2;
    397. RETURN:
    398.     return NULL;
    399. }
    400. IHTMLDocument3*    
    401. WebBrowser::GetHTMLDocument3()
    402. {
    403.     if( _pHtmlDoc3 != NULL )
    404.         return _pHtmlDoc3;
    405.     IWebBrowser2* pWB2 = NULL;
    406.     NULLTEST(pWB2 = GetWebBrowser2());//GetWebBrowser2已经将错误原因交给LastError.
    407.     IDispatch* pDp =  NULL;
    408.     HRTEST_SE(pWB2->get_Document(&pDp),L"DWebBrowser2::get_Document 错误");
    409.     HRTEST_SE(pDp->QueryInterface(IID_IHTMLDocument3,(void**)&_pHtmlDoc3),L"QueryInterface IID_IHTMLDocument3 失败");
    410.     return _pHtmlDoc3;
    411. RETURN:
    412.     return NULL;
    413. }
    414. IHTMLWindow2*
    415. WebBrowser::GetHTMLWindow2()
    416. {
    417.     if( _pHtmlWnd2 != NULL)
    418.         return _pHtmlWnd2;
    419.     IHTMLDocument2*  pHD2 = GetHTMLDocument2();
    420.     NULLTEST( pHD2 );
    421.     HRTEST_SE( pHD2->get_parentWindow(&_pHtmlWnd2),L"IHTMLWindow2::get_parentWindow 错误" );
    422.     return _pHtmlWnd2;
    423. RETURN:
    424.     return NULL;
    425. }
    426. IHTMLEventObj*   
    427. WebBrowser::GetHTMLEventObject()
    428. {
    429.     if( _pHtmlEvent != NULL )
    430.         return _pHtmlEvent;
    431.     IHTMLWindow2* pHW2;
    432.     NULLTEST( pHW2 = GetHTMLWindow2() );
    433.     HRTEST_SE( pHW2->get_event(&_pHtmlEvent),L"IHTMLWindow2::get_event 错误");
    434.     return _pHtmlEvent;
    435. RETURN:
    436.     return NULL;
    437. }
    438. BOOL       
    439. WebBrowser::SetWebRect(LPRECT lprc)
    440. {
    441.     BOOL bRet = FALSE;
    442.     if( false == _bInPlaced )//尚未OpenWebBrowser操作,直接写入_rcWebWnd
    443.     {
    444.        _rcWebWnd = *lprc;
    445.     }
    446.     else//已经打开WebBrowser,通过 IOleInPlaceObject::SetObjectRects 调整大小
    447.     {
    448.         SIZEL size;
    449.         size.cx = RECTWIDTH(*lprc);
    450.         size.cy = RECTHEIGHT(*lprc);
    451.         IOleObject* pOleObj;
    452.         NULLTEST( pOleObj= _GetOleObject());
    453.         HRTEST_E( pOleObj->SetExtent(  1,&size ),L"SetExtent 错误");
    454.         IOleInPlaceObject* pInPlace;
    455.         NULLTEST( pInPlace = _GetInPlaceObject());
    456.         HRTEST_E( pInPlace->SetObjectRects(lprc,lprc),L"SetObjectRects 错误");
    457.         _rcWebWnd = *lprc;
    458.     }
    459.     bRet = TRUE;
    460. RETURN:
    461.     return bRet;
    462. }
    463. BOOL    
    464. WebBrowser::OpenWebBrowser()
    465. {
    466.     BOOL bRet = FALSE;
    467.     NULLTEST_E( _GetOleObject(),L"ActiveX对象为空" );//对于本身的实现函数,其自身承担错误录入工作
    468.     
    469.     if( (RECTWIDTH(_rcWebWnd) && RECTHEIGHT(_rcWebWnd)) == 0 )
    470.         ::GetClientRect( GetHWND() ,&_rcWebWnd);//设置WebBrowser的大小为窗口的客户区大小.
    471.     
    472.     if( _bInPlaced == false )// Activate In Place
    473.     {
    474.         _bInPlaced = true;//_bInPlaced must be set as true, before INPLACEACTIVATE, otherwise, once DoVerb, it would return error;
    475.         _bExternalPlace = 0;//lParam;
    476.     
    477.         HRTEST_E( _GetOleObject()->DoVerb(OLEIVERB_INPLACEACTIVATE,0,this,0, GetHWND()  ,&_rcWebWnd),L"关于INPLACE的DoVerb错误");
    478.         _bInPlaced = true;
    479.         
    480.         
    481.         //* 挂接DWebBrwoser2Event
    482.         IConnectionPointContainer* pCPC = NULL;
    483.         IConnectionPoint*          pCP  = NULL;
    484.         HRTEST_E( GetWebBrowser2()->QueryInterface(IID_IConnectionPointContainer,(void**)&pCPC),L"枚举IConnectionPointContainer接口失败");
    485.         HRTEST_E( pCPC->FindConnectionPoint( DIID_DWebBrowserEvents2,&pCP),L"FindConnectionPoint失败");
    486.         DWORD dwCookie = 0;
    487.         HRTEST_E( pCP->Advise( (IUnknown*)(void*)this,&dwCookie),L"IConnectionPoint::Advise失败");
    488.     }
    489.     bRet = TRUE;
    490. RETURN:
    491.     return bRet;
    492. }
    493. BOOL    
    494. WebBrowser::OpenURL(VARIANT* pVarUrl)
    495. {
    496.     BOOL bRet = FALSE;
    497.     HRTEST_E( GetWebBrowser2()->Navigate2( pVarUrl,0,0,0,0),L"GetWebBrowser2 失败");
    498.     bRet = TRUE;
    499. RETURN:
    500.     return bRet;
    501. }
    五.例子
         
    1. class WebBrowserWindow :
    2.     public WebBrowser
    3. {
    4. public:
    5.     WebBrowserWindow(void);
    6.     ~WebBrowserWindow(void);
    7. public:
    8.     virtual HWND GetHWND(){ return YourWindow};
    9. private:
    10.     LRESULT OnCreate( WPARAM wParam,LPARAM lParam);
    11.     //您可以在OnCreate中调用OpenWebBrowser 然后调用 OpenURL
    12. };
     
    六.下期预告,如果有的话
          如果有人感兴趣的话, 以后会说道如何扩展WebBrowser, 让他包罗万象, 你会发现很简单.
          如果有问题,欢迎提问. 谢谢.
  • 相关阅读:
    S4全球总决赛(2)南邮NOJ2059
    S4全球总决赛(2)南邮NOJ2059
    S4全球总决赛(1) 南邮NOJ
    S4全球总决赛(1) 南邮NOJ
    S4全球总决赛(1) 南邮NOJ
    【Linux】鸟哥的Linux私房菜基础学习篇整理(五)
    【Linux】鸟哥的Linux私房菜基础学习篇整理(四)
    【HDOJ】2428 Stars
    【Linux】鸟哥的Linux私房菜基础学习篇整理(三)
    【Linux】鸟哥的Linux私房菜基础学习篇整理(二)
  • 原文地址:https://www.cnblogs.com/dps001/p/4381502.html
Copyright © 2011-2022 走看看