IUnknown接口是COM的核心,所有其他的COM接口都必须从IUnknown继承。
IUnknown实质上就是一个含有纯虚函数的抽象类。

class IUnknown{  
public:  
     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) = 0;  
     virtual ULONG __stdcall AddRef() = 0;  
     virtual ULONG __stdcall Release() = 0;  
}; 

COM客户程序要使用COM对象是通过COM库创建而来的,而实际上COM库是调用COM对象的类厂来创建的。COM类厂对象也是一个COM对象,所以它也从IUnknow继承而来,而它又支持IClassFactory接口:

class IClassFactory:public IUnknow  
{  
    public:  
        virtual HRESULT CreateInstance(IUnkonwn* pUnkOuter, REFIID iid, void** ppObject)=0;  
        virtual HRESULT LockServer(BOOL fLock)=0;  
}; 

CreateInstance是构造COM对象的函数,通过传入接口的IID,从ppObject输出COM接口指针,而pUnkOuter一般设为NULL,该参数在聚合时起作用。
LockServer是用来控制COM类厂的生命周期的函数,将fLock设为TRUE后,即使组件程序中所有COM对象已释放了,该类厂指针也会一直保存并且有效,当不再需要的时候设为FALSE即可。

若要使用类厂对象去创建COM对象,首先得创建类厂对象,可以使用库函数CoGetClassObject来创建COM类的类厂,若找到的COM对象是进程内组件,则使用DLL导出函数DllGetClassObject函数创建类厂,然后将对象指针传出。

STDAPI DLLGetClassObject(REFCLSID rclsid, REFIID riid, void** ppObject)  
{  
  if(rclsid == CLSID_SAMPLE)  
  {  
    CSampleFactory* csf = new CSampleFactory();  
    if(FAILED(csf->QueryInterface(riid, ppObject)))  
    {  
       delete pFactory;  
       *ppObject = NULL;  
       return E_INVALIDARG;  
    }  
   }  
   return NO_ERROR;  
}  

COM自动卸载
客户端程序调用CoFreeUnusedLibraries来释放组件,但是释放组件需要满足:组件中的对象数目为0和类厂的锁计数为0,要知道是否满足以上条件,需要导出函数DllCanUnloadNow,该函数通过判断组件对象的引用计数来判断是否可以释放组件。

COM 进程模型
进程内组件:组件直接加载到客户的进程地址中,通常是DLL的形式存在。
本地组件:组件程序与客户程序在同一台机器上,但是组件程序是以独立的形势存在,通常是EXE。
远程组件:组件程序与客户在不同机器上,可以使DLL也可以使EXE。

包容与聚合
COM不是简单的C/S模型,有时客户可以反过来提供服务,COM对象提供服务的同时也可以向其他组件寻求服务,所以COM对象可能是一个服务方的同时也是客户,而C/S在这里只是相对的。
COM提供了两种对象的重用机制,分别是包容和聚合,对于客户而言,他只知道对象B的存在而不知道对象A,而对象B可能在实现一些服务时调用了对象A的服务。两者的区别在于
包容是指客户调用B的服务时,由B直接调用A的服务,并把结果返回给客户,而聚合是指客户调用某个服务的时候,B直接把A的指针返回给客户去操作,但客户不知道A的存在,但他是直接调用A的

COM线程模型
COM提供的套间线程模型共有三种:
Single-Threaded Apartment(STA 单线程套间)位于STA的线程必须实现消息循环
Multithreaded Apartment(MTA 多线程套间
Neutral Apartment/Thread Neutral Apartment/Neutral Threaded Apartment(NA/TNA/NTA 中立线程套间,由COM+提供)
COM组件可以配置使用五组线程模型(对应注册表中的ThreadingModel)
单线程模型(Single) 组件存在于STA中
套间线程模型(Apartment) 套间线程模型的组件只能存在于STA中
自由线程模型(Free) 组件存在于MTA中
双线程模型(Both) 组件既可能存在于STA,也可能是MTA
线程中立模型(Neutral) 组件被配置为使用线程中立模型。使用线程中立模型的组件位于TNA中,可以被任何线程自由地、直接地访问
COM组件建立过程
CoCreateInstance->CoGetClassObject->DllGetClassObject->IClassFactory->CreateInstance
我们在用 CoCreateInstance 建立COM对象时, 调用 CoGetClassObject, 系统根据传入的GUID从注册表中找到DLL的路径, 加载DLL, 调用DLL导出函数 DllGetClassObject, 而 DllGetClassObject 函数则建立类厂对象, 返回类厂对象的指针
         CoCreateInstance 相当于做了以下工作

CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, &pCF);
hresult = pCF->CreateInstance(pUnkOuter, riid, ppvObj)
pCF->Release();

转载请注明转自: 听风 , 本文固定链接: COM 知识点摘要