授权CSDN, 请在征求同意后转载. 作者: 陈嘉, NetSecure Inc, Canada, 软件工程师
微软在1997年正式退出Browser Helper Object (BHO), 使程序员能够更好的对IE进行二次开发和操作. 在通过编写BHO程序数月后, 我希望把我的一些经验告诉才开始的同志, 避免走一些弯路.
我本人是非常喜欢C++的. 因为C++对内存直接操作的方式可以节省非常多的内存损耗, 也更快一些. 但是在开发BHO的时候, 我的确也认识到, C#明显要比C++强大很多. 例如C#提供的FOREACH 循环就可以避免FOR循环产生的溢出. 另外C#的类型转换也明显要强于C++. 毕竟BHO和C#都是出自微软一家, 理所当然, C#更适合BHO开发一些. 我的第一个BHO程序是用C++写的. 对于COM的操作,让我至少弄了几天才搞清楚他们到底想干什么. 但是我的第一个C# BHO程序只用了几分钟就搭建好了钩子. 如果你希望从事BHO开发, 而且你才开始学. 我想这片篇文章对您有点帮助.
这篇文章本来是用英文写成的. 因为工作环境的原因, 中文已经越来越生疏. 如果有错误或者不太明显的地方. 请参考英文原文
http://www.horizonideas.com/writings/article.php?id=11
下面竟让我们开始.
首先我们需要在C#中新建一个DLL工程. 因为BHO是通过让IE调用DLL来驱动的. 我用的是V C# EXPRESS. 因为这已经完全够用了. V C# PROFESSIONAL 并不需要, 而且还很浪费内存.
当我们建立一个空工程以后, 随便添加一个文件夹叫BHO, 然后添加一个文件.
需要我们注意的是, 我们这个文件必须被命名为IObjectWithSite.cs因为这样IE才知道这是一个BHO程序. 如果想知道更多关于IObjectWiteSite接口的内容, 请查询MSDN http://msdn2.microsoft.com/en-us/library/Aa768220.aspx
在IObjectWithSite中必须有两个方法GetSite和SetSite. 我们主要是对后者进行调用.通过名字大家就可以猜到他们是干什么的.
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.
请把VS STUIDO 默认的类名给去掉.因为IObjectWithSite并不是一个类, 而是一个接口.
不要忘记添加 System.Runtime.InteropServices
下面我们再添加剂一个叫BHO.CS的主文件.
这个新建的类是基于 IObjectWithSite接口的. 正如同我前面讲的. 你就是通过这个接口来调用IE.
为了使用微软的BHO库.我们必须添加下面两个库: SHDocVw and MSHTML.他们一般都在 Windows\System32 下面
SHDocVw is Microsoft Shell Doc Object and Control Library
MSHTML is: All interfaces for accessing the Dynamic HTML (DHTML) Object Model are based on IDispatch and are the basis of access to the object model that is also used by scripts. http://msdn2.microsoft.com/en-us/library/bb498651.aspx
光using SHDocVw" 是不够的, 你需要添加
Add SHDocVw
因为稍后我们需要用到MESSAGEBOX, 所以这里我也添加了一个WINDOWS FORM库.
下面添加两个变量: WebBrowser and HTMLDocument. 就如同他们的名字. 一个是IE的变量, 另外一个是IE所访问的HTML页变量.
下面在这个类中田间一个叫 OnDocumentComplete 的函数. 取其他名字也行, 没什么太大关系. 但是这里为了CODE的可用性,我们叫OnDocumentComplete. 这个函数实际上是和CDHTMLDIALOG下面的OnDocumentComplete所对应的.
CDHtmlDialog Class http://msdn2.microsoft.com/en-us/library/8bed8k60(VS.80).aspx .
OnDocumentComplete的触发是在一个HTML页被LOAD完以后. 你也可以避免用Navigate() or OnBeforeNavigate(). 他们表示在发出访问和访问之前触发.
Please refer to http://msdn2.microsoft.com/en-us/library/8k5z3ekh(VS.80).aspx to find out what you need exactly.
在 IObjectWithSite.cs下,你需要支出IE的GUID, 这样才方便注册表的更改.
另外你需要给自己的程序添加一个GUID. 这样IE才能在注册表中找到你的信息. 你可以使用System.Guid.NewGuid() method 来得到一个GUID. 这比C++得到GUID的方法要容易得多了.
我们必须给 SetSite and GetSite 加上内容. 在SETSITE中我们就需要加入一个EVENTHANDLER, 让IE来触发我们的OnDocumentComplete函数.
Add one more reference
在BHO.CS下我们需要为我们的DLL添加register/unregister 函数.
下面通过DOS下的 regasm /codebase "BHO HelloWorld.dll" 命令在注册dll. 这里有一个问题了, 为什么?
因为我们忘了把我们的主类设置成PUBLIC, 所以别人都不能调用到你的类. 自然注册不了.
然后就成功了.
打开注册表, 找到Browser Helper Object under LOCAL_MACHINE->SOFTWARE->MICROSOFT->WINDOWS->EXPLORER, 看看是不是有变化了?
我们注册完了, 下面就是来写我们的住程序来控制IE了. 下面就是一个例子来抓去你正访问的页面上的所有INPUT 元素的NAME.
在DOCUMENT中, 我们的所有元素都为IHTMLElement, 我们需要调用的是IHTMLInputElement. 所以我们通过GetElementByTagName的方法来查找所有的INPUT ELEMENT. 在找到以后还需要进行类型转换才能找到对应的ATTRIBUTE. 否则IHTMLElement是不代有NAME ATTRIBUTE的. IHTMLElement提供的ATTRIBUTE都是所有元素都有的. 例如ID, 例如TITLE, 例如OnClick等. 有的元素有自己特有的ATTRIBUTE, 例如INPUT有OnFocus这就必须要转换成IHTMLInputElement才能上使用. INPUT对应的IHTMLInputElement, Select-> IHTMLSelectElement .......
下面我们试另外一个方法叫 BeforeNavigate() .它的触发是在你开始下一个页面之前. 也就是说例如你要提交一个表单, 页面要变化了, 他就被触发.实际上MS提供了两个类似的接口 BeforeNavigate and BeforeNavigate2(). 大家可以查MSDN看看有什么区别. 这里我们不多讲了.
同样我们添加一个对应的函数原形(点图片, 看大图).
添加EVENTHANDLER
我们下面要干的是截获页面上的密码.
See, how easily, you can get it.
通过上面的过程. 我希望您对BHO有一个初步的了解. 如果想知道更多内容, 请访问MSDN. 里面有非常详细的介绍. 这里也引出了一个话题. 我们可以看到, 几乎用不了两分钟我们就可以截获你填写的任何内容, 你觉得IE是安全的吗? 即使他可以通过SSL来对进出网卡的内容加密, 但是在应用层一样是如此的薄弱. 另外大家如果用IE都会发觉泛滥成灾的ADD-ON, 这就是因为BHO惹的祸.
大家如果不想按照我上面的打,可以下我做好的模版.直接放到你的Visual Studio 2005\Templates\ProjectTemplates文件夹下. 当开始一个新工程时候, 点下那个BHO HELLOWORLD就可以了. 所有上面的代码都给你做好了.
project template下载TEMPLATE