ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx

上传人:b****7 文档编号:9451342 上传时间:2023-02-04 格式:DOCX 页数:19 大小:136.67KB
下载 相关 举报
ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx_第1页
第1页 / 共19页
ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx_第2页
第2页 / 共19页
ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx_第3页
第3页 / 共19页
ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx_第4页
第4页 / 共19页
ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx

《ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx》由会员分享,可在线阅读,更多相关《ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx(19页珍藏版)》请在冰豆网上搜索。

ATL 实现定制的 IE 浏览器栏工具栏和桌面工具栏.docx

ATL实现定制的IE浏览器栏工具栏和桌面工具栏

ATL实现定制的IE浏览器栏、工具栏和桌面工具栏

作者:

杨老师

下载源代码

关键字:

Band,DeskBand,ExplorerBand,ToolBand,浏览器栏,工具栏,桌面工具栏

一、引言

  最近,由于工作的要求,我需要在IE上做一些开发工作。

于是在MSDN上翻阅了一些资料,根据MSDN上的说明我用ATL胜利完成了“资本家老板”分配的任务。

(并且在白天睡觉的过程中梦到了老板给我加工资啦......)

现在,我把MSDN上的原文资料,经过翻译整理并把一个ATL的实现奉贤给VCKBASE上的朋友们。

∙概念

∙原理

基本band对象

必须实现的COM接口

   IPersistStream

   IObjectWithSite

   IDeskBand、IDockingWindow、IOleWindow

选择实现的COM接口

Band对象注册

∙ATL实现

二、概念

  在翻译的过程中,有两个词汇非常不好理解。

第一个词是Band对象,词典中翻译为“镶边、裙子边、带子、乐队......”我的英文水平有限,实在不知道应该翻译为什么词汇更合适。

于是我毅然决然地决定:

在如下的论述中,依然使用band这个词!

(什么?

没听明白?

我的意思就是说,我不翻译这个词了)但到底Band对象应该如何理解那?

请看图一:

图一

  图一中画红圈的地方,分别称作“垂直的浏览器栏”、“水平的浏览器栏”、“工具栏”和“桌面工具栏”。

这些“栏”,都可以在IE的“查看”菜单中或鼠标右键的上下文快捷方式菜单中显示或隐藏起来。

这些界面窗口的实现,其实就是实现一种COM接口对象,而这个对象叫band。

这个概念实在是只能意会而无法言传的,我总不能在文章中把它翻译为“总是靠在IE主窗口边上的对象”吧?

^_^

  另外,还有一个词叫site。

这个很好翻译,叫“站点”!

呵呵,我敢打包票,如果你要能理解这个翻译在计算机类文章中的含义,那就只能恭喜你了,你的智慧太高了。

(都是学计算机软件的人,做人的差距咋就这么大呢?

)在本篇文章中,site可以这样理解:

IE的主框架四周,就好比是“汽车站”,那些band对象,就好比是“汽车”。

band汽车总是可以停靠在“汽车站”上。

所以,site就是“站点”,它也是COM接口的对象(IObjectWithSite、IInputObjectSite)。

三、原理

3.1 基本band对象

  Band对象,从Shell4.71(IE5.0)开始提供支持。

Band是一个COM对象,必须放在一个容器中去使用,当然使用它们就好象使用普通窗口是一样的。

IE就是一个容器,桌面Shell也是一个容器,它们提供不同的函数功能,但基本的实现是相似的。

  Band对象分三种类型,浏览器栏band(Explorerbands)、工具栏band(ToolBands)和桌面工具栏(Deskbands),而浏览器栏band又有两种表现形式:

垂直和水平的。

那么IE和Shell如何区分并加载这些bands对象呢?

方法是:

你要对不同的band对象,在注册表中注册不同的组件类型(CATID)。

Band样式

组件类型

CATID

垂直的浏览器栏

CATID_InfoBand

00021493-0000-0000-C000-000000000046

水平的浏览器栏

CATID_CommBand

00021494-0000-0000-C000-000000000046

桌面的工具栏

CATID_DeskBand

00021492-0000-0000-C000-000000000046

  IE工具栏不使用组件类型注册,而是使用在注册进行CLSID的登记方式。

详细情况见3.3。

  在例子程序中,实现了全部四个类型的band对象,垂直浏览器栏(CVerticalBar)显示了一个HTML文件,并且实现了对IE主窗口浏览网页的导航等功能;水平的浏览器栏(CHorizontalBar)是一个编辑窗,它同步显示当前网页的BODY源文件内容;IE工具栏(CToolBar)最简单,只是添加了一个空的工具栏;桌面工具栏(CDeskBar)实现了一个单行编辑窗口,你可以在上面输入命令行或文件名称,回车后它会执行Shell的打开动作。

3.2 必须实现的COM接口

  Band对象是IE或Shell的进程内服务器,所以它被包装在DLL中。

而作为COM对象,它必须要实现IUnknown和IClassFactory接口。

(大家可以不同操心,因为我们用ATL写程序,这两个接口是不用我们自己写代码的。

)另外,Band对象还必须实现IDeskBand、IObjectWithSite和IPersistStream三个接口:

  IPersistStream是持续性接口的一种。

当IE加载band对象的时候,它通过这个接口的Load方法传递属性值给对象,让其进行初始化;而当卸载前,IE则调用这个接口的Save方法保存对象的属性。

用ATL实现这个接口很简单:

classATL_NO_VTABLECxxx:

......

publicIPersistStreamInitImpl,//添加继承

......

{

public:

BOOLm_bRequiresSave;//IPersistStreamInitImpl所必须的变量

......

BEGIN_COM_MAP(CVerticalBar)

......

COM_INTERFACE_ENTRY2(IPersist,IPersistStreamInit)

COM_INTERFACE_ENTRY2(IPersistStream,IPersistStreamInit)

COM_INTERFACE_ENTRY(IPersistStreamInit)

......

END_COM_MAP()

BEGIN_PROP_MAP(Cxxx)

......//添加需要持续性的属性

END_PROP_MAP()

  上面的代码,其实实现的是IPersistStreamInit接口,不过没有关系,因为IPersistStreamInit派生自IPersistStream,实例化了派生类,自然就实例化了基类。

在例子程序中,我只在桌面工具栏对象中添加了持续性属性,用来保存和初始化“命令行”。

另外COM_INTERFACE_ENTRY2(A,B)表示的含义是:

如果想查询A接口的指针,则提供B接口指针来代替。

为什么可以这样那?

因为B接口派生自A接口,那么B接口的前几个函数必然就是A接口的函数了,自然B接口的地址其实和A接口的地址是一样的了。

  IObjectWithSite是IE用来对插件进行管理和通讯用的一个接口。

必须要实现这个接口的2个函数:

SetSite()和GetSite()。

当IE加载band对象和释放band对象的时候,都要调用SetSite()函数,那么在这个函数里正好是写初始化和释放操作代码的地方:

STDMETHODIMPCxxx:

:

SetSite(IUnknown*pUnkSite)

{

if(NULL==pUnkSite)//释放band的时候

{

//如果加载的时候,保存了一些接口

//那么现在:

释放它

}

else//加载band的时候

{

m_hwndParent=NULL;//装载band的父窗口(就是带有标题的那个框架窗口)

//这个窗口的句柄,是调用IUnknown:

:

QueryInterface()得到IOleWindow

//然后调用IOleWindow:

:

GetWindow()而获得的。

CComQIPtrspOleWindow(pUnkSite);

if(spOleWindow)spOleWindow->GetWindow(&m_hwndParent);

if(!

m_hwndParent)returnE_FAIL;

//现在,正好是建立子窗口的时机。

//注意,子窗口建立的时候,不要使用WS_VISIBLE属性

......

//在例子程序中,用CAxWindow实现了一个能包容ActiveX的容器窗口(垂直浏览器栏)

//在例子程序中,用WINAPI函数CreateWindow实现了标准窗口(水平浏览器栏、工具栏)

//在例子程序中,用CWindowImpl实现了一个包容窗口(桌面工具栏)

/*********************************************************/

以下部分,根据band对象特有的功能,是可以选择实现的

**********************************************************/

//如果子窗口实现了用户输入,那么必须实现IInputObject接口,

//而该接口是被IE的IInputObjectSite调用的,因此在你的对象

//中,应该保存IInputObjectSite的接口指针。

//在类的头文件中,定义:

//CComQIPtrm_spSite;

m_spSite=pUnkSite;//保存IInputObjectSite指针

if(!

m_spSite)returnE_FAIL;

//你需要控制IE的主框架吗?

//那么在类的头文件中,定义:

//CComQIPtrm_spFrameWB;

//然后,先取得IServiceProvider,再取得IWebBrowser2

CComQIPtrspSP(pUnkSite);

if(!

spSP)returnE_FAIL;

spSP->QueryService(SID_SWebBrowserApp,&m_spFrameWB);

if(!

m_spFrameWB)returnE_FAIL;

//如果你取得了IE主框架的IWebBrowser2指针

//那么,当它发生了什么事情,你难道不想知道吗?

//定义:

CComPtrm_spCP;

CComQIPtr

&IID_IConnectionPointContainer>spCPC(m_spFrameWB);

if(spCPC)

{

spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2,&m_spCP);

if(m_spCP)

{

m_spCP->Advise(reinterpret_cast(this),&m_dwCookie);

}

}

//咳~~~不说了,看源码去吧。

这里能干的事情太多了......

}

returnS_OK;

}

IDeskBand是一个特殊的band对象接口,有一个方法函数:

GetBarInfo();

IDockingWindow是IDeskBank的基类,有3个方法函数:

ShowDW()、CloseDW()、ResizeBorderDW();

IOleWindow又是IDockingWindow的基类,有2个方法函数:

GetWindow()、ContextSensitiveHelp();

  首先声明IDeskBand,然后要实现IDeskBand接口的共6个函数,这些函数比较简单,不同类型的band对象,其实现方法也都基本一致:

classATL_NO_VTABLECxxx:

......

publicIDeskBand,

......

{

......

BEGIN_COM_MAP(Cxxx)

......

COM_INTERFACE_ENTRY_IID(IID_IDeskBand,IDeskBand)

......

END_COM_MAP()

 

//IOleWindow

STDMETHODIMPCxxx:

:

GetWindow(HWND*phwnd)

{//取得band对象的窗口句柄

//m_hWnd是建立窗口时候保存的

*phwnd=m_hWnd;

returnS_OK;

}

STDMETHODIMPCxxx:

:

ContextSensitiveHelp(BOOLfEnterMode)

{//上下文帮助,参考IContextMenu接口

returnE_NOTIMPL;

}

//IDockingWindow

STDMETHODIMPCVerticalBar:

:

ShowDW(BOOLbShow)

{//显示或隐藏band窗口

if(m_hWnd)

:

:

ShowWindow(m_hWnd,bShow?

SW_SHOW:

SW_HIDE);

returnS_OK;

}

STDMETHODIMPCVerticalBar:

:

CloseDW(DWORDdwReserved)

{//销毁band窗口

if(:

:

IsWindow(m_hWnd))

:

:

DestroyWindow(m_hWnd);

m_hWnd=NULL;

returnS_OK;

}

STDMETHODIMPCVerticalBar:

:

ResizeBorderDW(LPCRECTprcBorder,IUnknown*punkToolbarSite,BOOLfReserved)

{//当框架窗口的边框大小改变时

returnE_NOTIMPL;

}

//IDeskBand

STDMETHODIMPCVerticalBar:

:

GetBandInfo(DWORDdwBandID,DWORDdwViewMode,DESKBANDINFO*pdbi)

{

//取得band的基本信息,你需要填写pdbi参数作为返回

if(NULL==pdbi)returnE_INVALIDARG;

//如果将来需要调用IOleCommandTarget:

:

Exec()则需要保存这2个参数

m_dwBandID=dwBandID;

m_dwViewMode=dwViewMode;

if(pdbi->dwMask&DBIM_MINSIZE)

{//最小尺寸

pdbi->ptMinSize.x=10;

pdbi->ptMinSize.y=10;

}

if(pdbi->dwMask&DBIM_MAXSIZE)

{//最大尺寸(-1表示4G)

pdbi->ptMaxSize.x=-1;

pdbi->ptMaxSize.y=-1;

}

if(pdbi->dwMask&DBIM_INTEGRAL)

{

pdbi->ptIntegral.x=1;

pdbi->ptIntegral.y=1;

}

if(pdbi->dwMask&DBIM_ACTUAL)

{

pdbi->ptActual.x=0;

pdbi->ptActual.y=0;

}

if(pdbi->dwMask&DBIM_TITLE)

{//窗口标题

wcscpy(pdbi->wszTitle,L"窗口标题");

}

if(pdbi->dwMask&DBIM_MODEFLAGS)

{

pdbi->dwModeFlags=DBIMF_VARIABLEHEIGHT;

}

if(pdbi->dwMask&DBIM_BKCOLOR)

{//如果使用默认的背景色,则移除该标志

pdbi->dwMask&=~DBIM_BKCOLOR;

}

returnS_OK;

}

3.3 选择实现的COM接口

  有两个接口不是必须实现的,但也许很有用:

IInputObject和IContextMenu。

如果band对象需要接收用户的输入,那么必须实现IInputObject接口。

IE实现了IInputObjectSite接口,当容器中有多个输入窗口时,它调用IInputObject接口方法去负责管理用户的输入焦点。

在浏览器栏中需要实现3个函数:

UIActivateIO()、HasFocusIO()、TranslateAcceleratorIO()。

当浏览器栏激活或失去活性的时候,IE调用UIActivateIO函数,当激活的时候,浏览器栏一般调用SetFocus去设置它自己窗口的焦点。

当IE需要判断哪个窗口有焦点的时候,它调用HasFocusIO。

当浏览器栏的窗口或其子窗口有输入焦点时,则应返回S_OK,否则返回S_FALSE。

TranslateAcceleratorIO允许对象处理加速键,例子程序中没有实现,所以直接返回S_FALSE。

STDMETHODIMPCExplorerBar:

:

UIActivateIO(BOOLfActivate,LPMSGpMsg)

{

if(fActivate)

SetFocus(m_hWnd);

returnS_OK;

}

STDMETHODIMPCExplorerBar:

:

HasFocusIO(void)

{

if(m_bFocus)

returnS_OK;

returnS_FALSE;

}

STDMETHODIMPCExplorerBar:

:

TranslateAcceleratorIO(LPMSGpMsg)

{

returnS_FALSE;

}

  Band对象能够通过包容器的IOleCommandTarget:

:

Exec()调用执行命令。

而IOleCommandTarget接口指针,则可以通过调用包容器的IInputOjbectSite:

:

QueryInterface(IID_IOleCommandTarget,...)函数得到。

CGID_DeskBand是命令组,当一个band对象的GetBandInfo被调用的时候,包容器通过dwBandID参数指定一个ID给band对象,对象要保存住这个ID,以便调用IOleCommandTarget:

:

Exec()的时候使用。

ID的命令有:

∙DBID_BANDINFOCHANGED

Band的信息变化。

设置参数pvaIn为bandID,该ID就是最近一次调用GetBandInfo所得到的值,容器会调用band对象的GetBandInfo函数来更新请求信息。

∙DBID_MAXIMIZEBAND

最大化band。

设置参数pvaIn为bandID,该ID就是最近一次调用?

GetBandInfo?

所得到的值。

∙DBID_SHOWONLY

打开或关闭容器中其它的bands。

设置参数pvaIn为VT_UNKNOWN类型,它可以是如下的值:

 

描述

pUnk

band对象的IUnknown指针,其它的桌面bands将被隐藏

0

隐藏所有的桌面bands

1

显示所有的桌面bands

∙DBID_PUSHCHEVRON

在菜单项左边显示“v”的选择标志。

容器发送一个RB_PUSHCHEVRON消息,当band对象接收到通知消息RBN_CHEVRONPUSHED提示它显示一个"v"的标志。

设置IOleCommandTarget:

:

Exec函数中nCmdExecOpt参数为bandID,该ID是最近一次调用GetBandInfo?

所得到的值,设置IOleCommandTarget:

:

Exec函数中pvaIn参数为VT_I4类型,这是应用程序定义的一个值,它通过通知消息RBN_CHEVRONPUSHED中lAppValue回传给band对象。

3.4 Band对象注册

  Band对象必须注册为一个OLE进程内的服务器,并且支持apartment线程公寓。

注册表中默认键的值是表示菜单的文字。

对于浏览器栏,它加到IE菜单的“查看\浏览器栏”中;对于工具栏band,它加到IE菜单的“查看\工具栏”中;对于桌面band,它加到系统任务栏的快捷菜单中。

在菜单资源中,可以使用“&”指明加速键。

通常,一个基本的band对象的注册表项目是:

HKEY_CLASSES_ROOT

CLSID

{你的band对象的CLSID}

  (Default)=菜单的文字

  InProcServer32

   (Default)=DLL的全路径文件名

   ThreadingModel=Apartment

工具栏bands还必须把它们的CLSID注册到IE的注册表中。

在HKEY_LOCAL_MACHINE\Software\Microsoft\InternetExplorer\Toolbar下给出CLSID作为键名,而其键值是被忽略的。

HKEY_LOCAL_MACHINE

Software

Microsoft

InternetExplorer

Toolbar

  {你的band对象的CLSID}

  还有几个可选的注册表项目(例子程序并不是这样实现的)。

比如,你想让浏览器栏显示HTML的话,必须要如下设置注册表:

HKEY_CLASSES_ROOT

CLSID

{你的Band对象的CLSID}

Instance

CLSID

  (Default)={4D5C8C2A-D075-11D0-B416-00C04FB90376}

同时,如果要指定一个本地的HTML文件,那么要如下设置:

HKEY_CLASSES_R

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 其它课程

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1