`

[Ray Linn]用Visual Studio 2008开发IE BHO(浏览器帮助对象) 之二

阅读更多
原文发表于blogs.ejb.cc,版权为Ray_linn所有。

上一篇文章开发的RayBHO只是BHO的一个框架,根本不具备任何功能.

在这篇文章里,我们将使继续扩展这个BHO,让它具备更强的功能.首先我们学习如何让BHO接收IE的事件通知,接者学习为ie添加一个按钮,并让BHO对按钮做出响应.

要让BHO能接收事件通知, 它必须让处理函数与浏览器事件建立连接点. 为响应这些事件,它必须实现IDispEventImpl, ATL提供了一个默认实现,可以帮助简化这个事件处理逻辑。
在RayBHO.h添加:
#include "exdispid.h"
#include "shlguid.h"


我们的CRayBHO必须派生自IDispEventImpl,修改后的代码如下:

class ATL_NO_VTABLE CRayBHO :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CRayBHO, &CLSID_RayBHO>,
	public IObjectWithSiteImpl<CRayBHO>,
	public IDispatchImpl<IRayBHO, &IID_IRayBHO, &LIBID_MySolutionPluginLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
	public IDispEventImpl<1,CRayBHO,&DIID_DWebBrowserEvents2,&LIBID_SHDocVw,1,1>


DispEventImpl为处理事件提供了一种简单安全的方法。

IDispEventImpl与事件路由表配合工作,可以将事件路由到相应的处理程序函数。在例子中,我们将"DocumentComplete"的事件交由OnDocumentComplete函数进行处理.

在public段添加路由表:
BEGIN_SINK_MAP(CHelloWorldBHO)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
END_SINK_MAP()


上述声明中SINK_ENTRY_EX(1,...)中的"1"与接口声明中的IDispEventImpl<1,....>是对应的,在必要时可以用于区分来自不同接口的事件.

DocumentComplete将被路由到处理函数OnDocumentComplete:
   void STDMETHODCALLTYPE OnDocumentComplete(IDispatch* pDisp, VARIANT* URL);


它的参数和参数顺序与DocumentComplete事件所定义的相同,另请注意,不要试图从事件处理程序返回值,这是因为 Internet Explorer 会忽略任何从 Invoke 返回的值.
我们还声明了一个私有变量来跟踪事件映射的处理情况

BOOL m_fAdvised; 



SetSite函数中必须处理事件派遣:
STDMETHODIMP CRayBHO::SetSite(IUnknown*pUnkSite)
{
	if(pUnkSite!=NULL)
	{
		HRESULT hr;
		CComPtr<IServiceProvider> sp;

		hr = pUnkSite->QueryInterface(&sp);
		if(SUCCEEDED(hr) && sp)
		{
			//缓存指向IWebBrowser2的指针
			hr = sp->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&m_spWebBrowser);

			if(SUCCEEDED(hr)&&m_spWebBrowser!=0)
			{
				//注册DWebBrowserEvents2事件。
				hr=DispEventAdvise(m_spWebBrowser2);
			
				if(SUCCEEDED(hr))
				{
					m_fAdvised=TRUE;
				}
			}
		}
		m_spUnkSite = pUnkSite;
		this->m_bIsIe7=this->IsIE7();
		
		//hr = sp->QueryInterface(IID_IOleCommandTarget,(void**)&m_spTarget);
		//this->GetInternetExplorerVersion();

	}
	else
	{
		//取消注册事件。
		if(m_fAdvised)
		{
			DispEventUnadvise(m_spWebBrowser);
			m_fAdvised=FALSE;
		}
		//在此释放缓存的指针和其他资源。
		m_spWebBrowser.Release();
		//m_spTarget.Release();
	}
	//调用基类实现。
	return IObjectWithSiteImpl<CRayBHO>::SetSite(pUnkSite);
}


我从网上找了一个OnDocumentComplete函数的例子并将之修改成范型,它对HTML Dom进行操作,将图像的属性设置为Display:None, 具体操作与javascript类似,不再赘述.

void	STDMETHODCALLTYPE	CRayBHO::OnDocumentComplete(IDispatch*pDisp,VARIANT*pvarURL)
{
	HRESULT hr = S_OK; 
	// 查询 IWebBrowser2 接口。 
	CComQIPtr<IWebBrowser2> spTempWebBrowser = pDisp; 
	// 此事件是否与顶级浏览器相关联? 
	if (spTempWebBrowser && m_spWebBrowser && m_spWebBrowser.IsEqualObject(spTempWebBrowser)) 
	{ 
		// 从浏览器中获取当前文档对象…… 
		CComPtr<IDispatch>  spDispDoc; 
		hr = m_spWebBrowser->get_Document(&spDispDoc); 
		if (SUCCEEDED(hr)) 
		{ 
			// ……并查询 HTML 文档。 
			CComQIPtr<IHTMLDocument2> spHTMLDoc = spDispDoc; 
			if (spHTMLDoc != NULL) { 
				// 最后,删除这些图像。 
				RemoveImages(spHTMLDoc); 
			} 
		} 
	} 
}

void CRayBHO::RemoveImages(IHTMLDocument2* pDocument) 
{ 
	CComPtr<IHTMLElementCollection> spImages; 
	// 从 DOM 中获取图像集。 
	HRESULT hr = pDocument->get_images(&spImages); 
	if (hr == S_OK && spImages != NULL) { 
		// 获取集合中的图像数。 
		long cImages = 0; 
		hr = spImages->get_length(&cImages); 
		if (hr == S_OK && cImages > 0) 
		{ 
			for (int i = 0; i < cImages; i++) 
			{ 
				CComVariant svarItemIndex(i); 
				CComVariant svarEmpty; 
				CComPtr<IDispatch> spdispImage; 
				// 按索引从集合中获取图像。 
				hr = spImages->item(svarItemIndex, svarEmpty, &spdispImage); 
				if (hr == S_OK && spdispImage != NULL) 
				{ 
					// 首先,查询通用 HTML 元素接口…… 
					CComQIPtr<IHTMLElement> spElement = spdispImage; 
					if (spElement) 
					{ 
						// ……然后请求样式接口。 
						CComPtr<IHTMLStyle> spStyle; 
						hr = spElement->get_style(&spStyle); 
						// 设置 display="none" 以隐藏图像。 
						if (hr == S_OK && spStyle != NULL) 
						{ 
							static const CComBSTR sbstrNone(L"none"); 
							spStyle->put_display(sbstrNone);
						}
					} 
				} 
			} 
		} 
	} 
}


利用VC++操作HTML并没有想象中的繁琐, 你可以开发出更有趣的东西,比如从数据库自动填表单的BHO等等.
分享到:
评论
1 楼 andywu 2009-03-15  
先占个位置,仔细品尝中....

相关推荐

    【工作点滴】用VS 2010 编译 Ruby 1.9.1

    标题中的“【工作点滴】用VS 2010 编译 Ruby 1.9.1”表明了本文将探讨如何使用Visual Studio 2010这个集成开发环境(IDE)来编译Ruby 1.9.1版本的源代码。Ruby是一种动态、面向对象的编程语言,而1.9.1是它的一个...

    Kagney LInn

    a little bit huge FUcking guy this bitch web!

    模拟技术中的Wolfson使Linn的新产品Akurate DS展示音乐的未来、实现终极音乐体验

    标题中的核心知识点主要聚焦在模拟技术以及Wolfson(欧胜微电子)的WM8741音频数字模拟转换器在Linn新产品Akurate DS中的应用,这款产品被誉为展示音乐未来和实现终极音乐体验的关键。 模拟技术是音频系统中的重要...

    与短消息开发相关的GSM AT指令

    AT指令集 全球定位系统(GPS)系统由于性能优异,在民用上应用范围很广。其可以用于空中交通管理、大地精密测量、摄影测量、监测地壳运动、火山活动、野外调查和勘探的...本文主要介绍与短消息开发相关的GSM AT指令。

    linn-gaarder-js1-ca

    【标题】"linn-gaarder-js1-ca" 是一个与JavaScript编程相关的项目或课程,可能由Linn Gaarder创建,旨在教授基础到中级的JavaScript知识。这个项目的名称暗示了它可能涵盖JavaScript的第一个阶段,即初级部分,并且...

    linn9000cass:linn9000cass:用于 Linn9000 和 LinnSequencer 数据盒格式的工具-开源

    工具“l9000cassdecode”可用于对 Linn9000 和 LinnSequencer 的数据盒(磁带)格式进行解码。 根据数据盒内容,提取 Linn9000 相关文件,例如以下文件类型:DSQ、MSQ、ALL、ASQ、ADS、AMS、ALM、SND、KIT。 可选:...

    linn9000cass:linn9000cass:用于Linn9000和LinnSequencer数据盒带格式的工具-开源

    根据数据盒带的内容,提取与Linn9000相关的文件,例如,使用以下文件类型:DSQ,MSQ,ALL,ASQ,ADS,AMS,ALM,SND,KIT。 可选:tar文件导出。 注意:例如,可以通过包含在项目“ linn9000fs”中的工具“ l9000fs...

    Linn-Wilhelmsen-js1-ma1

    【标题】"Linn-Wilhelmsen-js1-ma1" 可能是指一个JavaScript编程项目或课程作业,由Linn和Wilhelmsen两位作者共同完成,第一部分(可能是系列中的第一个模块或者任务)。 【描述】由于提供的描述与标题相同,没有...

    Syngress.Coding for Penetration Testers.Building Better Tools.2011

    《Coding for Penetration Testers: Building Better Tools》是一本专注于渗透测试领域的书籍,通过教授如何使用脚本语言自行开发工具,帮助读者提高自身的技能水平。书中不仅介绍了基本概念和理论知识,还深入探讨...

    sb2m3u:Linn Songbox 远程播放列表到 M3U 的转换

    在 Kinsky 中创建播放列表很棒,我想远程保存它们,如果您使用 Linn 的 Songbox,您可以这样做。 播放列表上的每个曲目都是一个 URI,它允许灵活地从多个媒体服务器创建播放列表,此外元数据的 URI 也与播放列表中的...

    Volumio-BubbleUPnP-Server:用于Volumio的BubbleUPnP服务器安装程序

    这是一个直接在Volumio系统上安装BubbleUPnP Server的帮助程序工具。 可用于流化潮汐和Qobuz(使用MDP)。 您需要的是OpenHome渲染器应用程序,例如Linn Kazoo,Lumin等。 默认情况下, BubbleUPnP服务器正在使用...

    Scala与Clojure函数式编程

    函数式编程是编程范式之一,它强调使用函数来表达计算,而非传统命令式的编程方式。在函数式编程中,数据和函数结合得非常紧密,数据被视为函数作用的原象,而函数则是数据的变换器。函数式编程在逻辑上摒弃了可变...

    [Pragmatic Bookshelf] Functional Programming Patterns in Scala and Clojure

    - **对象导向编程(Object-Oriented Programming, OOP)简介**:对象导向编程是一种编程方法论,它通过对象来组织代码。这些对象由类定义,并包含属性和行为。OOP强调封装(Encapsulation)、继承(Inheritance)、...

    D-Link路由器当交换机配置步骤.doc

    【路由器作为交换机的配置方法】 在某些网络环境中,我们可能需要将一个路由器用作交换机,以便扩展网络接口或管理多个设备的连接。这里,我们将详细解释如何将D-Link路由器转换为交换机,以及如何配置不同品牌的...

    Phaseolus lunatus Linn vel aff的种子中A型血专-性凝集素的研究* (1991年)

    用亲和层析法从PhaseoZus lunatus Linn vel aff的种子中纯化出一种对人类A型血专一的凝集素.该凝集素的粗浸提液都只对A型血细胞凝集,而对 B、O型绝不凝集.当纯化的凝集素浓度为0.98μg/mL时,即能凝集A型血细胞,...

    4万元HIEND解码器LINNAKURATEDS评测汇编.pdf

    【LINN AKURATE DS评测】 LINN是一家享有盛誉的HI-END音响品牌,创立于1972年,以其卓越的音质和经典产品如Sondek LP12黑胶唱盘和CD12播放机而闻名。随着时代的发展,LINN宣布将停止CD播放机的生产,转而专注于PC...

    4万元HIEND解码器LINNAKURATEDS评测.pdf

    LINN DS系列的独特之处在于采用了网线接口,不同于传统的USB、火线、光纤或同轴接口。这种设计极大地保证了音频数据传输的精度,避免了计算机操作系统对音频的潜在干扰,从而实现近乎无损的数据传输。USB接口可能会...

    基于连接自组织发育的稀疏跨越-侧抑制神经网络设计.pdf

    本文主要探讨了一种新颖的神经网络设计方法,即基于连接自组织发育的稀疏跨越-侧抑制神经网络(Sparse Span-lateral Inhibition Neural Network, sS-LINN)。这种网络设计受到生物神经系统中神经元稀疏连接特性的...

    BKE-Elk-Global_Header_and_Footer:ElkArte论坛的全球页眉和页脚插件

    如果满足以下条件,则允许以源代码和二进制形式进行重新分发和使用,无论是否经过修改,都可以: 重新分发源代码必须保留上述版权声明,此条件列表和以下免责声明。 二进制形式的重新分发必须在分发随附的文档和/或...

    黄芪属(Astragalus Linn)植物生物学特性及组织培养技术研究进展 (2006年)

    本文主要针对黄芪属(Astragalus Linn)植物的生物学特性和组织培养技术进行了全面的回顾与总结。黄芪作为传统中药材之一,在全球范围内拥有广泛的药用价值。近年来,随着生物科技的进步,黄芪属植物的研究逐渐深入...

Global site tag (gtag.js) - Google Analytics