一.由来
我还记还得当自认为学习完了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) 容器需要以下接口:
- publicIDispatch
- publicIOleClientSite
- publicIOleInPlaceSite
- publicIOleInPlaceFrame
- //IUnknownmethods
- virtualSTDMETHODIMPQueryInterface(REFIIDiid,void**ppvObject);
- virtualSTDMETHODIMP_(ULONG)AddRef();
- virtualSTDMETHODIMP_(ULONG)Release();
- //IDispatchMethods
- HRESULT_stdcallGetTypeInfoCount(unsignedint*pctinfo);
- HRESULT_stdcallGetTypeInfo(unsignedintiTInfo,LCIDlcid,ITypeInfoFAR*FAR*ppTInfo);
- HRESULT_stdcallGetIDsOfNames(REFIIDriid,OLECHARFAR*FAR*rgszNames,unsignedintcNames,LCIDlcid,DISPIDFAR*rgDispId);
- HRESULT_stdcallInvoke(DISPIDdispIdMember,REFIIDriid,LCIDlcid,WORDwFlags,DISPPARAMSFAR*pDispParams,VARIANTFAR*pVarResult,EXCEPINFOFAR*pExcepInfo,unsignedintFAR*puArgErr);
- //IOleClientSitemethods
- virtualSTDMETHODIMPSaveObject();
- virtualSTDMETHODIMPGetMoniker(DWORDdwA,DWORDdwW,IMoniker**pm);
- virtualSTDMETHODIMPGetContainer(IOleContainer**pc);
- virtualSTDMETHODIMPShowObject();
- virtualSTDMETHODIMPOnShowWindow(BOOLf);
- virtualSTDMETHODIMPRequestNewObjectLayout();
- //IOleInPlaceSitemethods
- virtualSTDMETHODIMPGetWindow(HWND*p);
- virtualSTDMETHODIMPContextSensitiveHelp(BOOL);
- virtualSTDMETHODIMPCanInPlaceActivate();
- virtualSTDMETHODIMPOnInPlaceActivate();
- virtualSTDMETHODIMPOnUIActivate();
- virtualSTDMETHODIMPGetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo);
- virtualSTDMETHODIMPScroll(SIZEs);
- virtualSTDMETHODIMPOnUIDeactivate(int);
- virtualSTDMETHODIMPOnInPlaceDeactivate();
- virtualSTDMETHODIMPDiscardUndoState();
- virtualSTDMETHODIMPDeactivateAndUndo();
- virtualSTDMETHODIMPOnPosRectChange(LPCRECT);
- //IOleInPlaceFramemethods
- virtualSTDMETHODIMPGetBorder(LPRECTl);
- virtualSTDMETHODIMPRequestBorderSpace(LPCBORDERWIDTHS);
- virtualSTDMETHODIMPSetBorderSpace(LPCBORDERWIDTHSw);
- virtualSTDMETHODIMPSetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTRs);
- virtualSTDMETHODIMPInsertMenus(HMENUh,LPOLEMENUGROUPWIDTHSx);
- virtualSTDMETHODIMPSetMenu(HMENUh,HOLEMENUhO,HWNDhw);
- virtualSTDMETHODIMPRemoveMenus(HMENUh);
- virtualSTDMETHODIMPSetStatusText(LPCOLESTRt);
- virtualSTDMETHODIMPEnableModeless(BOOLf);
- virtualSTDMETHODIMPTranslateAccelerator(LPMSG,WORD);
这里插几句题外话, 我讨厌看文章, 因为萝莉罗嗦也没看到那个爆炸点, 就是你看到他,一下子思路有了头绪, 不再是一头雾水了.可惜,我看到的大部分文章都不是这样, 为了避免这个问题, 我在这里放个屁, 嗯,也算是一个小小的爆破吧.
好,上面已经罗列了需要的接口和接口的方法.
要想实现WB的容器,你必须有这段代码:
- WebBrowser::WebBrowser()
- {
- //初始化OLE
- OleInitialize(0);
- //创建IStorage对象,其中_pStorage是WebBrowser的私有变量
- StgCreateDocfile(0,STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DIRECT|STGM_CREATE,0,&_pStorage);
- //创建IOleObject对象,我们看到,短短的一条语句,已经几乎创建完成了WebBrowser!
- //this在这里时表示当前类(即WebBrowser)作为容器,承载_pOleObj这个控件
- //这里就是放屁现场了,大家好好看看哈.
- OleCreate( CLSID_WebBrowser,IID_IOleObject,OLERENDER_DRAW, 0 , this, _pStorage, (void**)&_pOleObj );
- //获得IOleInPlaceObject对象
- _pOleObj->QueryInterface(IID_IOleInPlaceObject,(LPVOID*)&_pInPlaceObj);
- }
OpenWebBrowser:
- BOOL
- WebBrowser::OpenWebBrowser()
- {
- BOOLbRet=FALSE;
- //RECTWIDTH和RECTHEIGHT是计算RECT长宽的宏函数
- //_rcWebWnd是WebBrowser的私有RECT成员,就是GetHWND()的大小.
- //下面的语句就是关联两者
- //GetHWND()获取容器的框架窗口句柄,就是我们创建的窗口,关于这个函数,下面会单独讲
- if((RECTWIDTH(_rcWebWnd)&&RECTHEIGHT(_rcWebWnd))==0)
- ::GetClientRect(GetHWND(),&_rcWebWnd);//设置WebBrowser的大小为窗口的客户区大小.
- //_bInPlaced是WebBrowser的一个私有BOOL成员,初始为false
- //一旦执行了OLEIVERB_INPLACEACTIVATE(就是下面的操作)后,立即设置为true,防止控件被多次放置在容器中
- //_GetOleObject()是WebBrowser的一个保护函数成员,他只是简单的返回_pOleObj
- //_pOleObj就是WB控件本身.考虑到WebBrowser是一个基本类,以后必然被其他类继承,所以使用_GetOleObject()来返回_pOleObject,来实现防止_pOleObject本身不被修改的意外.
- if(_bInPlaced==false)//ActivateInPlace
- {
- _bInPlaced=true;//_bInPlacedmustbesetastrue,beforeINPLACEACTIVATE,otherwise,onceDoVerb,itwouldreturnerror;
- _bExternalPlace=0;//lParam;
- _GetOleObject()->DoVerb(OLEIVERB_INPLACEACTIVATE,0,this,0,GetHWND(),&_rcWebWnd);
- _bInPlaced=true;
- }
- bRet=TRUE;
- RETURN:
- returnbRet;
- }
OpenURL(...)
- BOOL
- WebBrowser::OpenURL(VARIANT*pVarUrl)
- {
- BOOLbRet=FALSE;
- //GetWebBrowser2返回IWebBrowser2
- //他的实现是这样的:
- //if(_pWB2!=NULL)//_pWB2是WebBrowser的私有IWebBrowser2指针
- //return_pWB2;//如果_pWB2已经不是NULL,即已经获取过内容,则直接返回
- 否则使用WB控件对象枚举IWebBrowser2指针
- //_pOleObj->QueryInterface(IID_IWebBrowser2,(void**)&_pWB2);
- //return_pWB2;
- GetWebBrowser2()->Navigate2(pVarUrl,0,0,0,0);//打开网页
- bRet=TRUE;
- RETURN:
- returnbRet;
- }
三.细节
前面说过,那几个接口的方法,大部分都是直接返回E_NOTIMPL和S_OK, E_FAIL.,我说大部分,说明必然有些函数需要做一些事情,而且其作用很不小, 请看官别马虎了这段. :)
IDispatch 接口中的 IUnknown 的实现实在是不必多言, 稍微说一下接口枚举:
- STDMETHODIMPWebBrowser::QueryInterface(REFIIDiid,void**ppvObject)
- {
- *ppvObject=0;
- if(iid==IID_IOleClientSite)
- *ppvObject=(IOleClientSite*)this;
- if(iid==IID_IUnknown)
- *ppvObject=this;
- if(iid==IID_IDispatch)
- *ppvObject=(IDispatch*)this;
- if(_bExternalPlace==false)
- {
- if(iid==IID_IOleInPlaceSite)
- *ppvObject=(IOleInPlaceSite*)this;
- if(iid==IID_IOleInPlaceFrame)
- *ppvObject=(IOleInPlaceFrame*)this;
- if(iid==IID_IOleInPlaceUIWindow)
- *ppvObject=(IOleInPlaceUIWindow*)this;
- }
- if(iid==DIID_DWebBrowserEvents2)
- *ppvObject=(DWebBrowserEvents2*)this;
- if(iid==IID_IDocHostUIHandler)
- *ppvObject=(IDocHostUIHandler*)this;
- if(*ppvObject)
- {
- AddRef();
- returnS_OK;
- }
- returnE_NOINTERFACE;
- }
下面先说GetWindow
- //IOleInPlaceSitemethods
- STDMETHODIMPWebBrowser::GetWindow(HWND*p)
- {
- *p=GetHWND();//需要设置p为当前框架的窗口,否则Ole对象不知道框架
- returnS_OK;
- }
- //IOleInPlaceSitemethods
- STDMETHODIMPWebBrowser::CanInPlaceActivate()//IfthisfunctionreturnS_FALSE,AXcannotactivateinplace!
- {
- if(_bInPlaced)//DoesWebBrowserControlalreadyinplaced?
- {
- _bCalledCanInPlace=true;
- returnS_OK;
- }
- returnS_FALSE;
- }
- STDMETHODIMPWebBrowser::GetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo)
- {
- //因为IOleInPlaceFrame接口已经被我们的WebBrowser实现
- //所以直接设置为this
- *ppFrame=(IOleInPlaceFrame*)this;
- AddRef();
- *ppDoc=NULL;
- //r1,r2设置为框架的大小,让WB充满整个窗口
- ::GetClientRect(GetHWND(),&_rcWebWnd);
- *r1=_rcWebWnd;
- *r2=_rcWebWnd;
- //我们没有这方面的要求,所以仅仅初始化.
- o->cb=sizeof(OLEINPLACEFRAMEINFO);
- o->fMDIApp=false;
- o->hwndFrame=GetParent(GetHWND());
- o->haccel=0;
- o->cAccelEntries=0;
- returnS_OK;
- }
注意这个接口正是上面说过的函数GetWindowContent 传递给OleObj对象的
- //IOleInPlaceFramemethods|
- STDMETHODIMPWebBrowser::GetBorder(LPRECTl)
- {
- ::GetClientRect(GetHWND(),&_rcWebWnd);
- *l=_rcWebWnd;
- returnS_OK;
- }
实际上,WebBrowser 作为一个基本类,不应当实现GetHWND(), 相反地, 他应当作为一个纯虚函数,要求其子类实现.
然后,我做了一个实验, 发现作为纯虚函数, 不能在类的构造函数中被调用, 或者间接调用. 而我们在WebBrowser::WebBrowser()中已经间接调用了GetHWND(),所以会有问题, 于是我们耍赖,把GetHWND(){return NULL;}
这样可以解决虚函数的问题.
四. 所有实现
WebBroser.h
- classWebBrowser:
- publicIDispatch,
- publicIOleClientSite,
- publicIOleInPlaceSite,
- publicIOleInPlaceFrame,
- publicIDocHostUIHandler
- {
- public:
- WebBrowser();
- ~WebBrowser(void);
- public:
- //IUnknownmethods
- virtualSTDMETHODIMPQueryInterface(REFIIDiid,void**ppvObject);
- virtualSTDMETHODIMP_(ULONG)AddRef();
- virtualSTDMETHODIMP_(ULONG)Release();
- //IDispatchMethods
- HRESULT_stdcallGetTypeInfoCount(unsignedint*pctinfo);
- HRESULT_stdcallGetTypeInfo(unsignedintiTInfo,LCIDlcid,ITypeInfoFAR*FAR*ppTInfo);
- HRESULT_stdcallGetIDsOfNames(REFIIDriid,OLECHARFAR*FAR*rgszNames,unsignedintcNames,LCIDlcid,DISPIDFAR*rgDispId);
- HRESULT_stdcallInvoke(DISPIDdispIdMember,REFIIDriid,LCIDlcid,WORDwFlags,DISPPARAMSFAR*pDispParams,VARIANTFAR*pVarResult,EXCEPINFOFAR*pExcepInfo,unsignedintFAR*puArgErr);
- //IOleClientSitemethods
- virtualSTDMETHODIMPSaveObject();
- virtualSTDMETHODIMPGetMoniker(DWORDdwA,DWORDdwW,IMoniker**pm);
- virtualSTDMETHODIMPGetContainer(IOleContainer**pc);
- virtualSTDMETHODIMPShowObject();
- virtualSTDMETHODIMPOnShowWindow(BOOLf);
- virtualSTDMETHODIMPRequestNewObjectLayout();
- //IOleInPlaceSitemethods
- virtualSTDMETHODIMPGetWindow(HWND*p);
- virtualSTDMETHODIMPContextSensitiveHelp(BOOL);
- virtualSTDMETHODIMPCanInPlaceActivate();
- virtualSTDMETHODIMPOnInPlaceActivate();
- virtualSTDMETHODIMPOnUIActivate();
- virtualSTDMETHODIMPGetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo);
- virtualSTDMETHODIMPScroll(SIZEs);
- virtualSTDMETHODIMPOnUIDeactivate(int);
- virtualSTDMETHODIMPOnInPlaceDeactivate();
- virtualSTDMETHODIMPDiscardUndoState();
- virtualSTDMETHODIMPDeactivateAndUndo();
- virtualSTDMETHODIMPOnPosRectChange(LPCRECT);
- //IOleInPlaceFramemethods
- virtualSTDMETHODIMPGetBorder(LPRECTl);
- virtualSTDMETHODIMPRequestBorderSpace(LPCBORDERWIDTHS);
- virtualSTDMETHODIMPSetBorderSpace(LPCBORDERWIDTHSw);
- virtualSTDMETHODIMPSetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTRs);
- virtualSTDMETHODIMPInsertMenus(HMENUh,LPOLEMENUGROUPWIDTHSx);
- virtualSTDMETHODIMPSetMenu(HMENUh,HOLEMENUhO,HWNDhw);
- virtualSTDMETHODIMPRemoveMenus(HMENUh);
- virtualSTDMETHODIMPSetStatusText(LPCOLESTRt);
- virtualSTDMETHODIMPEnableModeless(BOOLf);
- virtualSTDMETHODIMPTranslateAccelerator(LPMSG,WORD);
- protected:
- virtualHWNDGetHWND(){returnNULL;};//继承的类应该实现这个方法,告诉WebBrowser,到底用哪一个HWND放置WebBrowser
- //内部工具函数
- private:
- inlineIOleObject*_GetOleObject(){return_pOleObj;};
- inlineIOleInPlaceObject*_GetInPlaceObject(){return_pInPlaceObj;};
- //外部方法
- public:
- IWebBrowser2*GetWebBrowser2();
- IHTMLDocument2*GetHTMLDocument2();
- IHTMLDocument3*GetHTMLDocument3();
- IHTMLWindow2*GetHTMLWindow2();
- IHTMLEventObj*GetHTMLEventObject();
- BOOLSetWebRect(LPRECTlprc);
- BOOLOpenWebBrowser();
- BOOLOpenURL(VARIANT*pVarUrl);
- //内部数据
- protected:
- long_refNum;
- private:
- RECT_rcWebWnd;
- bool_bInPlaced;
- bool_bExternalPlace;
- bool_bCalledCanInPlace;
- bool_bWebWndInited;
- private:
- //指针
- IOleObject*_pOleObj;
- IOleInPlaceObject*_pInPlaceObj;
- IStorage*_pStorage;
- IWebBrowser2*_pWB2;
- IHTMLDocument2*_pHtmlDoc2;
- IHTMLDocument3*_pHtmlDoc3;
- IHTMLWindow2*_pHtmlWnd2;
- IHTMLEventObj*_pHtmlEvent;
- };
注意: 里面有许多讨厌的东西, 是我加的饲料. 解释一下,我个人很喜欢这种错误处理方式.
读者可以简单的认为: (因为实际上我的实现不是那么简单,因为这个再说就有点复杂,所以简单化)
NULLTEST_SE( fn , wstr ) ; 如果 fn == 0 , 则显示 wstr, 并且跳转到RETURN
HRTEST_SE( fn, wstr); 如果 fn!=S_OK ,则显示wstr,并且跳转到RETURN
另外,考虑到WebBrowser以后总是作为另外一个类的父类,所以他完全不会因为计数器归零而自删除.
- #include"WebBrowser.h"
- /*
- ==================
- |构造和析构|
- ==================
- */
- WebBrowser::WebBrowser(void):
- _refNum(0),
- //_rcWebWnd(0),
- _bInPlaced(false),
- _bExternalPlace(false),
- _bCalledCanInPlace(false),
- _bWebWndInited(false),
- _pOleObj(NULL),
- _pInPlaceObj(NULL),
- _pStorage(NULL),
- _pWB2(NULL),
- _pHtmlDoc2(NULL),
- _pHtmlDoc3(NULL),
- _pHtmlWnd2(NULL),
- _pHtmlEvent(NULL)
- {
- ::memset((PVOID)&_rcWebWnd,0,sizeof(_rcWebWnd));
- HRTEST_SE(OleInitialize(0),L"Ole初始化错误");
- HRTEST_SE(StgCreateDocfile(0,STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DIRECT|STGM_CREATE,0,&_pStorage),L"StgCreateDocfile错误");
- HRTEST_SE(OleCreate(CLSID_WebBrowser,IID_IOleObject,OLERENDER_DRAW,0,this,_pStorage,(void**)&_pOleObj),L"Ole创建失败");
- HRTEST_SE(_pOleObj->QueryInterface(IID_IOleInPlaceObject,(LPVOID*)&_pInPlaceObj),L"OleInPlaceObject创建失败");
- RETURN:
- return;
- }
- WebBrowser::~WebBrowser(void)
- {
- }
- /*
- ==================
- |IUnknownmethods|
- ==================
- */
- STDMETHODIMPWebBrowser::QueryInterface(REFIIDiid,void**ppvObject)
- {
- *ppvObject=0;
- if(iid==IID_IOleClientSite)
- *ppvObject=(IOleClientSite*)this;
- if(iid==IID_IUnknown)
- *ppvObject=this;
- if(iid==IID_IDispatch)
- *ppvObject=(IDispatch*)this;
- if(_bExternalPlace==false)
- {
- if(iid==IID_IOleInPlaceSite)
- *ppvObject=(IOleInPlaceSite*)this;
- if(iid==IID_IOleInPlaceFrame)
- *ppvObject=(IOleInPlaceFrame*)this;
- if(iid==IID_IOleInPlaceUIWindow)
- *ppvObject=(IOleInPlaceUIWindow*)this;
- }
- /*
- 这里是一点货,留在以后讲,如果有机会,你可以发现,原来如此简单.
- if(iid==DIID_DWebBrowserEvents2)
- *ppvObject=(DWebBrowserEvents2*)this;
- if(iid==IID_IDocHostUIHandler)
- *ppvObject=(IDocHostUIHandler*)this;
- */
- if(*ppvObject)
- {
- AddRef();
- returnS_OK;
- }
- returnE_NOINTERFACE;
- }
- STDMETHODIMP_(ULONG)WebBrowser::AddRef()
- {
- return::InterlockedIncrement(&_refNum);
- }
- STDMETHODIMP_(ULONG)WebBrowser::Release()
- {
- return::InterlockedDecrement(&_refNum);
- }
- /*
- =====================
- |IDispatchMethods|
- =====================
- */
- HRESULT_stdcallWebBrowser::GetTypeInfoCount(
- unsignedint*pctinfo)
- {
- returnE_NOTIMPL;
- }
- HRESULT_stdcallWebBrowser::GetTypeInfo(
- unsignedintiTInfo,
- LCIDlcid,
- ITypeInfoFAR*FAR*ppTInfo)
- {
- returnE_NOTIMPL;
- }
- HRESULT_stdcallWebBrowser::GetIDsOfNames(REFIIDriid,
- OLECHARFAR*FAR*rgszNames,
- unsignedintcNames,
- LCIDlcid,
- DISPIDFAR*rgDispId)
- {
- returnE_NOTIMPL;
- }
- HRESULT_stdcallWebBrowser::Invoke(
- DISPIDdispIdMember,
- REFIIDriid,
- LCIDlcid,
- WORDwFlags,
- DISPPARAMS*pDispParams,
- VARIANT*pVarResult,
- EXCEPINFO*pExcepInfo,
- unsignedint*puArgErr)
- {
- /*货,留在以后讲,是关于DWebBrowserEvents2让人激动的实现,而且简单.
- //DWebBrowserEvents2
- if(dispIdMember==DISPID_DOCUMENTCOMPLETE)
- {
- DocumentComplete(pDispParams->rgvarg[1].pdispVal,pDispParams->rgvarg[0].pvarVal);
- returnS_OK;
- }
- if(dispIdMember==DISPID_BEFORENAVIGATE2)
- {
- BeforeNavigate2(pDispParams->rgvarg[6].pdispVal,
- pDispParams->rgvarg[5].pvarVal,
- pDispParams->rgvarg[4].pvarVal,
- pDispParams->rgvarg[3].pvarVal,
- pDispParams->rgvarg[2].pvarVal,
- pDispParams->rgvarg[1].pvarVal,
- pDispParams->rgvarg[0].pboolVal);
- returnS_OK;
- }
- */
- returnE_NOTIMPL;
- }
- /*
- ========================
- |IOleClientSitemethods|
- ========================
- */
- STDMETHODIMPWebBrowser::SaveObject()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::GetMoniker(DWORDdwA,DWORDdwW,IMoniker**pm)
- {
- *pm=0;
- returnE_NOTIMPL;
- }
- STDMETHODIMPWebBrowser::GetContainer(IOleContainer**pc)
- {
- *pc=0;
- returnE_FAIL;
- }
- STDMETHODIMPWebBrowser::ShowObject()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::OnShowWindow(BOOLf)
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::RequestNewObjectLayout()
- {
- returnS_OK;
- }
- /*
- =========================
- |IOleInPlaceSitemethods|
- =========================
- */
- STDMETHODIMPWebBrowser::GetWindow(HWND*p)
- {
- *p=GetHWND();
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::ContextSensitiveHelp(BOOL)
- {
- returnE_NOTIMPL;
- }
- STDMETHODIMPWebBrowser::CanInPlaceActivate()//IfthisfunctionreturnS_FALSE,AXcannotactivateinplace!
- {
- if(_bInPlaced)//DoesWebBrowserControlalreadyinplaced?
- {
- _bCalledCanInPlace=true;
- returnS_OK;
- }
- returnS_FALSE;
- }
- STDMETHODIMPWebBrowser::OnInPlaceActivate()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::OnUIActivate()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::GetWindowContext(IOleInPlaceFrame**ppFrame,IOleInPlaceUIWindow**ppDoc,LPRECTr1,LPRECTr2,LPOLEINPLACEFRAMEINFOo)
- {
- *ppFrame=(IOleInPlaceFrame*)this;
- AddRef();
- *ppDoc=NULL;
- ::GetClientRect(GetHWND(),&_rcWebWnd);
- *r1=_rcWebWnd;
- *r2=_rcWebWnd;
- o->cb=sizeof(OLEINPLACEFRAMEINFO);
- o->fMDIApp=false;
- o->hwndFrame=GetParent(GetHWND());
- o->haccel=0;
- o->cAccelEntries=0;
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::Scroll(SIZEs)
- {
- returnE_NOTIMPL;
- }
- STDMETHODIMPWebBrowser::OnUIDeactivate(int)
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::OnInPlaceDeactivate()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::DiscardUndoState()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::DeactivateAndUndo()
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::OnPosRectChange(LPCRECT)
- {
- returnS_OK;
- }
- /*
- ==========================
- |IOleInPlaceFramemethods|
- ==========================
- */
- STDMETHODIMPWebBrowser::GetBorder(LPRECTl)
- {
- ::GetClientRect(GetHWND(),&_rcWebWnd);
- *l=_rcWebWnd;
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::RequestBorderSpace(LPCBORDERWIDTHSb)
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::SetBorderSpace(LPCBORDERWIDTHSb)
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::SetActiveObject(IOleInPlaceActiveObject*pV,LPCOLESTRs)
- {
- returnS_OK;
- }
- STDMETHODIMPWebBrowser::SetStatusText(LPCOLESTRt)
- {
- returnE_NOTIMPL;
- }
- STDMETHODIMPWebBrowser::EnableModeless(BOOLf)
- {
- returnE_NOTIMPL;
- }
- STDMETHODIMPWebBrowser::TranslateAccelerator(LPMSG,WORD)
- {
- returnE_NOTIMPL;
- }
- HRESULT_stdcallWebBrowser::RemoveMenus(HMENUh)
- {
- returnE_NOTIMPL;
- }
- HRESULT_stdcallWebBrowser::InsertMenus(HMENUh,LPOLEMENUGROUPWIDTHSx)
- {
- returnE_NOTIMPL;
- }
- HRESULT_stdcallWebBrowser::SetMenu(HMENUh,HOLEMENUhO,HWNDhw)
- {
- returnE_NOTIMPL;
- }
- /*
- ====================
- |DWebBrowserEvents2|
- ====================
- */
- /*货,以后再讲
- void
- WebBrowser::DocumentComplete(IDispatch*pDisp,VARIANT*URL)
- {
- //老天保佑,多好的函数啊.
- return;
- }
- void
- WebBrowser::BeforeNavigate2(IDispatch*pDisp,VARIANT*&url,VARIANT*&Flags,VARIANT*&TargetFrameName,VARIANT*&PostData,VARIANT*&Headers,VARIANT_BOOL*&Cancel)
- {
- PCWSTRpcwApp=L"app:";
- if(url->vt!=VT_BSTR)
- return;
- if(0==_wcsnicmp(pcwApp,url->bstrVal,wcslen(pcwApp)))
- {
- *Cancel=VARIANT_TRUE;
- _OnHtmlCmd(url->bstrVal+wcslen(pcwApp));
- return;
- }
- *Cancel=VARIANT_FALSE;
- }
- */
- /*
- =====================
- |IDocHostUIHandler|
- =====================
- */
- /*
- 传说中的IDocHostUIHanler,同样留在以后讲
- HRESULTWebBrowser::ShowContextMenu(
- DWORDdwID,
- POINT*ppt,
- IUnknown*pcmdtReserved,
- IDispatch*pdispReserved){returnE_NOTIMPL;}
- HRESULTWebBrowser::GetHostInfo(
- DOCHOSTUIINFO*pInfo){returnE_NOTIMPL;}
- HRESULTWebBrowser::ShowUI(
- DWORDdwID,
- IOleInPlaceActiveObject*pActiveObject,
- IOleCommandTarget*pCommandTarget,
- IOleInPlaceFrame*pFrame,
- IOleInPlaceUIWindow*pDoc){returnE_NOTIMPL;}
- HRESULTWebBrowser::HideUI(void){returnE_NOTIMPL;}
- HRESULTWebBrowser::UpdateUI(void){returnE_NOTIMPL;}
- //HRESULTWebBrowser::EnableModeless(
- //BOOLfEnable){returnE_NOTIMPL;}
- HRESULTWebBrowser::OnDocWindowActivate(
- BOOLfActivate){returnE_NOTIMPL;}
- HRESULTWebBrowser::OnFrameWindowActivate(
- BOOLfActivate){returnE_NOTIMPL;}
- HRESULTWebBrowser::ResizeBorder(
- LPCRECTprcBorder,
- IOleInPlaceUIWindow*pUIWindow,
- BOOLfRameWindow){returnE_NOTIMPL;}
- HRESULTWebBrowser::TranslateAccelerator(
- LPMSGlpMsg,
- constGUID*pguidCmdGroup,
- DWORDnCmdID){returnE_NOTIMPL;}
- HRESULTWebBrowser::GetOptionKeyPath(
- LPOLESTR*pchKey,
- DWORDdw){returnE_NOTIMPL;}
- HRESULTWebBrowser::GetDropTarget(
- IDropTarget*pDropTarget,
- IDropTarget**ppDropTarget)
- {
- returnE_NOTIMPL;//使用默认拖拽
- //returnS_OK;//自定义拖拽
- }
- HRESULTWebBrowser::GetExternal(IDispatch**ppDispatch)
- {
- returnE_NOTIMPL;
- }
- HRESULTWebBrowser::TranslateUrl(
- DWORDdwTranslate,
- OLECHAR*pchURLIn,
- OLECHAR**ppchURLOut){returnE_NOTIMPL;}
- HRESULTWebBrowser::FilterDataObject(
- IDataObject*pDO,
- IDataObject**ppDORet){returnE_NOTIMPL;}
- */
- /*
- ===============
- |OtherMethods|
- ===============
- */
- IWebBrowser2*
- WebBrowser::GetWebBrowser2()
- {
- if(_pWB2!=NULL)
- return_pWB2;
- NULLTEST_SE(_pOleObj,L"Ole对象为空");
- HRTEST_SE(_pOleObj->QueryInterface(IID_IWebBrowser2,(void**)&_pWB2),L"QueryInterfaceIID_IWebBrowser2失败");
- return_pWB2;
- RETURN:
- returnNULL;
- }
- IHTMLDocument2*
- WebBrowser::GetHTMLDocument2()
- {
- if(_pHtmlDoc2!=NULL)
- return_pHtmlDoc2;
- IWebBrowser2*pWB2=NULL;
- NULLTEST(pWB2=GetWebBrowser2());//GetWebBrowser2已经将错误原因交给LastError.
- IDispatch*pDp=NULL;
- HRTEST_SE(pWB2->get_Document(&pDp),L"DWebBrowser2::get_Document错误");
- HRTEST_SE(pDp->QueryInterface(IID_IHTMLDocument2,(void**)&_pHtmlDoc2),L"QueryInterfaceIID_IHTMLDocument2失败");
- return_pHtmlDoc2;
- RETURN:
- returnNULL;
- }
- IHTMLDocument3*
- WebBrowser::GetHTMLDocument3()
- {
- if(_pHtmlDoc3!=NULL)
- return_pHtmlDoc3;
- IWebBrowser2*pWB2=NULL;
- NULLTEST(pWB2=GetWebBrowser2());//GetWebBrowser2已经将错误原因交给LastError.
- IDispatch*pDp=NULL;
- HRTEST_SE(pWB2->get_Document(&pDp),L"DWebBrowser2::get_Document错误");
- HRTEST_SE(pDp->QueryInterface(IID_IHTMLDocument3,(void**)&_pHtmlDoc3),L"QueryInterfaceIID_IHTMLDocument3失败");
- return_pHtmlDoc3;
- RETURN:
- returnNULL;
- }
- IHTMLWindow2*
- WebBrowser::GetHTMLWindow2()
- {
- if(_pHtmlWnd2!=NULL)
- return_pHtmlWnd2;
- IHTMLDocument2*pHD2=GetHTMLDocument2();
- NULLTEST(pHD2);
- HRTEST_SE(pHD2->get_parentWindow(&_pHtmlWnd2),L"IHTMLWindow2::get_parentWindow错误");
- return_pHtmlWnd2;
- RETURN:
- returnNULL;
- }
- IHTMLEventObj*
- WebBrowser::GetHTMLEventObject()
- {
- if(_pHtmlEvent!=NULL)
- return_pHtmlEvent;
- IHTMLWindow2*pHW2;
- NULLTEST(pHW2=GetHTMLWindow2());
- HRTEST_SE(pHW2->get_event(&_pHtmlEvent),L"IHTMLWindow2::get_event错误");
- return_pHtmlEvent;
- RETURN:
- returnNULL;
- }
- BOOL
- WebBrowser::SetWebRect(LPRECTlprc)
- {
- BOOLbRet=FALSE;
- if(false==_bInPlaced)//尚未OpenWebBrowser操作,直接写入_rcWebWnd
- {
- _rcWebWnd=*lprc;
- }
- else//已经打开WebBrowser,通过IOleInPlaceObject::SetObjectRects调整大小
- {
- SIZELsize;
- size.cx=RECTWIDTH(*lprc);
- size.cy=RECTHEIGHT(*lprc);
- IOleObject*pOleObj;
- NULLTEST(pOleObj=_GetOleObject());
- HRTEST_E(pOleObj->SetExtent(1,&size),L"SetExtent错误");
- IOleInPlaceObject*pInPlace;
- NULLTEST(pInPlace=_GetInPlaceObject());
- HRTEST_E(pInPlace->SetObjectRects(lprc,lprc),L"SetObjectRects错误");
- _rcWebWnd=*lprc;
- }
- bRet=TRUE;
- RETURN:
- returnbRet;
- }
- BOOL
- WebBrowser::OpenWebBrowser()
- {
- BOOLbRet=FALSE;
- NULLTEST_E(_GetOleObject(),L"ActiveX对象为空");//对于本身的实现函数,其自身承担错误录入工作
- if((RECTWIDTH(_rcWebWnd)&&RECTHEIGHT(_rcWebWnd))==0)
- ::GetClientRect(GetHWND(),&_rcWebWnd);//设置WebBrowser的大小为窗口的客户区大小.
- if(_bInPlaced==false)//ActivateInPlace
- {
- _bInPlaced=true;//_bInPlacedmustbesetastrue,beforeINPLACEACTIVATE,otherwise,onceDoVerb,itwouldreturnerror;
- _bExternalPlace=0;//lParam;
- HRTEST_E(_GetOleObject()->DoVerb(OLEIVERB_INPLACEACTIVATE,0,this,0,GetHWND(),&_rcWebWnd),L"关于INPLACE的DoVerb错误");
- _bInPlaced=true;
- //*挂接DWebBrwoser2Event
- IConnectionPointContainer*pCPC=NULL;
- IConnectionPoint*pCP=NULL;
- HRTEST_E(GetWebBrowser2()->QueryInterface(IID_IConnectionPointContainer,(void**)&pCPC),L"枚举IConnectionPointContainer接口失败");
- HRTEST_E(pCPC->FindConnectionPoint(DIID_DWebBrowserEvents2,&pCP),L"FindConnectionPoint失败");
- DWORDdwCookie=0;
- HRTEST_E(pCP->Advise((IUnknown*)(void*)this,&dwCookie),L"IConnectionPoint::Advise失败");
- }
- bRet=TRUE;
- RETURN:
- returnbRet;
- }
- BOOL
- WebBrowser::OpenURL(VARIANT*pVarUrl)
- {
- BOOLbRet=FALSE;
- HRTEST_E(GetWebBrowser2()->Navigate2(pVarUrl,0,0,0,0),L"GetWebBrowser2失败");
- bRet=TRUE;
- RETURN:
- returnbRet;
- }
五.例子
- classWebBrowserWindow:
- publicWebBrowser
- {
- public:
- WebBrowserWindow(void);
- ~WebBrowserWindow(void);
- public:
- virtualHWNDGetHWND(){returnYourWindow};
- private:
- LRESULTOnCreate(WPARAMwParam,LPARAMlParam);
- //您可以在OnCreate中调用OpenWebBrowser然后调用OpenURL
- };
六.下期预告,如果有的话
如果有人感兴趣的话, 以后会说道如何扩展WebBrowser, 让他包罗万象, 你会发现很简单.
如果有问题,欢迎提问. 谢谢.
转自:http://blog.csdn.net/norsd/article/details/2921389