DeskBand实现之——对象介绍

最近的项目上用到了Desk Band这种东西,我也是第一次做这个,做完后感觉收获很多,本文就讲一个如果实现一个自定义的Desk Band COM对象。

 

1. Band对象介绍


Windows的区(Bands)对象有三种:浏览栏(Explorer Bar)区对象,工具栏(Tools Bands)区对象,和桌面区对象(Desk Bands)。

本文主要讲一下桌面区对象的实现。

Desk Band出现在任务栏上,也可以是桌面浮动窗口。通过在任务栏上单击右键,然后在弹出的菜单中选择“工具栏”的子菜单项。如下图所示:


桌面区位于Windows外壳(Shell)中,它是由explorer.exe来调用的。它是一个COM对象,必须存在于某个容器中,这个容器就是任务栏。在这个COM对象(Band)注册时,可以选择不同的对象类型及容器,也就是说,在注册时除了注册它们的CLSID之外,浏览栏和桌面区对象还必须进行组件类别(category)的注册,它决定了对象的类型及其容器。工具需要进行种类注册。归纳起来,需要进行CATID注册的在种区对象是:



2. 实现区对象

2.1 实现的接口

      下图展示了Desk Band所实现的接口,包括必须实现的可选择实现的接口:


如果某个区对象接受用户输入,它还必须实现IInputObject接口。如果要往上下文菜单中添加菜单项目,还必须实现IContextMenu接口。注意:工具栏区对象不支持上下文菜单。

IDeskBand——这是最重要的接口,它派生于IDockingWIndow,而IDockingWIndow又派生于IOleWIndow。它有一个方法,GetBandInfo,这个方法可以得到窗体的大小,标题,背景色等信息。

IDeskBand2这个接口用于出现玻璃效果,有三个方法:CanRenderComposited,SetCompositionState和GetCompositionState。

IOleWindow有两个方法:GetWindow 和 ContextSensitiveHelp。GetWindow用于得到Band对象窗体的句柄。

IDockingWindow有三个方法:ShowDW,CloseDW和ResizeBorderDW。ShowDW用于显示或隐藏窗体,CloseDW用于关闭窗体,调用DestroyWindow来销毁窗体,ResizeBorderDW一般不用实现。


2.2 注册

区对象必须作为进程内服务器(in-process)注册。其线程模型必须为“Apartment”。也就是说区对象必须以DLL的形式来实现。用来描述服务器注册条目的缺省值是一个菜单文本串。

通常区对象的注册条目如下:


2.3 执行顺序


Windows(桌面band用于资源管理器,浏览栏用于IE)通过查找实现了CATID_DeskBand,,CATID_InfoBand,或 CATID_CommBand的COM对象来发现band对象,并将band的名字添加到工具栏菜单。

1、当用户从菜单选中band时,Windows调用CoCreateInstance或它的同等函数。COM则调用DLL中的 DllGetClassObject输出函数,COM用正确的 ID搜索到一个类工厂并将它返回。然后COM调用IClassFactory::CreateInstance进行一系列的COM常规处理。

关键就是类工厂能正确找到我们自己写的COM,那说明我们要重写IClassFactory::CreateInstance,让它能正确创建出我们写的COM的对象。

2、Windows调用IObjectWithSite::SetSite给出一个(IUnknown*)类型的指针指向对象容器,在这个函数里面我们就要创建BAND对象的窗口了。注意,此时创建的窗口一定要是不可见的,即保证不要使用WS_VISIBLE来创建窗口。

3、接下来,Windows调用IOleWindow::GetWindow来获得窗口的HWND。(这就是为什么你必须在SetSite中创建窗口的原因)。

4、接着,Windows调用IDeskBand::GetBandInfo请求关于band的信息,如大小,可变高度或者定高,以及背景颜色和标题。

5、接着,Windows调用IDockingWindow::ShowDW来显示窗体。

6、当用户关闭Band时,Windows调用IDockingWindow::CloseDW。

 

通常,IObjectWithSite::SetSite实现应该完成下列步骤:

1. 释放当前所把持的任何现场指针。

2. 如果传递到SetSite的指针被置为NULL,此则区对象被删除。SetSite可以返回S_OK。

3. 如果传递到SetSite的指针被置为非NULL,则建立新的现场。SetSite应该做以下的事情:

   a)调用现场QueryInterface方法请求IOleWindow接口。

   b)调用IOleWindow::GetWindow获取父窗口句柄,并存储它,以便以后使用。如果不再使用的话,就释放IOleWindow接口。

   c)创建此band对象的窗口为一个子窗口,其父窗口就是上一步获得的那个窗口。注意在此不能将它创建成可见窗口。

   d)如果此band对象实现IInputObject,调用现场QueryInterface方法请求IInputObjectSite接口,存储这个接口的指针以备后用。

   e)如果所有步骤都成功,则返回S_OK,否则返回OLE定义的错误代码以指示错误类型。

 

未完待续,下一篇我将给出一些具体实现细节和代码。


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值