图二
为了创建定制的浏览栏,必须编程实现,然后注册它们。Windows在外壳(Shell)4.71中引入了区对象。它提供与普通窗口一样的功能。但因为它是以IE或外壳为容器的COM对象,所以实现起来就与普通窗口有所不同。图一中显示的就是一个简单的浏览栏例子。图中有一个垂直的浏览栏和一个水平的浏览栏。
工具栏区对象简称工具栏,它是在IE5.0中引入用以支持单选工具栏(radio toolbar)特性的。IE工具栏实际上是一个Rebar控件,它包含了几个工具栏(toolbar)控件。通过创建工具栏,你可以将某个区对象功能添加到Rebar控件中。不论是在IE中还是在资源管理器中,区对象都是一样的,所以工具栏也是一个通用窗口。(如图三)
图三
用户可以从“查看”菜单中的“工具栏”子菜单中选择显示单选工具栏,也可以在工具栏区域单击鼠标右键从它的上下文菜单中选择显示单选工具栏。
区对象也可以用在桌面,也就是创建桌面区对象。虽然它们的基本实现与浏览栏类似,但桌面区与IE没有关系,它不用IE作为容器。它主要用来创建桌面浮动窗口。通过在任务栏上单击右键,然后在弹出的菜单中选择“工具栏”的子菜单选项。(如图四)
图四
桌面区的初始浮动位置在任务栏:(如图五
图五
用户可以将桌面区拖到桌面上,这时它就成了一个普通窗口:(如图六)
![](/document/journal/vckbase11/images/112700106.GIF)
图六
--------------------next---------------------
尽管可以像使用普通窗口一样使用区对象,但它们毕竟是COM对象,存在于某个容器之中。如浏览栏和工具栏位于IE之中,桌面区位于外壳之中。虽然它们的功能不同,但其基本实现非常相似。一个主要的差别是它们的注册方式不同,而注册方式的不同又决定了对象的类型及其容器。这一部分我们先讨论所有区对象实现的共性。其它的实现细节可参考。
区对象除了要实现 IUnknown 和 IClassFactory 两个接口之外,所有的区对象还必须实现以下这几个接口:
- IDeskBand
- IObjectWithSite
- IPersistStream
另外,在注册时除了注册它们的CLSID之外,浏览栏和桌面区对象还必须进行组件类别(category)的注册。它决定了对象的类型及其容器。工具栏不需要进行种类注册。归纳起来,需要进行CATID注册的三种区对象是:
区对象类型 |
组件类型 |
垂直浏览栏 |
CATID_InfoBand |
水平浏览栏 |
CATID_CommBand |
桌面区 |
CATID_DeskBand |
对于如何注册区对象的进一步讨论请参见。
如果某个区对象接受用户输入,它还必须实现IInputObject接口。如果要往上下文菜单中添加菜单项目,还必须实现IContextMenu接口。注意:工具栏区对象不支持上下文菜单。
因为区对象实现的是子窗口,所以它们还必须有窗口过程来处理Windows的消息。
区对象可以通过其IOleCommandTarget接口发送命令到它的容器。为了得到这个接口的指针,必须调用容器的IInputObjectSite::QueryInterface方法
来请求IID_IoleCommandTarget。然后用IOleCommandTarget::Exec把命令发送到容器。命令组是CGID_DeskBand。当某个区对象的IDeskBand::GetBandInfo方法被调用时,容器用dwBandID参数将一个标示符赋给这个对象。这个标示符被用于IOleCommandTarget::Exec方法调用时所用命令组中的三个命令。目前命令组共支持四个IOleCommandTarget::Exec命令IDs。这四个命令的解释如下:
DBID_BANDINFOCHANGED——Band的信息已改变。参数pvaIn的值应该是最近一次调用所用的band标示符。容器将调用这个标示符所指的band对象的IDeskBand::GetBandInfo方法请求更新的信息。
DBID_MAXIMIZEBAND——容器将最大化band。参数pvaIn的值应该是最近一次调用所用的band标示符。
DBID_SHOWONLY——关闭或打开容器中其它band。参数pvaIn的值为VT_UNKNOWN类型,可以取下列值之一:
值 |
描述 |
pUnk |
这个对象IUnknown接口的指针。所有其它的桌面band将被隐藏。 |
0 |
隐藏所有桌面band。 |
1 |
显示所有桌面band。 |
DBID_PUSHCHEVRON——目前没有实现。
区对象必须作为进程内服务器(in-process)注册。其线程模型必须为“Apartment”。也就是说区对象必须以DLL的形式来实现。用来描述服务器注册条目的缺省值是一个菜单文本串。就拿浏览栏来说。这个菜单出现在资源管理器或IE
“查看(View)”菜单的“浏览栏(Explorer Bar)”子菜单中。而工具栏的菜单则出现在资源管理器或IE “查看(View)”菜单的“工具栏(Toolbars)”子菜单中。桌面区出现在任务栏上下文菜单的“工具栏(Toolbars)”子菜单中。作为菜单资源,提供键盘快捷的方法与一般菜单快捷键相同。也就是将“&”字符放在某个单词字母前表示这个字母显示下划线来指示快捷键。
通常区对象的注册条目如下:
HKEY_CLASSES_ROOT
...
CLSID
...
{Band 对象的 CLSID GUID} = "菜单文本串"
InProcServer32 = "DLL 路径名"
ThreadingModel = "Apartment"
工具栏区对象必须还要注册对象的CLSID。为此必须在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet
Explorer\Toolbar下创建一个REG_SZ值,用工具栏区对象的CLSID GUID串命名。如:
HKEY_LOCAL_MACHINE
Software
Microsoft
Internet Explorer
Toolbar
{ Band 对象的 CLSID GUID }
除此之外,还有几个可选的注册值可以加到注册表中,本文的例子中未使用这些值。
- HKEY_CLASSES_ROOT\CLSID\{Band 对象的 CLSID GUID}\Instance\CLSID, 它应该被设置为
"{4D5C8C2A-D075-11D0-B416-00C04FB90376}".
- HKEY_CLASSES_ROOT\CLSID\{Band对象的CLSID GUID}\Instance\InitPropertyBag\Url
它应该被设置为要在浏览栏显示的包含HTML内容的文件位置。
- \HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Explorer Bars\{Band
对象的 CLSID GUID}\BarSize 它应该被设置为栏目的高和宽,它需要八个字节才能作为串放入注册表,字节之间用逗号分开。开始的四个字节一像素为单位指定大小,格式要用十六进制,从最左边字节开始。最后四个字节是保留字节,应该将它置为零。例如,垂直浏览栏的缺省宽度为291(0x123)像素,则BarSize
的值应该是"23,01,00,00,00,00,00,00"
如果要用浏览栏显示HTML,则前两个注册项是必须的。最后一个注册项则根据垂直的或者水平的浏览栏定义相应的缺省宽度和高度。
能显示HTML的浏览栏(缺省宽度为291各像素单位)注册表条目的形式如下:
HKEY_CLASSES_ROOT
...
CLSID
...
{Band 对象的 CLSID GUID} = "菜单文本串"
InProcServer32 = "DLL 路径名"
ThreadingModel = "Apartment"
Instance
CLSID = "{4D5C8C2A-D075-11D0-B416-00C04FB90376}"
InitPropertyBag
Url = "HTML文件"
...
HKEY_CURRENT_USER
...
Software
...
Microsoft
...
Internet Explorer
...
Explorer Bars
{ Band 对象的 CLSID GUID }
BarSize = "23,01,00,00,00,00,00,00"
你可以通过编程的方式来处理区对象类别 CATID 的注册。创建一个组件类别管理器对象(CLSID_StdComponentCategoriesMgr)并请求一个指向ICatRegister接口的指针。将区对象的CLSID和CATID传递到ICatRegister::RegisterClassImplCategories。
这个例子展示了前面所介绍过的垂直浏览栏的整个实现过程。它借助了平台SDK(Platform SDK——在msdn中可以找到)中关于band对象示范代码。其中还包括了水平浏览栏和桌面band的实现代码。详细实现细节请参见:CommBand.cpp和DeskBand.cpp。
创建定制浏览栏的基本过程是这样的:
- 实现DLL需要的函数。
- 实现必须的COM接口。
- 实现任何想要的可选接口。
- 注册对象的CLSID。
- 进行恰当的组件种类注册。
- 创建IE子窗口,调整窗口大小适合浏览栏的显示区域。
- 使用子窗口显示信息并与用户交互。
实际上,只要通过恰当的组件种类注册,浏览栏例子代码便既可用于浏览栏的实现,也能用于桌面band实现。更加复杂的实现将需要定制每种对象类型的显示区域和容器。但大多数的定制工作都能通过范例代码以及Windows子窗口的编程技术来完成。例如,你可以添加用户交互控制或者进行色彩丰富的图形显示处理。
所有三种区对象被打包在一个DLL中,它输出以下的函数:
- DllMain
- DllCanUnloadNow
- DllGetClassObject
- DllRegisterServer
这些函数可以在BandObjs.cpp中找到,它们服务于所有三种区对象。前三个函数乃标准的实现,我们不再本文中讨论。类工厂也是标准实现,代码可以在ClsFact.cpp中找到
有了COM对象后,必须对浏览栏的CLSID进行注册。另外如果要与IE或资源管理器
协调运行,还必须进行的恰当的组件种类(CATID_InfoBand)注册。这个工作由DllRegisterServer处理。浏览栏例子代码有关的处理部分如下:
...
//注册浏览栏对象
if(!RegisterServer(CLSID_SampleExplorerBar, TEXT("垂直浏览栏例子")))
return SELFREG_E_CLASS;
//注册浏览栏的对象组件种类
if(!RegisterComCat(CLSID_SampleExplorerBar, CATID_InfoBand))
return SELFREG_E_CLASS;
...
区对象的注册使用通常的COM过程,它由私有函数RegisterServer处理。
除了CLSID之外,这个区对象服务器还必须注册一个以上的组件种类。这实际上是垂直浏览栏和水平浏览栏实现之间的主要差别。这个过程的处理是通过创建一个组件种类管理器对象(CLSID_StdComponentCategoriesMgr),并用ICatRegister::RegisterClassImplCategories方法来注册区对象服务器。在这个例子中,组件种类注册的处理是通过将浏览栏的CLSID和CATID传递到私有函数RegisterComCat完成的:
BOOL RegisterComCat(CLSID clsid, CATID CatID)
{
ICatRegister *pcr;
HRESULT hr = S_OK ;
CoInitialize(NULL);
hr = CoCreateInstance( CLSID_StdComponentCategoriesMgr,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICatRegister,
(LPVOID*)&pcr);
if(SUCCEEDED(hr))
{
hr = pcr->RegisterClassImplCategories(clsid, 1, &CatID);
pcr->Release();
}
CoUninitialize();
return SUCCEEDED(hr);
}
--------------------next---------------------