1、 为什么要用COM
OO vs. COM —— 重用的方法不同
(1)类库 —— 类库的重用基于源码的方式
① 限制了编程语言
② 每次都必须重新编译
(2)DLL ——
① 函数重名问题
② 各编译器对C++函数的名称修饰不兼容问题(也可以用extern "C";来强调使用标准的C函数特性,关闭修饰功能,但这样也丧失了C++的重载多态性功能)
③ 路径问题
④ DLL与EXE的依赖问题
2、 COM组件实际上是一个C++类,而接口都是纯虚类。组件从接口派生而来。COM组件是以 C++为基础的,特别重要的是虚函数和多态性的概念,COM中所有函数都是虚函数,都必须通过虚函数表VTable来调用。
3、 COM组件有三个最基本的接口类,分别是IUnknown、IClassFactory、IDispatch。
COM规范规定任何组件、任何接口都必须从IUnknown继承,IUnknown包含三个函数,分别是 QueryInterface、AddRef、Release。这三个函数是无比重要的,而且它们的排列顺序也是不可改变的。
IClassFactory的作用是创建COM组件。每个组件都必须有一个与之相关的类厂,这个类厂知道怎么样创建组件,当客户请求一个组件对象的实例时,实际上这个请求交给了类厂,由类厂创建组件实例,然后把实例指针交给客户程序。IClassFactory最重要的一个函数就是CreateInstance,顾名思议就是创建组件实例。
IDispatch叫做调度接口。调度接口把每一个函数每一个属性都编上号,客户程序要调用这些函数属性的时侯就把这些编号传给IDispatch接口就行了,IDispatch再根据这些编号调用相应的函数,仅此而已。
4、 COM组件有三种,进程内、本地、远程。对于后两者情况必须调度接口指针及函数参数。
5、 COM组件的核心是IDL。
6、 COM组件的运行机制
IUnknown *pUnk=NULL;
IObject *pObject=NULL;
CoInitialize(NULL); CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (void**)&pUnk); pUnk->QueryInterface(IID_IOjbect, (void**)&pObject); pUnk->Release(); pObject->Func(); pObject->Release(); CoUninitialize(); |
这就是一个典型的创建COM组件的框架,不过我的兴趣在CoCreateInstance身上,让我们来看看它内部做了一些什么事情。以下是它内部实现的一个伪代码:
CoCreateInstance(....)
{ .......
IClassFactory *pClassFactory=NULL; CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&pClassFactory); pClassFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk); pClassFactory->Release(); ........
}
|
这段话的意思就是先得到类厂对象,再通过类厂创建组件从而得到IUnknown指针。继续深入一步,看看CoGetClassObject的内部伪码:
CoGetClassObject(.....)
{ //通过查注册表CLSID_Object,得知组件DLL的位置、文件名
//装入DLL库 //使用函数GetProcAddress(...)得到DLL库中函数DllGetClassObject的函数指针。 //调用DllGetClassObject }
|
DllGetClassObject是干什么的,它是用来获得类厂对象的。只有先得到类厂才能去创建组件.下面是DllGetClassObject的伪码:
DllGetClassObject(...)
{ ......
CFactory* pFactory= new CFactory; //类厂对象 pFactory->QueryInterface(IID_IClassFactory, (void**)&pClassFactory); //查询IClassFactory指针 pFactory->Release(); ......
}
|
CoGetClassObject的流程已经到此为止,现在返回CoCreateInstance,看看CreateInstance的伪码:
CFactory::CreateInstance(.....)
{ ...........
CObject *pObject = new CObject; //组件对象 pObject->QueryInterface(IID_IUnknown, (void**)&pUnk); pObject->Release(); ........... } |
7、 注册表问题