`
helpbs
  • 浏览: 1154651 次
文章分类
社区版块
存档分类
最新评论

使用C++实现SDK之WebBrowser容器

 
阅读更多
一.由来
还记还得当自认为学习完了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. publicIDispatch
  2. publicIOleClientSite
  3. publicIOleInPlaceSite
  4. publicIOleInPlaceFrame
每个接口需要实现的方法分别是:
  1. //IUnknownmethods
  2. virtualSTDMETHODIMPQueryInterface(REFIIDiid,void**ppvObject);
  3. virtualSTDMETHODIMP_(ULONG)AddRef();
  4. virtualSTDMETHODIMP_(ULONG)Release();
  5. //IDispatchMethods
  6. HRESULT_stdcallGetTypeInfoCount(unsignedint*pctinfo);
  7. HRESULT_stdcallGetTypeInfo(unsignedintiTInfo,LCIDlcid,ITypeInfoFAR*FAR*ppTInfo);
  8. HRESULT_stdcallGetIDsOfNames(REFIIDriid,OLECHARFAR*FAR*rgszNames,unsignedintcNames,LCIDlcid,DISPIDFAR*rgDispId);
  9. HRESULT_stdcallInvoke(DISPIDdispIdMember,REFIIDriid,LCIDlcid,WORDwFlags,DISPPARAMSFAR*pDispParams,VARIANTFAR*pVarResult,EXCEPINFOFAR*pExcepInfo,unsignedintFAR*puArgErr);
  10. //IOleClientSitemethods
  11. virtualSTDMETHODIMPSaveObject();
  12. virtualSTDMETHODIMPGetMoniker(DWORDdwA,DWORDdwW,IMoniker**pm);
  13. virtualSTDMETHODIMPGetContainer(IOleContainer**pc);
  14. virtualSTDMETHODIMPShowObject();
  15. virtualSTDMETHODIMPOnShowWindow(BOOLf);
  16. virtualSTDMETHODIMPRequestNewObjectLayout();
  17. //IOleInPlaceSitemethods
  18. virtualSTDMETHODIMPGetWindow(HWND*p);
  19. virtualSTDMETHODIMPContextSensitiveHelp(BOOL);
  20. virtualSTDMETHODIMPCanInPlaceActivate();
  21. virtualSTDMETHODIMPOnInPlaceActivate();
  22. virtualSTDMETHODIMPOnUIActivate();
  23. virtualSTDMETHODIMPGetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo);
  24. virtualSTDMETHODIMPScroll(SIZEs);
  25. virtualSTDMETHODIMPOnUIDeactivate(int);
  26. virtualSTDMETHODIMPOnInPlaceDeactivate();
  27. virtualSTDMETHODIMPDiscardUndoState();
  28. virtualSTDMETHODIMPDeactivateAndUndo();
  29. virtualSTDMETHODIMPOnPosRectChange(LPCRECT);
  30. //IOleInPlaceFramemethods
  31. virtualSTDMETHODIMPGetBorder(LPRECTl);
  32. virtualSTDMETHODIMPRequestBorderSpace(LPCBORDERWIDTHS);
  33. virtualSTDMETHODIMPSetBorderSpace(LPCBORDERWIDTHSw);
  34. virtualSTDMETHODIMPSetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTRs);
  35. virtualSTDMETHODIMPInsertMenus(HMENUh,LPOLEMENUGROUPWIDTHSx);
  36. virtualSTDMETHODIMPSetMenu(HMENUh,HOLEMENUhO,HWNDhw);
  37. virtualSTDMETHODIMPRemoveMenus(HMENUh);
  38. virtualSTDMETHODIMPSetStatusText(LPCOLESTRt);
  39. virtualSTDMETHODIMPEnableModeless(BOOLf);
  40. virtualSTDMETHODIMPTranslateAccelerator(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. BOOLbRet=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. //_bInPlaced是WebBrowser的一个私有BOOL成员,初始为false
  12. //一旦执行了OLEIVERB_INPLACEACTIVATE(就是下面的操作)后,立即设置为true,防止控件被多次放置在容器中
  13. //_GetOleObject()是WebBrowser的一个保护函数成员,他只是简单的返回_pOleObj
  14. //_pOleObj就是WB控件本身.考虑到WebBrowser是一个基本类,以后必然被其他类继承,所以使用_GetOleObject()来返回_pOleObject,来实现防止_pOleObject本身不被修改的意外.
  15. if(_bInPlaced==false)//ActivateInPlace
  16. {
  17. _bInPlaced=true;//_bInPlacedmustbesetastrue,beforeINPLACEACTIVATE,otherwise,onceDoVerb,itwouldreturnerror;
  18. _bExternalPlace=0;//lParam;
  19. _GetOleObject()->DoVerb(OLEIVERB_INPLACEACTIVATE,0,this,0,GetHWND(),&_rcWebWnd);
  20. _bInPlaced=true;
  21. }
  22. bRet=TRUE;
  23. RETURN:
  24. returnbRet;
  25. }

OpenURL(...)
  1. BOOL
  2. WebBrowser::OpenURL(VARIANT*pVarUrl)
  3. {
  4. BOOLbRet=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. returnbRet;
  16. }


三.细节
面说过,那几个接口的方法,大部分都是直接返回E_NOTIMPL和S_OK, E_FAIL.,我说大部分,说明必然有些函数需要做一些事情,而且其作用很不小, 请看官别马虎了这段. :)
IDispatch 接口中的 IUnknown 的实现实在是不必多言, 稍微说一下接口枚举:
  1. STDMETHODIMPWebBrowser::QueryInterface(REFIIDiid,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. returnS_OK;
  27. }
  28. returnE_NOINTERFACE;
  29. }

下面先说GetWindow
  1. //IOleInPlaceSitemethods
  2. STDMETHODIMPWebBrowser::GetWindow(HWND*p)
  3. {
  4. *p=GetHWND();//需要设置p为当前框架的窗口,否则Ole对象不知道框架
  5. returnS_OK;
  6. }
再来说:CanInPlaceActivate(); Ole对象会询问容器,我能不能插进来(脸红中~)? 得到准许后才能温柔的插入,粗暴是不行的哦!
  1. //IOleInPlaceSitemethods
  2. STDMETHODIMPWebBrowser::CanInPlaceActivate()//IfthisfunctionreturnS_FALSE,AXcannotactivateinplace!
  3. {
  4. if(_bInPlaced)//DoesWebBrowserControlalreadyinplaced?
  5. {
  6. _bCalledCanInPlace=true;
  7. returnS_OK;
  8. }
  9. returnS_FALSE;
  10. }
WebBrowser::GetWindowContext(...) 获取窗口上下文(内容)
  1. STDMETHODIMPWebBrowser::GetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo)
  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. returnS_OK;
  19. }
好了,下面是最后一个需要加料的函数了: IOleInPlaceFrame 接口的方法: GetBorder
注意这个接口正是上面说过的函数GetWindowContent 传递给OleObj对象的
  1. //IOleInPlaceFramemethods|
  2. STDMETHODIMPWebBrowser::GetBorder(LPRECTl)
  3. {
  4. ::GetClientRect(GetHWND(),&_rcWebWnd);
  5. *l=_rcWebWnd;
  6. returnS_OK;
  7. }
到现在为止,对于容器本身的实现已经全部完成了, 但是细心的读者会问到, GetHWND(void)还没有实现那!?
实际上,WebBrowser 作为一个基本类,不应当实现GetHWND(), 相反地, 他应当作为一个纯虚函数,要求其子类实现.
然后,我做了一个实验, 发现作为纯虚函数, 不能在类的构造函数中被调用, 或者间接调用. 而我们在WebBrowser::WebBrowser()中已经间接调用了GetHWND(),所以会有问题, 于是我们耍赖,把GetHWND(){return NULL;}
这样可以解决虚函数的问题.

四. 所有实现

WebBroser.h
  1. classWebBrowser:
  2. publicIDispatch,
  3. publicIOleClientSite,
  4. publicIOleInPlaceSite,
  5. publicIOleInPlaceFrame,
  6. publicIDocHostUIHandler
  7. {
  8. public:
  9. WebBrowser();
  10. ~WebBrowser(void);
  11. public:
  12. //IUnknownmethods
  13. virtualSTDMETHODIMPQueryInterface(REFIIDiid,void**ppvObject);
  14. virtualSTDMETHODIMP_(ULONG)AddRef();
  15. virtualSTDMETHODIMP_(ULONG)Release();
  16. //IDispatchMethods
  17. HRESULT_stdcallGetTypeInfoCount(unsignedint*pctinfo);
  18. HRESULT_stdcallGetTypeInfo(unsignedintiTInfo,LCIDlcid,ITypeInfoFAR*FAR*ppTInfo);
  19. HRESULT_stdcallGetIDsOfNames(REFIIDriid,OLECHARFAR*FAR*rgszNames,unsignedintcNames,LCIDlcid,DISPIDFAR*rgDispId);
  20. HRESULT_stdcallInvoke(DISPIDdispIdMember,REFIIDriid,LCIDlcid,WORDwFlags,DISPPARAMSFAR*pDispParams,VARIANTFAR*pVarResult,EXCEPINFOFAR*pExcepInfo,unsignedintFAR*puArgErr);
  21. //IOleClientSitemethods
  22. virtualSTDMETHODIMPSaveObject();
  23. virtualSTDMETHODIMPGetMoniker(DWORDdwA,DWORDdwW,IMoniker**pm);
  24. virtualSTDMETHODIMPGetContainer(IOleContainer**pc);
  25. virtualSTDMETHODIMPShowObject();
  26. virtualSTDMETHODIMPOnShowWindow(BOOLf);
  27. virtualSTDMETHODIMPRequestNewObjectLayout();
  28. //IOleInPlaceSitemethods
  29. virtualSTDMETHODIMPGetWindow(HWND*p);
  30. virtualSTDMETHODIMPContextSensitiveHelp(BOOL);
  31. virtualSTDMETHODIMPCanInPlaceActivate();
  32. virtualSTDMETHODIMPOnInPlaceActivate();
  33. virtualSTDMETHODIMPOnUIActivate();
  34. virtualSTDMETHODIMPGetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo);
  35. virtualSTDMETHODIMPScroll(SIZEs);
  36. virtualSTDMETHODIMPOnUIDeactivate(int);
  37. virtualSTDMETHODIMPOnInPlaceDeactivate();
  38. virtualSTDMETHODIMPDiscardUndoState();
  39. virtualSTDMETHODIMPDeactivateAndUndo();
  40. virtualSTDMETHODIMPOnPosRectChange(LPCRECT);
  41. //IOleInPlaceFramemethods
  42. virtualSTDMETHODIMPGetBorder(LPRECTl);
  43. virtualSTDMETHODIMPRequestBorderSpace(LPCBORDERWIDTHS);
  44. virtualSTDMETHODIMPSetBorderSpace(LPCBORDERWIDTHSw);
  45. virtualSTDMETHODIMPSetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTRs);
  46. virtualSTDMETHODIMPInsertMenus(HMENUh,LPOLEMENUGROUPWIDTHSx);
  47. virtualSTDMETHODIMPSetMenu(HMENUh,HOLEMENUhO,HWNDhw);
  48. virtualSTDMETHODIMPRemoveMenus(HMENUh);
  49. virtualSTDMETHODIMPSetStatusText(LPCOLESTRt);
  50. virtualSTDMETHODIMPEnableModeless(BOOLf);
  51. virtualSTDMETHODIMPTranslateAccelerator(LPMSG,WORD);
  52. protected:
  53. virtualHWNDGetHWND(){returnNULL;};//继承的类应该实现这个方法,告诉WebBrowser,到底用哪一个HWND放置WebBrowser
  54. //内部工具函数
  55. private:
  56. inlineIOleObject*_GetOleObject(){return_pOleObj;};
  57. inlineIOleInPlaceObject*_GetInPlaceObject(){return_pInPlaceObj;};
  58. //外部方法
  59. public:
  60. IWebBrowser2*GetWebBrowser2();
  61. IHTMLDocument2*GetHTMLDocument2();
  62. IHTMLDocument3*GetHTMLDocument3();
  63. IHTMLWindow2*GetHTMLWindow2();
  64. IHTMLEventObj*GetHTMLEventObject();
  65. BOOLSetWebRect(LPRECTlprc);
  66. BOOLOpenWebBrowser();
  67. BOOLOpenURL(VARIANT*pVarUrl);
  68. //内部数据
  69. protected:
  70. long_refNum;
  71. private:
  72. RECT_rcWebWnd;
  73. bool_bInPlaced;
  74. bool_bExternalPlace;
  75. bool_bCalledCanInPlace;
  76. bool_bWebWndInited;
  77. private:
  78. //指针
  79. IOleObject*_pOleObj;
  80. IOleInPlaceObject*_pInPlaceObj;
  81. IStorage*_pStorage;
  82. IWebBrowser2*_pWB2;
  83. IHTMLDocument2*_pHtmlDoc2;
  84. IHTMLDocument3*_pHtmlDoc3;
  85. IHTMLWindow2*_pHtmlWnd2;
  86. IHTMLEventObj*_pHtmlEvent;
  87. };
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. |IUnknownmethods|
  37. ==================
  38. */
  39. STDMETHODIMPWebBrowser::QueryInterface(REFIIDiid,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. returnS_OK;
  68. }
  69. returnE_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. |IDispatchMethods|
  82. =====================
  83. */
  84. HRESULT_stdcallWebBrowser::GetTypeInfoCount(
  85. unsignedint*pctinfo)
  86. {
  87. returnE_NOTIMPL;
  88. }
  89. HRESULT_stdcallWebBrowser::GetTypeInfo(
  90. unsignedintiTInfo,
  91. LCIDlcid,
  92. ITypeInfoFAR*FAR*ppTInfo)
  93. {
  94. returnE_NOTIMPL;
  95. }
  96. HRESULT_stdcallWebBrowser::GetIDsOfNames(REFIIDriid,
  97. OLECHARFAR*FAR*rgszNames,
  98. unsignedintcNames,
  99. LCIDlcid,
  100. DISPIDFAR*rgDispId)
  101. {
  102. returnE_NOTIMPL;
  103. }
  104. HRESULT_stdcallWebBrowser::Invoke(
  105. DISPIDdispIdMember,
  106. REFIIDriid,
  107. LCIDlcid,
  108. WORDwFlags,
  109. DISPPARAMS*pDispParams,
  110. VARIANT*pVarResult,
  111. EXCEPINFO*pExcepInfo,
  112. unsignedint*puArgErr)
  113. {
  114. /*货,留在以后讲,是关于DWebBrowserEvents2让人激动的实现,而且简单.
  115. //DWebBrowserEvents2
  116. if(dispIdMember==DISPID_DOCUMENTCOMPLETE)
  117. {
  118. DocumentComplete(pDispParams->rgvarg[1].pdispVal,pDispParams->rgvarg[0].pvarVal);
  119. returnS_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. returnS_OK;
  131. }
  132. */
  133. returnE_NOTIMPL;
  134. }
  135. /*
  136. ========================
  137. |IOleClientSitemethods|
  138. ========================
  139. */
  140. STDMETHODIMPWebBrowser::SaveObject()
  141. {
  142. returnS_OK;
  143. }
  144. STDMETHODIMPWebBrowser::GetMoniker(DWORDdwA,DWORDdwW,IMoniker**pm)
  145. {
  146. *pm=0;
  147. returnE_NOTIMPL;
  148. }
  149. STDMETHODIMPWebBrowser::GetContainer(IOleContainer**pc)
  150. {
  151. *pc=0;
  152. returnE_FAIL;
  153. }
  154. STDMETHODIMPWebBrowser::ShowObject()
  155. {
  156. returnS_OK;
  157. }
  158. STDMETHODIMPWebBrowser::OnShowWindow(BOOLf)
  159. {
  160. returnS_OK;
  161. }
  162. STDMETHODIMPWebBrowser::RequestNewObjectLayout()
  163. {
  164. returnS_OK;
  165. }
  166. /*
  167. =========================
  168. |IOleInPlaceSitemethods|
  169. =========================
  170. */
  171. STDMETHODIMPWebBrowser::GetWindow(HWND*p)
  172. {
  173. *p=GetHWND();
  174. returnS_OK;
  175. }
  176. STDMETHODIMPWebBrowser::ContextSensitiveHelp(BOOL)
  177. {
  178. returnE_NOTIMPL;
  179. }
  180. STDMETHODIMPWebBrowser::CanInPlaceActivate()//IfthisfunctionreturnS_FALSE,AXcannotactivateinplace!
  181. {
  182. if(_bInPlaced)//DoesWebBrowserControlalreadyinplaced?
  183. {
  184. _bCalledCanInPlace=true;
  185. returnS_OK;
  186. }
  187. returnS_FALSE;
  188. }
  189. STDMETHODIMPWebBrowser::OnInPlaceActivate()
  190. {
  191. returnS_OK;
  192. }
  193. STDMETHODIMPWebBrowser::OnUIActivate()
  194. {
  195. returnS_OK;
  196. }
  197. STDMETHODIMPWebBrowser::GetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo)
  198. {
  199. *ppFrame=(IOleInPlaceFrame*)this;
  200. AddRef();
  201. *ppDoc=NULL;
  202. ::GetClientRect(GetHWND(),&_rcWebWnd);
  203. *r1=_rcWebWnd;
  204. *r2=_rcWebWnd;
  205. o->cb=sizeof(OLEINPLACEFRAMEINFO);
  206. o->fMDIApp=false;
  207. o->hwndFrame=GetParent(GetHWND());
  208. o->haccel=0;
  209. o->cAccelEntries=0;
  210. returnS_OK;
  211. }
  212. STDMETHODIMPWebBrowser::Scroll(SIZEs)
  213. {
  214. returnE_NOTIMPL;
  215. }
  216. STDMETHODIMPWebBrowser::OnUIDeactivate(int)
  217. {
  218. returnS_OK;
  219. }
  220. STDMETHODIMPWebBrowser::OnInPlaceDeactivate()
  221. {
  222. returnS_OK;
  223. }
  224. STDMETHODIMPWebBrowser::DiscardUndoState()
  225. {
  226. returnS_OK;
  227. }
  228. STDMETHODIMPWebBrowser::DeactivateAndUndo()
  229. {
  230. returnS_OK;
  231. }
  232. STDMETHODIMPWebBrowser::OnPosRectChange(LPCRECT)
  233. {
  234. returnS_OK;
  235. }
  236. /*
  237. ==========================
  238. |IOleInPlaceFramemethods|
  239. ==========================
  240. */
  241. STDMETHODIMPWebBrowser::GetBorder(LPRECTl)
  242. {
  243. ::GetClientRect(GetHWND(),&_rcWebWnd);
  244. *l=_rcWebWnd;
  245. returnS_OK;
  246. }
  247. STDMETHODIMPWebBrowser::RequestBorderSpace(LPCBORDERWIDTHSb)
  248. {
  249. returnS_OK;
  250. }
  251. STDMETHODIMPWebBrowser::SetBorderSpace(LPCBORDERWIDTHSb)
  252. {
  253. returnS_OK;
  254. }
  255. STDMETHODIMPWebBrowser::SetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTRs)
  256. {
  257. returnS_OK;
  258. }
  259. STDMETHODIMPWebBrowser::SetStatusText(LPCOLESTRt)
  260. {
  261. returnE_NOTIMPL;
  262. }
  263. STDMETHODIMPWebBrowser::EnableModeless(BOOLf)
  264. {
  265. returnE_NOTIMPL;
  266. }
  267. STDMETHODIMPWebBrowser::TranslateAccelerator(LPMSG,WORD)
  268. {
  269. returnE_NOTIMPL;
  270. }
  271. HRESULT_stdcallWebBrowser::RemoveMenus(HMENUh)
  272. {
  273. returnE_NOTIMPL;
  274. }
  275. HRESULT_stdcallWebBrowser::InsertMenus(HMENUh,LPOLEMENUGROUPWIDTHSx)
  276. {
  277. returnE_NOTIMPL;
  278. }
  279. HRESULT_stdcallWebBrowser::SetMenu(HMENUh,HOLEMENUhO,HWNDhw)
  280. {
  281. returnE_NOTIMPL;
  282. }
  283. /*
  284. ====================
  285. |DWebBrowserEvents2|
  286. ====================
  287. */
  288. /*货,以后再讲
  289. void
  290. WebBrowser::DocumentComplete(IDispatch*pDisp,VARIANT*URL)
  291. {
  292. //老天保佑,多好的函数啊.
  293. return;
  294. }
  295. void
  296. WebBrowser::BeforeNavigate2(IDispatch*pDisp,VARIANT*&url,VARIANT*&Flags,VARIANT*&TargetFrameName,VARIANT*&PostData,VARIANT*&Headers,VARIANT_BOOL*&Cancel)
  297. {
  298. PCWSTRpcwApp=L"app:";
  299. if(url->vt!=VT_BSTR)
  300. return;
  301. if(0==_wcsnicmp(pcwApp,url->bstrVal,wcslen(pcwApp)))
  302. {
  303. *Cancel=VARIANT_TRUE;
  304. _OnHtmlCmd(url->bstrVal+wcslen(pcwApp));
  305. return;
  306. }
  307. *Cancel=VARIANT_FALSE;
  308. }
  309. */
  310. /*
  311. =====================
  312. |IDocHostUIHandler|
  313. =====================
  314. */
  315. /*
  316. 传说中的IDocHostUIHanler,同样留在以后讲
  317. HRESULTWebBrowser::ShowContextMenu(
  318. DWORDdwID,
  319. POINT*ppt,
  320. IUnknown*pcmdtReserved,
  321. IDispatch*pdispReserved){returnE_NOTIMPL;}
  322. HRESULTWebBrowser::GetHostInfo(
  323. DOCHOSTUIINFO*pInfo){returnE_NOTIMPL;}
  324. HRESULTWebBrowser::ShowUI(
  325. DWORDdwID,
  326. IOleInPlaceActiveObject*pActiveObject,
  327. IOleCommandTarget*pCommandTarget,
  328. IOleInPlaceFrame*pFrame,
  329. IOleInPlaceUIWindow*pDoc){returnE_NOTIMPL;}
  330. HRESULTWebBrowser::HideUI(void){returnE_NOTIMPL;}
  331. HRESULTWebBrowser::UpdateUI(void){returnE_NOTIMPL;}
  332. //HRESULTWebBrowser::EnableModeless(
  333. //BOOLfEnable){returnE_NOTIMPL;}
  334. HRESULTWebBrowser::OnDocWindowActivate(
  335. BOOLfActivate){returnE_NOTIMPL;}
  336. HRESULTWebBrowser::OnFrameWindowActivate(
  337. BOOLfActivate){returnE_NOTIMPL;}
  338. HRESULTWebBrowser::ResizeBorder(
  339. LPCRECTprcBorder,
  340. IOleInPlaceUIWindow*pUIWindow,
  341. BOOLfRameWindow){returnE_NOTIMPL;}
  342. HRESULTWebBrowser::TranslateAccelerator(
  343. LPMSGlpMsg,
  344. constGUID*pguidCmdGroup,
  345. DWORDnCmdID){returnE_NOTIMPL;}
  346. HRESULTWebBrowser::GetOptionKeyPath(
  347. LPOLESTR*pchKey,
  348. DWORDdw){returnE_NOTIMPL;}
  349. HRESULTWebBrowser::GetDropTarget(
  350. IDropTarget*pDropTarget,
  351. IDropTarget**ppDropTarget)
  352. {
  353. returnE_NOTIMPL;//使用默认拖拽
  354. //returnS_OK;//自定义拖拽
  355. }
  356. HRESULTWebBrowser::GetExternal(IDispatch**ppDispatch)
  357. {
  358. returnE_NOTIMPL;
  359. }
  360. HRESULTWebBrowser::TranslateUrl(
  361. DWORDdwTranslate,
  362. OLECHAR*pchURLIn,
  363. OLECHAR**ppchURLOut){returnE_NOTIMPL;}
  364. HRESULTWebBrowser::FilterDataObject(
  365. IDataObject*pDO,
  366. IDataObject**ppDORet){returnE_NOTIMPL;}
  367. */
  368. /*
  369. ===============
  370. |OtherMethods|
  371. ===============
  372. */
  373. IWebBrowser2*
  374. WebBrowser::GetWebBrowser2()
  375. {
  376. if(_pWB2!=NULL)
  377. return_pWB2;
  378. NULLTEST_SE(_pOleObj,L"Ole对象为空");
  379. HRTEST_SE(_pOleObj->QueryInterface(IID_IWebBrowser2,(void**)&_pWB2),L"QueryInterfaceIID_IWebBrowser2失败");
  380. return_pWB2;
  381. RETURN:
  382. returnNULL;
  383. }
  384. IHTMLDocument2*
  385. WebBrowser::GetHTMLDocument2()
  386. {
  387. if(_pHtmlDoc2!=NULL)
  388. return_pHtmlDoc2;
  389. IWebBrowser2*pWB2=NULL;
  390. NULLTEST(pWB2=GetWebBrowser2());//GetWebBrowser2已经将错误原因交给LastError.
  391. IDispatch*pDp=NULL;
  392. HRTEST_SE(pWB2->get_Document(&pDp),L"DWebBrowser2::get_Document错误");
  393. HRTEST_SE(pDp->QueryInterface(IID_IHTMLDocument2,(void**)&_pHtmlDoc2),L"QueryInterfaceIID_IHTMLDocument2失败");
  394. return_pHtmlDoc2;
  395. RETURN:
  396. returnNULL;
  397. }
  398. IHTMLDocument3*
  399. WebBrowser::GetHTMLDocument3()
  400. {
  401. if(_pHtmlDoc3!=NULL)
  402. return_pHtmlDoc3;
  403. IWebBrowser2*pWB2=NULL;
  404. NULLTEST(pWB2=GetWebBrowser2());//GetWebBrowser2已经将错误原因交给LastError.
  405. IDispatch*pDp=NULL;
  406. HRTEST_SE(pWB2->get_Document(&pDp),L"DWebBrowser2::get_Document错误");
  407. HRTEST_SE(pDp->QueryInterface(IID_IHTMLDocument3,(void**)&_pHtmlDoc3),L"QueryInterfaceIID_IHTMLDocument3失败");
  408. return_pHtmlDoc3;
  409. RETURN:
  410. returnNULL;
  411. }
  412. IHTMLWindow2*
  413. WebBrowser::GetHTMLWindow2()
  414. {
  415. if(_pHtmlWnd2!=NULL)
  416. return_pHtmlWnd2;
  417. IHTMLDocument2*pHD2=GetHTMLDocument2();
  418. NULLTEST(pHD2);
  419. HRTEST_SE(pHD2->get_parentWindow(&_pHtmlWnd2),L"IHTMLWindow2::get_parentWindow错误");
  420. return_pHtmlWnd2;
  421. RETURN:
  422. returnNULL;
  423. }
  424. IHTMLEventObj*
  425. WebBrowser::GetHTMLEventObject()
  426. {
  427. if(_pHtmlEvent!=NULL)
  428. return_pHtmlEvent;
  429. IHTMLWindow2*pHW2;
  430. NULLTEST(pHW2=GetHTMLWindow2());
  431. HRTEST_SE(pHW2->get_event(&_pHtmlEvent),L"IHTMLWindow2::get_event错误");
  432. return_pHtmlEvent;
  433. RETURN:
  434. returnNULL;
  435. }
  436. BOOL
  437. WebBrowser::SetWebRect(LPRECTlprc)
  438. {
  439. BOOLbRet=FALSE;
  440. if(false==_bInPlaced)//尚未OpenWebBrowser操作,直接写入_rcWebWnd
  441. {
  442. _rcWebWnd=*lprc;
  443. }
  444. else//已经打开WebBrowser,通过IOleInPlaceObject::SetObjectRects调整大小
  445. {
  446. SIZELsize;
  447. size.cx=RECTWIDTH(*lprc);
  448. size.cy=RECTHEIGHT(*lprc);
  449. IOleObject*pOleObj;
  450. NULLTEST(pOleObj=_GetOleObject());
  451. HRTEST_E(pOleObj->SetExtent(1,&size),L"SetExtent错误");
  452. IOleInPlaceObject*pInPlace;
  453. NULLTEST(pInPlace=_GetInPlaceObject());
  454. HRTEST_E(pInPlace->SetObjectRects(lprc,lprc),L"SetObjectRects错误");
  455. _rcWebWnd=*lprc;
  456. }
  457. bRet=TRUE;
  458. RETURN:
  459. returnbRet;
  460. }
  461. BOOL
  462. WebBrowser::OpenWebBrowser()
  463. {
  464. BOOLbRet=FALSE;
  465. NULLTEST_E(_GetOleObject(),L"ActiveX对象为空");//对于本身的实现函数,其自身承担错误录入工作
  466. if((RECTWIDTH(_rcWebWnd)&&RECTHEIGHT(_rcWebWnd))==0)
  467. ::GetClientRect(GetHWND(),&_rcWebWnd);//设置WebBrowser的大小为窗口的客户区大小.
  468. if(_bInPlaced==false)//ActivateInPlace
  469. {
  470. _bInPlaced=true;//_bInPlacedmustbesetastrue,beforeINPLACEACTIVATE,otherwise,onceDoVerb,itwouldreturnerror;
  471. _bExternalPlace=0;//lParam;
  472. HRTEST_E(_GetOleObject()->DoVerb(OLEIVERB_INPLACEACTIVATE,0,this,0,GetHWND(),&_rcWebWnd),L"关于INPLACE的DoVerb错误");
  473. _bInPlaced=true;
  474. //*挂接DWebBrwoser2Event
  475. IConnectionPointContainer*pCPC=NULL;
  476. IConnectionPoint*pCP=NULL;
  477. HRTEST_E(GetWebBrowser2()->QueryInterface(IID_IConnectionPointContainer,(void**)&pCPC),L"枚举IConnectionPointContainer接口失败");
  478. HRTEST_E(pCPC->FindConnectionPoint(DIID_DWebBrowserEvents2,&pCP),L"FindConnectionPoint失败");
  479. DWORDdwCookie=0;
  480. HRTEST_E(pCP->Advise((IUnknown*)(void*)this,&dwCookie),L"IConnectionPoint::Advise失败");
  481. }
  482. bRet=TRUE;
  483. RETURN:
  484. returnbRet;
  485. }
  486. BOOL
  487. WebBrowser::OpenURL(VARIANT*pVarUrl)
  488. {
  489. BOOLbRet=FALSE;
  490. HRTEST_E(GetWebBrowser2()->Navigate2(pVarUrl,0,0,0,0),L"GetWebBrowser2失败");
  491. bRet=TRUE;
  492. RETURN:
  493. returnbRet;
  494. }
五.例子
  1. classWebBrowserWindow:
  2. publicWebBrowser
  3. {
  4. public:
  5. WebBrowserWindow(void);
  6. ~WebBrowserWindow(void);
  7. public:
  8. virtualHWNDGetHWND(){returnYourWindow};
  9. private:
  10. LRESULTOnCreate(WPARAMwParam,LPARAMlParam);
  11. //您可以在OnCreate中调用OpenWebBrowser然后调用OpenURL
  12. };

六.下期预告,如果有的话
如果有人感兴趣的话, 以后会说道如何扩展WebBrowser, 让他包罗万象, 你会发现很简单.
如果有问题,欢迎提问. 谢谢.
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics