这篇文章是应同学们的要求写的,以前都是用VC++ 6.0+Platform SDK完成的. 迁移到 VS2008之后,原来Visual Studio 6.0里的BHO向导不复存在,因此特此不厌其烦,详细说明,本文也适用于VS2005.
首先谈BHO的开发工具,我偏向使用VC++(unmanaged C++) 作为开发工具,因为Java JVM或.Net CLR的虚拟机是个很笨重的东西,也是内存杀手, 并不具备写plugin的快捷轻巧的特点.个人并不喜欢将其作为Plug-in的开发平台,不过我会有另文说明用C#开发BHO的全过程, 作为那些偏重开发效率的同学的参考.
其次是类库的选择,我倾向利用“活动模板库”(ATL) 来开发使用 C++ 的 BHO。之所以使用 ATL,是因为它方便地实现了我们可以按需进行扩展的基本样板。尽管使用“Microsoft 基础类”(MFC) 或 Win32 API 和 COM)也可以创建BHO,但 ATL 是为我们提供了自动处理许多细节的轻型库,包括建立含有 BHO 类标识符 (CLSID) 的注册表。
ATL 的另一个优势在于它的 COM智能感知指针类(例如,CComPtr 和 CComBSTR),这些类可管理 COM 对象的生命周期。例如,CComPtr 在赋值时会调用 AddRef,而在对象被销毁或超出范围时会调用 Release。智能指针简化了代码并且有助于避免内存泄漏。当在单个方法范围内使用时,它们的稳定性和可靠性尤为有用。
介绍完ATL, 我们也简单介绍一下BHO. BHO是将自定义功能添加到 Internet Explorer 的轻型 DLL 扩展,除了IE, BHO 还可以将功能添加到 Windows 资源管理器外壳程序.
BHO 通常并不提供其自身的任何用户界面 (UI)。它们而是通过在后台响应浏览器事件和用户输入数据来发挥作用。例如,BHO 可以拦截弹出窗口、自动填充窗体或为鼠标手势添加支持。
有一种常见误解认为工具栏扩展项需要 BHO.但如果将 BHO 与工具栏配合使用,则可以实现更丰富的用户体验。(关于IE工具栏的编程,在另一篇文章中说明).
BHO 的生命周期与它所交互的浏览器实例的生命周期相等。在 IE 6 和早期版本中,这意味着要为每个新的顶层窗口创建(和销毁)一个新 BHO。在IE 7中则是为每个选项卡都创建和销毁一个新 BHO。
BHO 必须实现 IObjectWithSite 接口, 该接口提供了两个方法GetSite和SetSite。根据MSDN的说明:
GetSite: Gets the last site set with IObjectWithSite::SetSite. If there is no known site, the object returns a failure code.
SetSite: Provides the site's IUnknown pointer to the object.
我们主要是对后者进行调用,此方法方便了与 Internet Explorer 的初始通信,并会在其将要释放时通知 BHO。我们实现此接口,然后将 BHO 的 CLSID 添加到注册表中,就可以创建一个简单的浏览器扩展。过程如下:
1. 在Visual Studio中,选择VC++中的ATL项目, 创建一个新的项目MySolutionPlugin, 在随后的向导中,确认Server Type是Dll, Visual Studio会为我们创建程序的模板.
2. 为该项目添加我们的程序主体, (不熟悉visual studio的同学在资源浏览器里的右键菜单里选 add-->class, 可别选到New Item), 类型选ATL Simple Object , short name命名为RayBHO,各项属性如下:
a) “线程模型” ---“Apartment”
b) “聚合”---“否”
c) “接口”---“双重”
d) “支持”---勾上“IobjectWithSite”。
具体的含义请参考MSDN.
一般来说,Internet Explorer 至少调用SetSite方法两次: 一次用于建立连接,另一次则是在浏览器退出时。我们 BHO 中的 SetSite 实现将执行以下操作:
•存储对站点的引用。在初始化期间,浏览器将 IUnknown 指针传递给顶层 WebBrowser 控件,然后 BHO 将对它的引用存储在一个专用成员变量中。
•释放目前被占用的站点指针。Internet Explorer 传递 NULL 时,BHO 必须释放所有接口引用并且断开与浏览器的连接。
要实现SetSite,我们需手工在添加一个public的方法:
STDMETHOD(SetSite)(IUnknown * pUnkSite);
STDMETHOD 宏是将方法标记为虚方法并且确保其具有适用于公共 COM 接口的调用约定的一个ATL 约定, 它有助于区分 COM 接口和该类中可能存在的其他公共方法。其实现成员方法时应相应使用 STDMETHODIMP 宏。同时我们需要声明一个私有变量来保存Browser的指针"
CComPtr<IWebBrowser2> m_spWebBrowser;//保存Browser指针的私有变量
然后是SetSite的实现
STDMETHODIMP CRayBHO::SetSite(IUnknown*pUnkSite)
{
if(pUnkSite!=NULL)
{
//缓存指向IWebBrowser2的指针。
pUnkSite->QueryInterface(IID_IWebBrowser2,(void**)&m_spWebBrowser);
}
else
{
//在此释放缓存的指针和其他资源。
m_spWebBrowser.Release();
}
//返回基类实现
return IObjectWithSiteImpl::SetSite(pUnkSite);
}
从上面的介绍我们知道, 初始化期间,浏览器将传递一个对其顶层 IWebBrowser2 接口(我们对其进行缓存处理)的引用。浏览器关闭时将传递 NULL,为避免内存泄漏和循环引用计数,此时释放所有指针和资源非常重要。最后,我们调用基类实现以便继续执行接口合约的其余部分。
加载DLL 后,系统将通过 DLL_PROCESS_ATTACH 通知调用 DllMain 函数。由于 Internet Explorer 大量使用多线程,因此,对 DllMain 的频繁的 DLL_THREAD_ATTACH 和 DLL_THREAD_DETACH 通知会降低扩展和浏览器进程的整体性能。
如果BHO 不需要线程级的跟踪,我们可以在 DLL_PROCESS_ATTACH 通知期间调用 DisableThreadLibraryCalls 以避免新线程通知的额外开销。修改DllMain.cpp 中的DllMain函数:
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if(dwReason==DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
}
return _AtlModule.DllMain(dwReason,lpReserved);
}
要使BHO工作,我们还需要把BHO 的 CLSID 添加到注册表中。此条目会将 此DLL 标记为浏览器帮助程序对象,并使 Internet Explorer 在启动时加载 BHO。我们可以在MySolutionPlugin.idl中找到该BHO的CLSID.幸运的,Visual Studio会帮助我们实现这些, 你看到:
importlib("stdole2.tlb");
[
uuid(057F3E68-6C2E-40A5-A641-E8CF9D6766F3),
helpstring("RayBHO Class")
]
您的机器的CLSID可能有所不同, 接着打开RayBHO.rgs文件,添加入:
HKLM
{
NoRemove SOFTWARE
{
NoRemove Microsoft
{
NoRemove Windows
{
NoRemove CurrentVersion
{
NoRemove Explorer
{
NoRemove 'Browser Helper Objects'
{
ForceRemove {057F3E68-6C2E-40A5-A641-E8CF9D6766F3} = s 'RayBHO Class'
{
val NoExplorer = d '1'
}
}
}
}
}
}
}
}
这一段是为了在注册表里添加一个双字节的NoExplorer=1的键,不让Windows Explorer加载该BHO,因此该BHO只能在ie中运行.
你可以编译这个BHO. 如果一切正常, 你可以在IE的管理加载项里看到这个BHO.
如果不幸报错: 该BHO无法被注册,根据我的经验,原因大概有2类,可以依次检查
1. 你是否有管理员权限以修改注册表,如不是管理员身份,可以在菜单上右击Microsoft Visual studio 2008,从右键菜单中选择"运行方式"...
2. 你的注册表条目语法是否正确,或者含有非法字符.
分享到:
相关推荐
标题中的“【工作点滴】用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中的应用,这款产品被誉为展示音乐未来和实现终极音乐体验的关键。 模拟技术是音频系统中的重要...
9. **跨浏览器兼容性**:由于不同的浏览器可能对某些JavaScript特性支持程度不同,开发者需要考虑代码的兼容性问题,可能需要使用库如jQuery来简化这一步骤。 10. **项目实践**:"linn-gaarder-js1-ca"可能包含一...
AT指令集 全球定位系统(GPS)系统由于性能优异,在民用上应用范围很广。其可以用于空中交通管理、大地精密测量、摄影测量、监测地壳运动、火山活动、野外调查和勘探的...本文主要介绍与短消息开发相关的GSM AT指令。
《Coding for Penetration Testers: Building Better Tools》是一本专注于渗透测试领域的书籍,通过教授如何使用脚本语言自行开发工具,帮助读者提高自身的技能水平。书中不仅介绍了基本概念和理论知识,还深入探讨...
工具“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两位作者共同完成,第一部分(可能是系列中的第一个模块或者任务)。 【描述】由于提供的描述与标题相同,没有...
函数式编程是编程范式之一,它强调使用函数来表达计算,而非传统命令式的编程方式。在函数式编程中,数据和函数结合得非常紧密,数据被视为函数作用的原象,而函数则是数据的变换器。函数式编程在逻辑上摒弃了可变...
在 Kinsky 中创建播放列表很棒,我想远程保存它们,如果您使用 Linn 的 Songbox,您可以这样做。 播放列表上的每个曲目都是一个 URI,它允许灵活地从多个媒体服务器创建播放列表,此外元数据的 URI 也与播放列表中的...
这是一个直接在Volumio系统上安装BubbleUPnP Server的帮助程序工具。 可用于流化潮汐和Qobuz(使用MDP)。 您需要的是OpenHome渲染器应用程序,例如Linn Kazoo,Lumin等。 默认情况下, BubbleUPnP服务器正在使用...
- **对象导向编程(Object-Oriented Programming, OOP)简介**:对象导向编程是一种编程方法论,它通过对象来组织代码。这些对象由类定义,并包含属性和行为。OOP强调封装(Encapsulation)、继承(Inheritance)、...
在某些网络环境中,我们可能需要将一个路由器用作交换机,以便扩展网络接口或管理多个设备的连接。这里,我们将详细解释如何将D-Link路由器转换为交换机,以及如何配置不同品牌的路由器来实现这一功能。 1. **D-...
用亲和层析法从PhaseoZus lunatus Linn vel aff的种子中纯化出一种对人类A型血专一的凝集素.该凝集素的粗浸提液都只对A型血细胞凝集,而对 B、O型绝不凝集.当纯化的凝集素浓度为0.98μg/mL时,即能凝集A型血细胞,...
薜荔和爱玉子是两种桑科植物,薜荔(Ficus pumila Linn)和爱玉子(Ficus awkeotsang Makino)不仅在形态上有相似之处,而且在生物学特性上也紧密相关。这两种植物的花和花序的形态特征比较是一个科学领域内较为关注...
【LINN AKURATE DS评测】 LINN是一家享有盛誉的HI-END音响品牌,创立于1972年,以其卓越的音质和经典产品如Sondek LP12黑胶唱盘和CD12播放机而闻名。随着时代的发展,LINN宣布将停止CD播放机的生产,转而专注于PC...
黄芪作为传统中药材之一,在全球范围内拥有广泛的药用价值。近年来,随着生物科技的进步,黄芪属植物的研究逐渐深入,特别是在其生物学特性和组织培养技术领域取得了显著成果。 #### 黄芪属植物的生物学特性 1. **...
本文主要探讨了一种新颖的神经网络设计方法,即基于连接自组织发育的稀疏跨越-侧抑制神经网络(Sparse Span-lateral Inhibition Neural Network, sS-LINN)。这种网络设计受到生物神经系统中神经元稀疏连接特性的...