没有找到合适的产品?
联系客服协助选型:023-68661681
提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
翻译|其它|编辑:郝浩|2006-03-02 12:08:00.000|阅读 2040 次
概述:
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
下载源代码
关键字:Band,Desk Band,Explorer Band,Tool
Band,浏览器栏,工具栏,桌面工具栏
一、引言
最近,由于工作的要求,我需要在 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 对象,从 Shell 4.71(IE 5.0) 开始提供支持。Band 是一个 COM
对象,必须放在一个容器中去使用,当然使用它们就好象使用普通窗口是一样的。IE 就是一个容器,桌面 Shell
也是一个容器,它们提供不同的函数功能,但基本的实现是相似的。
Band 对象分三种类型,浏览器栏 band(Explorer bands)、工具栏 band(Tool Bands)和桌面工具栏(Desk
bands),而浏览器栏 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-00000000004 |
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 实现这个接口很简单:
class ATL_NO_VTABLE Cxxx :
......
public IPersistStreamInitImpl, // 添加继承
......
{
public:
BOOL m_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()函数,那么在这个函数里正好是写初始化和释放操作代码的地方:
STDMETHODIMP Cxxx::SetSite(IUnknown *pUnkSite)
{
if( NULL == pUnkSite ) // 释放 band 的时候
{
// 如果加载的时候,保存了一些接口
// 那么现在:释放它
}
else // 加载 band 的时候
{
m_hwndParent = NULL; // 装载 band 的父窗口(就是带有标题的那个框架窗口)
// 这个窗口的句柄,是调用
IUnknown::QueryInterface() 得到 IOleWindow
// 然后调用 IOleWindow::GetWindow() 而获得的。
CComQIPtr< IOleWindow, &IID_IOleWindow >
spOleWindow(pUnkSite);
if( spOleWindow ) spOleWindow->GetWindow(&m_hwndParent);
if( !m_hwndParent ) return E_FAIL;
// 现在,正好是建立子窗口的时机。
// 注意,子窗口建立的时候,不要使用 WS_VISIBLE 属性
... ...
// 在例子程序中,用 CAxWindow
实现了一个能包容ActiveX的容器窗口(垂直浏览器栏)
// 在例子程序中,用 WIN API 函数 CreateWindow
实现了标准窗口(水平浏览器栏、工具栏)
// 在例子程序中,用 CWindowImpl 实现了一个包容窗口(桌面工具栏)
/*********************************************************/
以下部分,根据 band
对象特有的功能,是可以选择实现的
**********************************************************/
//
如果子窗口实现了用户输入,那么必须实现 IInputObject 接口,
// 而该接口是被 IE 的
IInputObjectSite 调用的,因此在你的对象
// 中,应该保存
IInputObjectSite 的接口指针。
// 在类的头文件中,定义:
// CComQIPtr<
IInputObjectSite, &IID_IInputObjectSite > m_spSite;
m_spSite = pUnkSite; // 保存 IInputObjectSite 指针
if( !m_spSite ) return E_FAIL;
// 你需要控制 IE 的主框架吗?
// 那么在类的头文件中,定义:
// CComQIPtr< IWebBrowser2,
&IID_IWebBrowser2 > m_spFrameWB;
// 然后,先取得 IServiceProvider,再取得 IWebBrowser2
CComQIPtr < IServiceProvider, &IID_IServiceProvider>
spSP(pUnkSite);
if( !spSP ) return E_FAIL;
spSP->QueryService( SID_SWebBrowserApp, &m_spFrameWB
);
if( !m_spFrameWB) return E_FAIL;
// 如果你取得了 IE 主框架的
IWebBrowser2 指针
// 那么,当它发生了什么事情,你难道不想知道吗?
// 定义:CComPtr m_spCP;
CComQIPtr< IConnectionPointContainer,
&IID_IConnectionPointContainer> spCPC(
m_spFrameWB );
if( spCPC )
{
spCPC->FindConnectionPoint(
DIID_DWebBrowserEvents2, &m_spCP );
if( m_spCP )
{
m_spCP->Advise( reinterpret_cast< IDispatch * >( this ), &m_dwCookie );
}
}
}
return S_OK;
}
IDeskBand 是一个特殊的 band 对象接口,有一个方法函数:GetBarInfo();
IDockingWindow 是 IDeskBank 的基类,有3个方法函数:ShowDW()、CloseDW()、ResizeBorderDW();
IOleWindow 又是 IDockingWindow 的基类,有2个方法函数:GetWindow()、ContextSensitiveHelp();
首先声明 IDeskBand ,然后要实现 IDeskBand 接口的共6个函数,这些函数比较简单,不同类型的 band 对象,其实现方法也都基本一致:
class ATL_NO_VTABLE Cxxx :
......
public IDeskBand,
......
{
......
BEGIN_COM_MAP(Cxxx)
......
COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
......
END_COM_MAP()
// IOleWindow
STDMETHODIMP Cxxx::GetWindow(HWND * phwnd)
{ // 取得 band 对象的窗口句柄
// m_hWnd 是建立窗口时候保存的
*phwnd = m_hWnd;
return S_OK;
}
STDMETHODIMP Cxxx::ContextSensitiveHelp(BOOL fEnterMode)
{ // 上下文帮助,参考 IContextMenu 接口
return E_NOTIMPL;
}
// IDockingWindow
STDMETHODIMP CVerticalBar::ShowDW(BOOL bShow)
{ // 显示或隐藏 band 窗口
if( m_hWnd )
::ShowWindow(
m_hWnd, bShow ? SW_SHOW : SW_HIDE);
return S_OK;
}
STDMETHODIMP CVerticalBar::CloseDW(DWORD dwReserved)
{ // 销毁 band 窗口
if( ::IsWindow( m_hWnd ) )
::DestroyWindow( m_hWnd );
m_hWnd = NULL;
return S_OK;
}
STDMETHODIMP CVerticalBar::ResizeBorderDW(LPCRECT prcBorder,
IUnknown* punkToolbarSite, BOOL fReserved)
{ // 当框架窗口的边框大小改变时
return E_NOTIMPL;
}
// IDeskBand
STDMETHODIMP CVerticalBar::GetBandInfo(DWORD dwBandID, DWORD
dwViewMode, DESKBANDINFO* pdbi)
{
// 取得 band
的基本信息,你需要填写 pdbi 参数作为返回
if( NULL == pdbi ) return
E_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;
}
return S_OK;
}
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com
面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@evget.com
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢
慧都科技 版权所有 Copyright 2003-
2025 渝ICP备12000582号-13 渝公网安备
50010702500608号