1. COM编程基础
COM是一种规范,而不是实现。
当使用C++来实现时,COM组件就是一个C++类,而COM接口就是继承至IUnknown的纯虚类,COM组件就是实现相应COM接口的C++类。
COM规范规定,任何组件或接口都必须从IUnknown接口中继承而来。IUnknown定义了3个重要函数,分别是QueryInterface、AddRef和Release。其中,QueryInterface负责组件对象上的接口查询,AddRef用于增加引用计数,Release用于减少引用计数。引用计数是COM中的一个非常重要的概念,它很好地解决了组件对象地生命周期问题,即COM组件何时被销毁,以及谁来销毁地问题。
除了IUnknown接口外,还有另外一个重要地接口,即IClassFactory。COM组件实际上是一个C++类,对于组件地外部使用者来说,这个类名一般不可知,那么如何创建这个类地的例?由谁来创建?COM规范规定,每个组件都必须实现一个与之对应的类工厂(Class Factory)。类工厂也是一个COM组件,它实现了IClassFactory接口。在IClassFactory的接口函数CreateInstance中,才能使用new操作生成一个COM组件类对象实例。
COM组件有3种类型:
① 进程内组件(CLSCTX_INPROC_SERVER)
② 本地进程组件(CLSCTX_LOCAL_SERVER)
③ 远程组件(CLSCTX_REMOTE_SERVER)
在接口成员函数中,字符串变量必须用Unicode字符指针,这是COM规范的要求。
2. COM组件开发
实现一个COM组件,需要完成以下工作:
COM组件接口
COM组件实现类
COM组件创建工厂
COM组件注册与取消注册
本文以一个例子作为说明,COM组件提供了一个SayHello的接口函数,将“Hello COM”打印输出。
2.1 创建COM组件接口
COM组件接口是一个继承IUnknown的抽象类:
COM组件类是一个实现了相应COM组件接口的C++类,注意:一个COM组件可以同时实现多个COM接口。
2.3 COM组件创建工厂
对于组件地外部使用者来说,这个COM组件的类名一般不可知,那么如何创建这个类地实例?由谁来创建?COM规范规定,每个组件都必须实现一个与之对应的类工厂(Class Factory)。类工厂也是一个COM组件,它实现了IClassFactory接口。在IClassFactory的接口函数CreateInstance中,才能使用new操作生成一个COM组件类对象实例。
2.4 COM组件的注册
COM组件需要使用regsvr32工具注册到系统才能被调用,然而COM组件是如何被regsvr32注册的?一个典型的自注册COM组件需要提供4个必需的导出函数:
DllGetClassObject:用于获得类工厂指针
DllCanUnloadNow:系统空闲时会调用这个函数,以确定是否可以卸载COM组件
DllRegisterServer:将COM组件注册到注册表中
DllUnregisterServer:删除注册表中的COM组件的注册信息
DLL还有一个可选的入口函数DllMain,可用于初始化和释放全局变量
DllMain:DLL的入口函数,在LoadLibrary和FreeLibrary时都会调用
导出文件(Source.def):
生成完后,使用regsvr32注册到系统中:
3. COM组件使用
COM组件的使用包括:
如何创建COM组件
如何得到组件对象上的接口以及如何调用接口方法
如何管理组件对象(需熟悉COM的引用计数机制)
下面的代码是最一般的步骤:
下面我们编写一个客户端,调用之前写的COM组件服务:
上面的例子和一般步骤不一致,少了QueryInterface,是因为默认返回的就是指定的接口,下面按一般步骤再实现一次:
是直接创建COM组件并获取接口,还是先创建COM组件得到默认接口再查询其他的接口,需要具体问题具体分析。
4.COM组件运行机制
一个COM组件从编写到最终可以被调用,整个运行流程是怎样的?或者我们再考虑简单一点,COM组件是如何被调用的?