COM编程——精选推荐
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
COM编程
⼀、COM组件基础
1.程序的编写⽅式
1) ⾯向过程的结构化编程
⾃顶向下的编程⽅式(流程图)
2) ⾯向对象的编程
以对象或以类为中⼼,更符合⼈的思维习惯,通过模拟现实情况完成软件的编写。
(类图)
3) ⾯向组件的编程
将⼀些功能直接封装成可以执⾏的⼆进制模块,类似于搭积⽊的⽅式。
更适合⼤型项⽬,功能需求频繁发⽣变更的项⽬的开发,功能的复⽤,复⽤性更⾼的。
2. 组件及组件的特点
组件就是可以执⾏的⼆进制代码,可以为系统,软件或者其他组件提供相应的功能。
特点:
1. ⼆进制代码,可以执⾏
2. 动态加载和卸载
3. 和具体的编程语⾔⽆关
3. 组件的标准
COM提供可组件编写的彼标准,任何开发的语⾔编写组件时。
都要遵循这个标准。
⼆、COM接⼝
1.接⼝Win API –Win32应⽤程序编程接⼝(函数库)
C语⾔接⼝就是函数、
C++语⾔,接⼝就是类的公有函数集合
DLL的接⼝就是它所输出的那些函数
COM接⼝就是⼀组纯虚函数集合,是⼀个包含⼀个函数指针数组的内存结构,每个数组元素包含的是⼀个由组件所实现的函数的地址。
2.C++接⼝的实现
1.定义纯虚函数,不能有任何成员变量和⾮纯虚函数
2.基于纯虚类,派⽣实现类
3.添加创建对象的函数,并使⽤接⼝返回创建的对象
引⼊c++接⼝之后,当功能的提供者发⽣变化时,功能的使⽤者代码不⽤修改,两者之间的耦合性降低了。
Dll接⼝的实现
功能的提供者放到动态库中和功能的使⽤者分开两个不⽤的⼯程
1.创建Win32 dll的⼯程
2.添加头⽂件XXX.h,在⽂件中添加接⼝的定义
3.在⼯程的实现⽂件中添加实现类以及创建对象的函数
1. 导出创建对象的函数,通过添加def⽂件导出该函数
Dll 接⼝的使⽤
调出导出函数的步骤:
1. 加载动态库,LoadLibrary获得句柄。
2. 获取导出函数的函数地址,GetProcAddress
3. 调⽤导出函数,创建对象,返回接⼝。
通过接⼝调⽤函数完成相关的功能
三、COM组件
它是以win32动态链接库(DLLs)或可执⾏⽂件(EXEs)的形式发布的可执⾏代码组成的。
COM组件是动态链接的,使⽤DLL将组件动态链接,其次必须还是封装的。
组件本⾝只是接⼝的实现细节,在COM中接⼝⽐实现接⼝的组件更为重要。
COM组件是完全与编写语⾔⽆关的。
开发组件不⼀定⾮⽤类,只是⽤类来实现组件更容易。
以⼆进制形式发布的
在不妨碍⽼客户的情况下被升级
可以透明地在⽹络上被重新分配,对远程机器上的组件同本地及其上的组件的处理⽅式没有差别。
COM使⽤了DLL来给组件提供动态链接的能⼒。
C++中可以使⽤抽象基类来实现COM接⼝,⼀个COM组件
可以⽀持任意数量的接⼝,可以有通过多重继承来实现⼀个提供多个接⼝的组件。
⼀个接⼝是⼀个函数集合,⼀个组件是⼀个接⼝集,⽽⼀个系统则是⼀系列组件的集合。
COM组件与COM接⼝:
组件实现信息的隐藏,有利于代码的保护。
COM组件的实现:
每个组件ID:每个组件都通过GUID来标识。
在IDL⽂件中定义组件
接⼝类定义:(objbase.h头⽂件中)
#define interface struct
接⼝的性质:接⼝不变性、多态以及接⼝继承
接⼝不变性:当对组件升级时⼀般不会修改已经有的接⼝,⽽是加⼊⼀些新的接⼝。
此时多重继承为组件和客户可以智能地同对⽅的新版本进⾏交互提供可坚实的基础。
多态:以同⼀种⽅式处理不同的对象。
客户可以按照相同的⽅式处理不同的组件,⼀个组件所⽀持的接⼝越多,组件就应该越⼩,较⼩的接⼝表现简单的⾏为,⼤的接⼝表现更多的⾏为。
⼀个接⼝的⾏为越多,则特定性越强,被其他组件复⽤的可能性将越⼩,对于不能复⽤的接⼝,使⽤此接⼝的客户代码也将不能复⽤。
所有的COM接⼝都必须继承⼀个名为IUnknown的接⼝。
COM需要的所有的接⼝都⽀持三个函数,QueryInterface函数、AddRef函数与Release函数。
使得的所有的COM接⼝前三个函数均为它们。
QueryInterface函数:查询组件其他的接⼝
IUnknown接⼝(头⽂件UNKNWN.H):
客户调⽤QueryInterface决定组件是否⽀持某个特定的接⼝。
AddRef与Release函数可以控制接⼝的⽣命期。
获取⼀个指向IUnknown接⼝的指针:通过CreateInstance函数,他可以建⽴⼀个组件并返回⼀个IUnkown指针。
IUnkown *CreateInstance();
idd也标识客户所需的接⼝,是⼀个”接⼝标识符”IDD(GUID)结构。
如:
typedef struct _GUID
{
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;
ppv是QueryInterface存放所请求的指针地址,返回值HRESULT返回为S-OK或E_NOINTERFACE,对于此返回值,需要使⽤SUCCEEDED宏或FAILED宏来⽐较判断返回值,⽽不能直接使⽤。
QueryInstanceface对所有的IUnknown接⼝查询请求都必须返回相同的指针。
QueryInstanceface实现规则:
1.QueryInstanceface返回的总是同⼀IUnknown指针。
2.若客户曾经获取过某个接⼝,那么他将总能获取此接⼝。
3.客户可以再次获取已经拥有的接⼝。
4.客户可以从任何接⼝返回到起始接⼝
5. 若能从某个接⼝获取某特定接⼝,那么可以从任意接⼝都可以获取此接⼝。
组件的实例只有⼀个IUnknown接⼝,当查询组件实例的IUnknown接⼝时,不论哪个接⼝,所得到的均是同⼀指针值。
客户曾经获取过某个接⼝,那么他将总能获取此接⼝,同样若是失败,以后也会失败,除⾮当创建组件的⼀个新实例时,此条规则不⼀定适⽤。
所有的接⼝都继承了IUnknown,许多函数都需要⼀个IUnknown指针作为参数。
他们应该使⽤任何IUnknown指针获取任何接⼝;
《COM技术内幕》P44,即60页。