Chinaunix首页 | 论坛 | 博客
  • 博客访问: 110521
  • 博文数量: 23
  • 博客积分: 1464
  • 博客等级: 上尉
  • 技术积分: 231
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-06 16:44
文章分类

全部博文(23)

文章存档

2014年(4)

2011年(3)

2009年(2)

2008年(14)

我的朋友

分类:

2008-12-25 13:45:09

 

浏览器控件是个典型的Active控件,提供了大量的接口及自动化对象,可以灵活的加以控制,需要的时候,可以通过这些接口控制浏览器的行为,或提供相应的出接口定制浏览器。

一、概述

浏览器对象CLSID:

CLSID_WebBrowser

提供的主要接口

IWebBrowser2 浏览器的接口

当文档建立后,可以得到相应的文档接口,文档中各标记元素的接口。

在DHTML中,大量的对象和事件就是又这些接口提供和管理的。


IHTMLDocument2
IHTMLWindow2
IHTMLEventObj
IHTMLElement
....

浏览器还将调用宿主提供的接口,以发出事件或给用户提供定制机会。

出接口

DIID_DWebBrowserEvents2

DIID_HTMLDocumentEvents

DIID_HTMLWindowEvents

(ICustomDoc)

IDocHostUIHandler

二、事件的相应
除了使用MFC缺省的事件响应机制外,也可以自建事件接受器,来响应事件也就是,在封装对象中提供DIID_DWebBrowserEvents2 接口,然后将此接口作为接受器连接到浏览器对象。

一种做法是在派生类中,使用MFC建立接口方案提供一个DIID_DWebBrowserEvents2接口对象嵌套成员。

class CFMDBrowser : public CWebBrowser

{ 
... //事件接收器接口
//DWebBrowserEvents //这是一个IDispatch分发接口
BEGIN_INTERFACE_PART(BrowserEventSink,DWebBrowserEvents)
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
STDMETHOD(GetTypeInfo)(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo);
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,DISPID *rgDispId);
STDMETHOD(Invoke)(DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr);
END_INTERFACE_PART(BrowserEventSink)
DWORD m_dwEventSinkCookie;
...
}


这是一个接收器接口,无需添入到对象的接口表中。
(无需:BEGIN_INTERFACE_MAP、END_INTERFACE_MAP)

这是一个以分发接口(IDispatch)作为出接口的典型例子。在接口函数的实现中。Invoke负责又分发ID调用不同的虚拟函数。(事件函数作为虚拟函数,供派生类重载)

STDMETHODIMP CFMDBrowser::XBrowserEventSink::Invoke(DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
 UINT *puArgErr)
{
METHOD_PROLOGUE(CFMDBrowser,BrowserEventSink) //将事件分发到各虚拟函数
//分发ID的定义见 exdispid.h
switch(dispIdMember)
{
case DISPID_BEFORENAVIGATE:
 ...
HRESULT hr=pThis->OnBeforeNavigate(..) //事件对应的虚拟函数
...
break;
case DISPID_NAVIGATECOMPLETE:
...
case ...
case ...
}
}


建立与浏览器的连接
得到IConnectionPointContainer接口,查找与DIID_DWebBrowserEvents对应的接收器,建立连接,记录连接的标号(m_dwEventSinkCookie);

BOOL CFMDBrowser::Connect() 
{
 IUnknown *p_Unk=GetControlUnknown();
if(p_Unk==NULL)
return FALSE;
BOOL bOK=FALSE;

//查找连接点对象
IConnectionPointContainer *i_cpc=0;
HRESULT hr=p_Unk->QueryInterface(IID_IConnectionPointContainer,(void **)(&i_cpc));
if (SUCCEEDED(hr))
{
IConnectionPoint *i_cp=0;
hr=i_cpc->FindConnectionPoint(DIID_DWebBrowserEvents,&i_cp);
if (SUCCEEDED(hr))
{
hr=i_cp->Advise(&m_xBrowserEventSink,&m_dwEventSinkCookie);
i_cp->Release();
bOK=TRUE;
}
i_cpc->Release();
}
return bOK;
}

结束时,断开与浏览器的连接

BOOL CFMDBrowser::DisConnect() 
{
IUnknown *p_Unk=GetControlUnknown();
if(p_Unk==NULL)
return FALSE;
BOOL bOK=FALSE;
//查找连接点对象
IConnectionPointContainer *i_cpc=0;
HRESULT hr=p_Unk->QueryInterface(IID_IConnectionPointContainer,(void **)(&i_cpc));
if (SUCCEEDED(hr))
{
IConnectionPoint *i_cp=0;
hr=i_cpc->FindConnectionPoint(DIID_DWebBrowserEvents,&i_cp);
if (SUCCEEDED(hr))
{
hr=i_cp->Unadvise(m_dwEventSinkCookie);
i_cp->Release();
bOK=TRUE;
}
i_cpc->Release();
}
return bOK;
}

三、定制浏览器UI
浏览器提供了IDocHostUIHandler出接口,向用户查询界面特性
可以提供这个接口,与浏览器连接上,在其实现中,定制界面

1.建立接口

class CFMDBrowser : public CWebBrowser 
{
...
//IDocHostUIHandler接口,控制浏览器界面
BEGIN_INTERFACE_PART(UIHandlerSink,IDocHostUIHandler)
STDMETHOD(ShowContextMenu)(DWORD,POINT*,IUnknown*,IDispatch*);
STDMETHOD(GetHostInfo)(DOCHOSTUIINFO*);
STDMETHOD(ShowUI)(DWORD,
IOleInPlaceActiveObject*,
IOleCommandTarget*,
IOleInPlaceFrame*,
IOleInPlaceUIWindow*);
STDMETHOD(HideUI)();
STDMETHOD(UpdateUI)();
STDMETHOD(EnableModeless)(INT);
STDMETHOD(OnDocWindowActivate)(INT);
STDMETHOD(OnFrameWindowActivate)(INT);
STDMETHOD(ResizeBorder)(LPCRECT,IOleInPlaceUIWindow*,INT);
STDMETHOD(TranslateAccelerator)(LPMSG,const GUID*,DWORD);
STDMETHOD(GetOptionKeyPath)(LPOLESTR*,DWORD);
STDMETHOD(GetDropTarget)(IDropTarget*,IDropTarget**);
STDMETHOD(GetExternal)(IDispatch**);
STDMETHOD(TranslateUrl)(DWORD,OLECHAR*,OLECHAR**);
STDMETHOD(FilterDataObject)(IDataObject*,IDataObject**);
END_INTERFACE_PART(UIHandlerSink)
...
}

无需添加接口映射

2.连接到浏览器
需要在NavigateComplete时间发生后,得到
ICustomDoc接口,由此接口的
SetUIHandler成员设置UI接口。

//设置界面接口 
IDispatch *i_dispatch=0;
if (SUCCEEDED(i_dispatch=pThis->GetDocument()))
{
IHTMLDocument2 *i_htmldoc2=0;
if (SUCCEEDED(i_dispatch->QueryInterface(IID_IHTMLDocument2,(void **)(&i_htmldoc2))))
{
// force connection of IDocHostUIHandler
ICustomDoc *i_customdoc=0;
if (SUCCEEDED(i_htmldoc2->QueryInterface(IID_ICustomDoc,(void **)(&i_customdoc))))
{
i_customdoc->SetUIHandler(&(pThis->m_xUIHandlerSink));
i_customdoc->Release();
}
}
i_dispatch->Release();
}

3.在接口的实现中,控制用户界面
例如更改右键菜单
在STDMETHOD(ShowContextMenu)(DWORD,POINT*,IUnknown*,IDispatch*);
的实现中:

HRESULT CFMDBrowser::ShowContextMenu(DWORD,POINT*,IUnknown*,IDispatch*) 
{
..建立自己的菜单
return S_OK;
}

参考接口:(VS.85).aspx
阅读(1211) | 评论(0) | 转发(0) |
0

上一篇:FTP断点续传

下一篇:文件编码的转换

给主人留下些什么吧!~~