COM客户程序是如何调用进程内组件的
我们用DLL组件代替EXE组件来开始这一节,因为这样程序的交互要简单点儿。我们将在这使用伪代码而非隐藏了太多细节的,将来会使用到的MFC类库。
Client
CLSID clsid;
IClassFactory* pClf;
IUnknown* pUnk;
CoInitialise(NULL);//Initialise COM
CLSIDFromProgID("componentname", &clsid);
COM
COM通过程序易读的"componentname"在注册表中寻找CLSID
Client
CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void**)&pclf);
COM
COM用CLSID在内存中寻找组件
if(组件还没有载入到内存){
COM从注册表中获得DLL的文件名
COM把DLL组件载入到内存进程中
}
DLL Component
if(如果组件被加载){
全局factory对象被构建
DLL的初始实例化被执行(仅仅对于MFC)
}
COM
COM调用DLL导出的全局方法DllGetClassObject,并把传递给CoGetClassObject的参数CLSID作为参数再传递给它
DLL Component
DllGetClassObject返回接口IClassFactory*
COM
COM把IClassFactory*返回给客户程序
Client
pClf->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk);
DLL Component
class factory 的CreateInstance方法被调用(该操作直接通过组件的虚函数表调用)
开始构建"componentname"类对象
返回请求的接口指针
Client
pClf->Release();
pUnk->Release();
Dll Component
释放"componentname"是通过调用虚函数表进行的
if(引用计数 == 0){
对象自己将作销毁操作
}
Client
CoFreeUnusedLibraries();
COM
COM调用DLL导出的全局方法DllCanUnloadNow
DLL Component
DllCanUnloadNow被调用
if(所有的DLL对象已经被释放){
return TRUE
}
Client
CoUninitialize();//如果上面DllCanUnloadNow推出时返回TRUE,那么COM将释放DLL
COM
COM releases resources
Client
客户程序退出
DLL Component
如果DLL还在内存中并且没有其它程序在使用它,windows将卸载DLL
有几个重要的问题需要注意:第一,DllGetClassObject是为了响应客户程序调用CoGetClassObject才被执行的;第二,返回的class factory接口地址是DLL中的虚函数表内class factory的实际物理地址,第三,客户程序调用CreateInstance或其它所有接口方法都是直接调用的(通过组件的vtable)。
下一节:How a COM Client Calls an Out-of-Process Component