系列导航:
- 小工具开发笔记—IE自动填表器—第零篇:序
- 小工具开发笔记—IE自动填表器—第一篇:你好,世界
继上篇博文初步介绍了小工具,本文就作为开发笔记正文第一篇,来叙述一下如何使用C++开发一个完整的IE插件。在动手编码之前,首先重申一下我的开发目的(即需求和功能)。列表如下:
- 在IE的工具栏里面嵌入一个按钮,效果如图:
- 当单击这个按钮时,执行自定义事件,我这里定义的事件就是自动填表(为了循序渐进,本文将以一个Hello World窗口为例来演示自定义事件)
目的叙述完毕,准备开工。那么怎么做呢?俗话说:外事找谷歌,内事找百度。咱先百度一下吧,查到一些中文资料,话说IE插件主要分为三种:ActiveX,BHO,Extension。打开自己的IE看一下,果然是唉。
仔细一看,还多了一种叫做Explorer Bar的东西,其实就是左侧栏的一个导航工具,History和Favorate就是这个类别。再分析一下这三种主要插件:
- ActiveX:一般被用来制作嵌在IE显示层里面的具有丰富UI表现能力的控件,如Silverlight、Flash以及一些网银输入控件(包括万恶的招行),HTML里面使用<object classid=”…” />标签来显示ActiveX控件。
- BHO (Browser Helper Object):这玩意可以通吃IE以及Windows Explorer,是病毒、木马的根源,一旦BHO被注册之后,即会随IE、Windows Explorer启动。这不是我要找的东西,暂且略过。
- Browser Extension:根据上图及这张图片
综合分析,可以肯定这就是我要的插件类型!(什么,你问我怎么分析,这个。。。看到不,Blog This, Send to OneNote即在Browser Extension里面出现,又在工具栏里面出现)
继续查资料,这次用谷歌查微软网站,找到一篇MSDN关于IE添加工具栏的文章,写的很详细很全。里面提到在IE工具栏里面添加一个按钮只需要修改注册表,增加那么一小段即可,里面的{GUID}可以用工具guidgen.exe自动生成一个。
HKEY_LOCAL_MACHINE Software Microsoft Internet Explorer Extensions {GUID}
ButtonText – 设置显示在工具栏上面按钮的名字
HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\{GUID}\ButtonText
HotIcon - 设置显示在工具栏上面按钮的图标
HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\{GUID}\HotIcon
Icon - 设置显示在工具栏上面按钮的灰色图标(即不可用状态)
HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\{GUID}\Icon
CLSID - 设为{1FBA04EE-3024-11d2-8F1F-0000F87ABD16},意思是加载并运行一个COM
HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\{GUID}\CLSID
ClsidExtension - 设为将要被执行的COM,此对象必须实现IOleCommandTarget接口的IOleCommandTarget::Exec方法以及实现IObjectWithSite接口,下文随机切入正题,我将编码实现这一的一个对象。
HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\{GUID}\ClsidExtension
那么,一份完整的注册表信息如下:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Extensions\{77A0B90A-FD44-45B3-ABF3-93F10E80ED4C}]
@="My First IE Extension"
"ButtonText"="Hello World"
"CLSID"="{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}"
"ClsidExtension"="{B73854BF-C89E-44E3-9B54-99D5DD7E948A}"
"Default Visible"="Yes"
"Hot Icon"="D:\\Test\\myicon.ico"
"Icon"="D:\\Test\\myicon.ico"
将其导入注册表,在此打开IE,便看到了Hello World按钮已经出现。注:上面的ClsidExtension将用后面代码生成的GUID替换
不过此时COM{B73854BF-C89E-44E3-9B54-99D5DD7E948A}还没有完成,故点击Hello World是没有反应的。好,接下去就是编码了,很容易,我边上图边解释。
步骤1:创建VC++ATL项目,取名叫HelloWorld,默认配置,直接Finish
步骤2:选择工程HelloWorld右键Add->Class,选择ATL Simple Object,点击Add
步骤3:在Short name里面输入Sample,确保IObjectWithSite勾上,向导会产生一个CSample类
步骤4:修改CExample.h文件,添加IOleCommandTarget接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 public CComObjectRootEx<CComSingleThreadModel>,
3 public CComCoClass<CExample, &CLSID_Example>,
4 public IObjectWithSiteImpl<CExample>,
5 public IDispatchImpl<IExample, &IID_IExample, &LIBID_HelloWorldLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
6 public IOleCommandTarget
7 {
8 public:
9 CExample()
10 {
11 }
12
13 DECLARE_REGISTRY_RESOURCEID(IDR_EXAMPLE)
14
15
16 BEGIN_COM_MAP(CExample)
17 COM_INTERFACE_ENTRY(IExample)
18 COM_INTERFACE_ENTRY(IDispatch)
19 COM_INTERFACE_ENTRY(IObjectWithSite)
20 COM_INTERFACE_ENTRY(IOleCommandTarget)
21 END_COM_MAP()
22
23
24
25 DECLARE_PROTECT_FINAL_CONSTRUCT()
26
27 HRESULT FinalConstruct()
28 {
29 return S_OK;
30 }
31
32 void FinalRelease()
33 {
34 }
35
36 public:
37 virtual /* [input_sync] */ HRESULT STDMETHODCALLTYPE QueryStatus(
38 /* [unique][in] */ __RPC__in_opt const GUID *pguidCmdGroup,
39 /* [in] */ ULONG cCmds,
40 /* [out][in][size_is] */ __RPC__inout_ecount_full(cCmds) OLECMD prgCmds[ ],
41 /* [unique][out][in] */ __RPC__inout_opt OLECMDTEXT *pCmdText);
42
43 virtual HRESULT STDMETHODCALLTYPE Exec(
44 /* [unique][in] */ __RPC__in_opt const GUID *pguidCmdGroup,
45 /* [in] */ DWORD nCmdID,
46 /* [in] */ DWORD nCmdexecopt,
47 /* [unique][in] */ __RPC__in_opt VARIANT *pvaIn,
48 /* [unique][out][in] */ __RPC__inout_opt VARIANT *pvaOut);
49
50 };
步骤5:修改CExample.cpp文件,添加IOleCommandTarget接口实现
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 /* [unique][in] */ __RPC__in_opt const GUID *pguidCmdGroup,
3 /* [in] */ ULONG cCmds,
4 /* [out][in][size_is] */ __RPC__inout_ecount_full(cCmds) OLECMD prgCmds[ ],
5 /* [unique][out][in] */ __RPC__inout_opt OLECMDTEXT *pCmdText)
6 {
7 //TODO:
8 return S_OK;
9 }
10
11 HRESULT STDMETHODCALLTYPE CExample::Exec(
12 /* [unique][in] */ __RPC__in_opt const GUID *pguidCmdGroup,
13 /* [in] */ DWORD nCmdID,
14 /* [in] */ DWORD nCmdexecopt,
15 /* [unique][in] */ __RPC__in_opt VARIANT *pvaIn,
16 /* [unique][out][in] */ __RPC__inout_opt VARIANT *pvaOut)
17 {
18 MessageBoxW(NULL, L"你好,世界", L"My First IE Extension", MB_OK | MB_ICONINFORMATION);
19 return S_OK;
20 }
步骤6:打开Example.rgs,把里面的GUID填入注册表刚才的位置
HKCR { NoRemove CLSID { ForceRemove {B73854BF-C89E-44E3-9B54-99D5DD7E948A} = s 'Example Class' { ForceRemove Programmable InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } TypeLib = s '{FE1A853C-DD4E-4435-87A1-889C86BB604B}' Version = s '1.0' } } }
步骤7:编译、构建(Compile and Build)。如果开发机是Vista或Win7,确保运行VS时有管理员权限,因为编译的最后一步是注册DLL
OK,完成了,再次启动IE,点击Hello World看看效果。
好,本文就写到这里,下一次我讲一下如何获取IE运行时页面里面的元素并对其进行修改。
--寻找源码请看小工具开发笔记—IE自动填表器—第零篇:序