中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Visual C++ > COM技术
定制浏览器
作者:未知 时间:2005-07-20 14:21 出处:VC知识库 责编:chinaitpower
              摘要:定制浏览器
定制浏览器
作者:冯明德


浏览器控件是个典型的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;         
}
关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有