1. 程式人生 > >COM元件開發(三)——類廠物件

COM元件開發(三)——類廠物件

COM類廠物件的實現

        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;
};
        所以,一個普通的類廠應該是這樣的:
class CSampleFactory: public IClassFactory
{
    public:       
       CSampleFactory();
       HRESULT __stdcall QueryInterface(REFIID riid, void** ppObject);
       ULONG __stdcall AddRef();
       ULONG __stdcall Release();
       HRESULT __stdcall CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppObject);
       HRESULT __stdcall LockServer(BOOL fLock);
    private:
       ULONG m_dwRefCount;
}; 

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;
}
        若建立的是程序外元件,則要分別呼叫CoRegisterClassObject和CoRevokeClassObject去註冊和反註冊類廠物件才能正常地建立、銷燬COM物件。

COM自動註冊

        在cmd窗體下,使用命令

                regsvr32 d:\sample.dll

        對sample.dll進行註冊,這時會呼叫該dll匯出的DllRegisterServer。

        另外,使用

                regsvr32 /u d:\sample.dll

        對其進行反註冊,同樣會呼叫匯出函式DllUnregisterServer。

        以上的命令是對程序內元件有效,而對程序外元件不必使用以上命令,由於自身是可執行程式,所以在執行時一般會自動呼叫DllRegisterServer和DllUnregisterServer。

COM自動解除安裝

         客戶端程式呼叫CoFreeUnusedLibraries來釋放元件,但是釋放元件需要滿足:元件中的物件數目為0和類廠的鎖計數為0,要知道是否滿足以上條件,需要匯出函式DllCanUnloadNow,該函式通過判斷元件物件的引用計數來判斷是否可以釋放元件。