定制Internet Explorer扩展界面接口

来源:百度文库 编辑:神马文学网 时间:2024/04/27 13:27:22
本文仅介绍IE扩展界面接口,不涉及内核级的高级扩展。
本文大部分资料来自MSDN,MSDN中有更详细的资料,本文只是摘要编辑。

MSDN中的基本Shell编程从Shell Programmers Guide开始,
IE Shell编程从Browser Extensions Overview开始。(用索引跳转)

相关资源: 1.本文提及的ATL向导都可在www.CodeTools.comwww.Codeguru.com上的ATL,Shell Programming页下载

要求知识: 基本COM, ATL理解和使用,Shell编程知识。

IE浏览器提供了可编程的对外接口,用于增加自定义的功能的界面接口,自然的,这些接口以COM的形式提供,即:IE定义了一系列的COM接口,你按照它的接口规定实现这些接口,IE运行时调用这些接口,从而完成你的定制界面。另外,有些比较简单的扩展只需增加注册表项就可以实现。

基本的扩展界面接口有这么几种:
1.添加定制菜单项到IE上下文菜单,如NetAnts, FalshGet。
2.添加定制菜单项到<工具>菜单下,如NetAnts, FalshGet,MSN Message Service
3.添加定制按钮到标准工具栏,如NetAnts, FalshGet。
4.添加定制的浏览栏,工具栏。如 历史记录,电台栏。
5.捕获浏览器点击,如NetAnts, FalshGet。

下面分别简述其实现方法:

1 添加定制菜单项到IE上下文菜单(只需添加注册表项,以FlashGet为例)
① 在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\下添加一个子键。
A. 该子键名即显示在上下文菜单上的文字,如<使用网际快车下载(&D)>字样。
B. 该子键的默认值为一个网页文件的路径,如C:\Program Files\FLASHGET\jc_link.htm,该文件中保存了你编写的菜单项命令激发时将执行的操作的脚本程序。脚本将可以利用External.menuArguments 收到当前IE运行状态的参数。如:

C. 如果你要控制定制菜单项的在网页上的显示范围,可以在该子键下添加一个Context二进制值,如
FlashGet的0x00000022,表示在点击图象或锚点(Archor)时才显示定制菜单项。具体的逻辑或位的设置含义如下:
Context 值
默认 0x1
图象 0x2
控件 0x4
表 0x8
被选文字 0x10
锚点 0x20

2.添加定制菜单项到<工具>菜单下 (要求IE5.0)
A. 用Guidgen创建一个GUID,然后用这个GUID为名称在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions 下创建一个子键。
B. 接着在该子键下创建一个名为CLSID的字符串值”{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}”(固定值)
C. 同理,创建名为MenuText的为菜单项显示字串,创建名为MenuStatusBar的为菜单高亮时状态栏显示的帮助字串。另外,如果创建名为MenuCustomize的字串”help”,会将定制的菜单项移到<帮助>主菜单下。
D. 要响应菜单命令有三种实现方式: Exe文件,脚本文件,COM对象。
1. 用Exe文件只需在子键下添加名为Exec的值为Exe文件的路径,如C:\Program Files\NETANTS\NetAnts.exe.
2. 用脚本文件只需添加名为script的值为脚本文件的路径。
3. COM实现最复杂,添加名为ClsidExtension字符串值为你为此扩展所创建的COM的GUID。
而你的COM对象必须实现IOleCommandTarget接口.
IOleCommandTarget是一个在Windows扩展中很常用的接口。我以为,定义接口其实就是定义协作各方在某一具体方面的协作规定,顾名思义,IOleCommandTarget就是规定了一种在OLE Container与其包容对象之间的命令传递的方式。
IOleCommandTarget比较简单,有两个要你实现的方法,Exec用于激发命令,执行你定制的功能,QueryStatus用于传递命令的解释性及状态性描述字符串,同注册表的MenuStatusBar项的功能。从具体的传递的参数来讲,你所实现的COM对象中的每一个菜单或按钮命令都以整数标识存在于一个数组中,该数组有一个唯一的GUID标识,使用时依靠命令的整数标识执行相应的操作。更具体的参数含义请见MSDN。

3.添加定制按钮到标准工具栏
基本注册项同上之菜单,接着你可以
创建ButtonText字符串值为按钮的文本标签。
创建HotIcon字符串值为彩色图标的文件路径
创建Icon字符串值为灰色图标的文件路径
创建Default Visible为是否默认可见,值"YES","NO"。
其命令激发机制与上述定制菜单项一致,另外还加进一项打开ExplorerBar功能,将上述2之CLISD项的固定值值改为{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}, 在添加BandCLSID字串值为要打开的浏览栏的CLSID,但这样一来菜单的定制就没了。

4.添加定制的浏览栏,工具栏
以上3种定制比较简单,基本上不用实现COM对象,而要定制浏览栏,工具栏就一定要实现含有必要接口的COM对象。
有4种可定制的栏,水平浏览栏,垂直浏览栏,桌面工具栏,IE工具栏,它们的COM实现基本上是一致的,不同之处仅在于它们在注册表中的注册项。除了相同的必要的COM对象类的注册,还要注册它们各自的Component Category(组件分类), Windows或IE根据其所注册的分类决定它们出现的位置,分别注册为:垂直栏 CATID_InfoBand,水平栏 CATID_CommBand, 桌面栏 CATID_DeskBand,工具栏则按另一种注册方式。
在ATL里要实现分类注册是很简单的,使用宏:
BEGIN_CATEGORY_MAP(你的COM类名称)
IMPLEMENTED_CATEGORY(分组GUID,如CATID_InfoBand)
END_CATEGORY_MAP()

对于工具栏则要在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar下以你实现的COM类的CLSID为名创建一个字符串值,可以手工编写rgs, 如
HKLM
{
    NoRemove Software
    {
        NoRemove Microsoft
        {
            NoRemove 'Internet Explorer'
            {
                NoRemove Toolbar
                {
                    val '{758C84FF-78FD-11D5-91A0-B4078A11DF77}' = b '00'
                }
            }
        }
    }
}

Band COM实现:
每一个Band对象都要实现三个基本接口IDeskBand, IObjectWithSite, IpersistStream,但不要求实现全部接口方法,而且基本实现是相同的。

其中对IPersistStream的要求最简单,你只要实现基接口IPersist的GetClassID,返回你的Band对象的CLSID即可,其余的直接返回即可。

IObjectWithSite也是一个OLE中常用的接口。Site是位于包容器与被包容对象两个概念之间的一个对象,通过它,包容器能对被包容对象的细节进行控制,而被包容对象则能执行自己的功能,而IObjectWithSite就是连通二者的Site对象接口。以IE工具栏为例,包容器就是IE的那个Rebar, Site代表详细的在Rebar提供的位置信息,Site能获得包容器的信息,然后你的COM对象要与Site打交道,这又是通过IObjectWithSite来通信的。
IobjectWithSite包含两个方法:
SetSite是你的栏窗口与IE连接的最重要的一环,要完成如下工作:
1.事先声明一个IInputObjectSite指针的类变量,通过该变量可获得当前站点的信息,而当你的栏窗口被放置到一新站点时,SetSite就被调用,在执行SetSite时如果先前已保留了一个IInputObjectSite应用,就要先释放引用。
2.如果传入的IUnknown为空,表示栏窗口被移除,直接返回即可。
3.如果传入的IUnknown不为空,表示你的栏窗口将被放到一个新Site,这时你要准备创建你的栏窗口,首先向IUnknown索要一个IoleWindow,利用此IOleWindow的GetWindow方法取得父窗口句柄,利用此句柄正式创建你的窗口栏为它的子窗口,最后向IUnknown索要一个IInputObjectSite对象,并保留其引用到上面所声明的类变量。
GetSite就是利用保存的IInputObjectSite指针获取调用者所要求的接口指针。

最后一个要实现的接口是IDeskBand,它本身只有一个GetBandInfo方法,不过由于IDeskBand扩展于IDockingWindow接口,而IDockingWindow又扩展于IOleWindow, 所以连带也要实现它们的接口。不过也很简单。

IOleWindow有两个方法,在GetWindow中返回你创建的栏窗口的句柄,对ContextSensitiveHelp直接返回S_OK.
IDockingWindow有三个方法,在ShowDW中显示或隐藏你的窗口栏,在CloseDW中销毁窗口栏,ResizeBorderDW中返回E_NOTIMPL。
IDeskBand的GetBandInfo根据传入的DESKBANDINFO结构的信息掩码,为其赋给相应的信息值。
另外,如果你要实现栏窗口上的上下文菜单,你必须实现IcontextMenu接口,
以上的接口细节,推荐使用RadBytes的RBDeskBand Wizard一下就可搞定,你根本不用去关心它的实现.,你所作的只是实现你的窗口类。如果使用MFC,你的窗口栏可以直接派生于CWnd或CtoolBar等等;不使用MFC,你可以用ATL的CwindowImpl类来派生窗口类,如果使用RadBytes的CwindowImpl Wizard就更简单了,这样你所做的跟在MFC下没什么区别,真的很好用。

5.捕获浏览器点击,
这个技术牵涉到一个很强大的对象Browser Helper Objects(BHO).
BHO是IE提供的一种可定制控制对象,使用它,你可以监测到IE的各种事件,如 前进,打开一个URL,下载完毕等;可以完全获取IE的菜单,工具栏并定制它;可以定制当前显示页的额外信息窗口,几乎是无所不能。

理所当然的,该对象也是你以COM形式提供的,并且每当一个IE进程实例运行,你的一个BHO实例也随之生成,并与之关联。

除了正常的COM注册,只要在HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects下以你的COM类GUID为名称创建一个子键即可(安装FlashGet的可在这发现它的注册项)。

Browser Helper Objects对象必须的接口只有IObjectWithSite,基本原理与上述一致,但实现的功能是不同的。
在SetSite中,你收到的是一个很谦虚的IUnknown,通过它,你可以索要BHO所在IE实例的IWebBrowser2接口,使用该接口你可以获取当前IE的所有信息,特别是get_Document可获得页面的内容。

要截获某一事件,可以通过上述IWebBrowser2接口索要IConnectionPointerContainer接口,再FindConnectionPoint,找到某一事件对应的出接口的连接点对象,然后用你的COM对象的指针调用Advice注册。从这个角度,你的COM就是一个接收器外象,所以你要实现IDispatch接口(在ATL工程选dual自动实现),并重载Invoke, 响应IE发给你的事件。如:
CComQIPtr m_spWebBrowser2;
CComQIPtr m_spCPC;
CComPtr spCP;

m_spWebBrowser2 = pUnkSite;//pUnkSite是由SetSite传入的
m_spCPC = m_spWebBrowser2;//智能指针在赋值时会自动请求对应变量类型的接口
m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);//DWebBrowserEvents2是出接口
spCP->Advise(reinterpret_cast(this), &m_dwCookie);//this:实现的BHO对象

在IDispatch的OnInvoke中:
if (dispidMember == DISPID_BEFORENAVIGATE2)//传入开始跳转事件 DoYourJob();
具体参数见MSDN索引DWebBrowserEvents2.

选用ATL的Internet Explorer Object向导很可以方便的生成基本实现框架,你只要重载实现必要的功能就可。更详细的资料及代码见MSDN索引Browser Helper Objects,IWebBrowser2。