原文发表于
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等等.
分享到:
相关推荐
标题中的“【工作点滴】用VS 2010 编译 Ruby 1.9.1”表明了本文将探讨如何使用Visual Studio 2010这个集成开发环境(IDE)来编译Ruby 1.9.1版本的源代码。Ruby是一种动态、面向对象的编程语言,而1.9.1是它的一个...
a little bit huge FUcking guy this bitch web!
标题中的核心知识点主要聚焦在模拟技术以及Wolfson(欧胜微电子)的WM8741音频数字模拟转换器在Linn新产品Akurate DS中的应用,这款产品被誉为展示音乐未来和实现终极音乐体验的关键。 模拟技术是音频系统中的重要...
AT指令集 全球定位系统(GPS)系统由于性能优异,在民用上应用范围很广。其可以用于空中交通管理、大地精密测量、摄影测量、监测地壳运动、火山活动、野外调查和勘探的...本文主要介绍与短消息开发相关的GSM AT指令。
【标题】"linn-gaarder-js1-ca" 是一个与JavaScript编程相关的项目或课程,可能由Linn Gaarder创建,旨在教授基础到中级的JavaScript知识。这个项目的名称暗示了它可能涵盖JavaScript的第一个阶段,即初级部分,并且...
工具“l9000cassdecode”可用于对 Linn9000 和 LinnSequencer 的数据盒(磁带)格式进行解码。 根据数据盒内容,提取 Linn9000 相关文件,例如以下文件类型:DSQ、MSQ、ALL、ASQ、ADS、AMS、ALM、SND、KIT。 可选:...
根据数据盒带的内容,提取与Linn9000相关的文件,例如,使用以下文件类型:DSQ,MSQ,ALL,ASQ,ADS,AMS,ALM,SND,KIT。 可选:tar文件导出。 注意:例如,可以通过包含在项目“ linn9000fs”中的工具“ l9000fs...
【标题】"Linn-Wilhelmsen-js1-ma1" 可能是指一个JavaScript编程项目或课程作业,由Linn和Wilhelmsen两位作者共同完成,第一部分(可能是系列中的第一个模块或者任务)。 【描述】由于提供的描述与标题相同,没有...
《Coding for Penetration Testers: Building Better Tools》是一本专注于渗透测试领域的书籍,通过教授如何使用脚本语言自行开发工具,帮助读者提高自身的技能水平。书中不仅介绍了基本概念和理论知识,还深入探讨...
在 Kinsky 中创建播放列表很棒,我想远程保存它们,如果您使用 Linn 的 Songbox,您可以这样做。 播放列表上的每个曲目都是一个 URI,它允许灵活地从多个媒体服务器创建播放列表,此外元数据的 URI 也与播放列表中的...
这是一个直接在Volumio系统上安装BubbleUPnP Server的帮助程序工具。 可用于流化潮汐和Qobuz(使用MDP)。 您需要的是OpenHome渲染器应用程序,例如Linn Kazoo,Lumin等。 默认情况下, BubbleUPnP服务器正在使用...
函数式编程是编程范式之一,它强调使用函数来表达计算,而非传统命令式的编程方式。在函数式编程中,数据和函数结合得非常紧密,数据被视为函数作用的原象,而函数则是数据的变换器。函数式编程在逻辑上摒弃了可变...
- **对象导向编程(Object-Oriented Programming, OOP)简介**:对象导向编程是一种编程方法论,它通过对象来组织代码。这些对象由类定义,并包含属性和行为。OOP强调封装(Encapsulation)、继承(Inheritance)、...
【路由器作为交换机的配置方法】 在某些网络环境中,我们可能需要将一个路由器用作交换机,以便扩展网络接口或管理多个设备的连接。这里,我们将详细解释如何将D-Link路由器转换为交换机,以及如何配置不同品牌的...
用亲和层析法从PhaseoZus lunatus Linn vel aff的种子中纯化出一种对人类A型血专一的凝集素.该凝集素的粗浸提液都只对A型血细胞凝集,而对 B、O型绝不凝集.当纯化的凝集素浓度为0.98μg/mL时,即能凝集A型血细胞,...
【LINN AKURATE DS评测】 LINN是一家享有盛誉的HI-END音响品牌,创立于1972年,以其卓越的音质和经典产品如Sondek LP12黑胶唱盘和CD12播放机而闻名。随着时代的发展,LINN宣布将停止CD播放机的生产,转而专注于PC...
LINN DS系列的独特之处在于采用了网线接口,不同于传统的USB、火线、光纤或同轴接口。这种设计极大地保证了音频数据传输的精度,避免了计算机操作系统对音频的潜在干扰,从而实现近乎无损的数据传输。USB接口可能会...
本文主要探讨了一种新颖的神经网络设计方法,即基于连接自组织发育的稀疏跨越-侧抑制神经网络(Sparse Span-lateral Inhibition Neural Network, sS-LINN)。这种网络设计受到生物神经系统中神经元稀疏连接特性的...
如果满足以下条件,则允许以源代码和二进制形式进行重新分发和使用,无论是否经过修改,都可以: 重新分发源代码必须保留上述版权声明,此条件列表和以下免责声明。 二进制形式的重新分发必须在分发随附的文档和/或...
本文主要针对黄芪属(Astragalus Linn)植物的生物学特性和组织培养技术进行了全面的回顾与总结。黄芪作为传统中药材之一,在全球范围内拥有广泛的药用价值。近年来,随着生物科技的进步,黄芪属植物的研究逐渐深入...