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,該函式通過判斷元件物件的引用計數來判斷是否可以釋放元件。