荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: oopilix (冬眠的抽象实例), 信区: Visual
标  题: [zz]《COM技术内幕》学习笔记(5)
发信站: 荔园晨风BBS站 (Mon Oct 20 13:29:32 2003), 站内信件

原作者姓名 雷神
文章原始出处 http://www.ai361.com

介绍
"只有当大家都不知道自己在使用COM的时侯,COM才是成功的。” ----- Greg
Hope, Microsoft


读者评分 3 评分次数 1

正文
第五部分:
"只有当大家都不知道自己在使用COM的时侯,COM才是成功的。” ----- Greg
Hope, Microsoft
这是COM集中营( http://comcamp.myrice.com/ )站长lostall在站点首页的引用
的一句话。在1个月前我还不能体会它的意思,但现在已经有点心得了。当你在你
的WORD文档中嵌入一个电子表格时,简单的可以用易如翻掌来形容。因为它使用了
OLE,而OLE正是COM的一个应用。如何使COM的应用变的简单高效正是第九章要说的


附:COM集中营是一个很有特点的网站,站长LOSTALL写了很多与COM/DOCM相关原创
文章,虽然不算多,但都是精品。正如网站的名称它是一个关于COM的专业站点。


FAQ36:COM组件的“叉烧包”(trouble)?〖第九章〗
FAQ37:关于智能接口指针?〖第九章〗
FAQ38:关于包装类?〖第九章〗
FAQ39:关于接口基类CUnknown? 〖第九章〗
FAQ40:关于类厂基类CFactory? 〖第九章〗
FAQ41:如何应用CUnknown和CFactory?〖第九章〗

Question:
    COM组件的“叉烧包”(trouble)?
Answer:
    COM组件不能象典型的C++类那样简单使用。
    COM组件必须进行引用记数。
    如果不慎访问了某个已被释放的组件上的接口指针,则应用程序崩溃。
    如果程序发生异常,异常处理并不会调用Release释放COM组件。
    除了正确的处理引用记数问题外,QueryInterface的代码还必须做很多的工作
使它合理化。
    但QueryInterface不是类型安全的。

Question:
    关于智能接口指针?
Answer:
    智能接口指针是用来封装接口指针的。
    智能指针实际上就是一个重载了操作符->的类。
    智能指针包含指向另外一个对象的指针。
    智能接口指针包含的指针指向一个接口。
可以通过一个接口类型指向其IID的指针来创建接口指针。
然后调用CoCreateInstance来创建所需的组件并获得其指针。
当程序执行离开智能指针的作用域时,它将在它的析构函数中自动调用Release。

当产生了异常情况时,相应的接口可以被释放,因为智能指针是一个C++对象。
大多数智能指针实现了Release函数,可以用点记法来调用。
可以用指定一个NULL值来释放智能指针对应的接口。
通过重载=操作符,可以将一个接口指针赋值给智能指针包含的指针。
template <class I,const GUID * pGUID>
I* interface_cast (IUnknown * pIUnknown)
{
    I* pI=NULL;
    HRESULT hr=pIUnknown->QueryInterface(*pGUID,(void**)&pI);
    Assert(SUCCEEDED(hr));
    return pI;
}
///使用
IY *pIY=interface_cast<IY,&IID_IY>(this);
本书作者推荐这样封装QueryInterface,而反对使用重载的赋值操作符,原因是它
违反了C++关于重载的规则:要保证重载后的操作符行为与相应的内置操作符相同

使用智能指针可以获得令人难以想象的灵活性:我们可以编写一个能被用于所有接
口(除IUnknown外)的智能指针。
智能指针封装的不是正在使用的接口而是接口指针的用法。

Question:
    关于包装类?
Answer:
对于某些接口,封装接口本身比使用智能指针更好。
一个包装类是一个或多个COM接口的客户,它所提供的是对这些接口用法的抽象。

应用程序可以调用包装类的成员函数,由这些成员函数调用COM接口中的成员函数

包装类可以充分利用C++的一些特性,如函数名重载、操作符重载、默认参数等。

包装类必须实现它所包装的接口的所有成员。
包装类可以在调用接口成员函数的前后加上新的代码。
包装类可以将几个单独的接口组合成一个逻辑单位。
MFC OLE支持基本上就是一种功能强大的包装类。

Question:
    关于接口基类CUnknown?
Answer:
    实现IUnknown的基类。
    基类Cunknown实现一个非委托unknown接口。
    宏DECLARE_IUNKNOWN实现一个委托unknown接口。
    对于从Cunknown继承的组件,当它没有被聚合时,GetOuterUnknown返回的是
组件的INon -delegationUnknown接口指针;当它被聚合时,返回的则是外部组件
的IUnknown接口指针。
    Cunknown的构造函数接收指向外部unknown接口的指针作为参数,并将其保存
供GetOuter -Unknown函数使用。
    Cunknown::Init虚函数用来创建被包容或聚合的组件。
    Cunknown::FinalRelease虚函数用来给被删除的组件提供一个释放它所保持
的指向内部组件接口指针的机会。

Question:
    关于类厂基类CFactory?
Answer:
    CFactory实现IClassFactory接口。
    CFactory实现DLL的入口点(如DllGetClassObject)的代码。
    CFactory允许同一个DLL包含不同的组件,并且这些组件共享一个
IClassFactory实现。
    CFactory可以满足下述三个要求的任意组件:
    组件必须实现一个具有如下原型的创建函数。
    HRESULT CreateFunction(IUnknown * pUnknownOuter    ///如此参数非空
,则组件是被聚合的。
Cunknown ** ppNewComponent)
    组件必须是从Cunknown继承得到的。
    组件必须添充一个CFactoryData结构并将其加入到全局数组
g_FactoryDataArray中。
    CFactoryData包含5个成员变量:组件的类标识符、指向组件创建函数的指针
、保存在windows注册表中的一个友好名称、ProID以及一个与版本无关的ProID、
一个用于查找CLSID的辅助函数。
    CFactory根据g_FactoryDataArray来决定它能创建哪些组件。

Question:
    如何应用CUnknown和CFactory?
Answer:
1、    编写实现组件的类
可以从CUnknown或其他从CUnknown派生的类派生出待实现的组件。
使用DECLARE_IUNKNOWN宏来实现委托Unknown接口。
在组件的构造函数中初始化CUnknown。
实现NondelegatingQueryInterface,在其中加入此组件支持而基类不支持的接口
。对那些组件不支持的接口,可以调用相应的基类函数。
若需要在构造了组件之后进行其他的清理工作,可以重载FinalRelease函数,比如
释放那些指向被包容或聚合的组件的指针。
为组件实现一个静态的CreateInstance函数。
实现组件支持的那些接口。
2、    对于同一个DLL中的其他组件,重复步骤1。
3、    编写类厂。
建立一个文件,以包含全局CFactoryData数组g_FactoryDataArray。
定义g_FactoryDataArray数组,并用DLL中的所有组件信息填充此数组。
定义变量g_FactoryDataEntries,其中包含有数组g_FactoryDataArray中组件的个
数。
4、    编写一个定义DLL入口点的DEF文件。
5、    将上面所编写的代码同CUNKNOWN.CPP和CFACTORY.CPP一起编译链接。


--


 ※ IP来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM oo.pi.li.x]
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 61.144.235.39]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店