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