作為程序内元件程式, 必須引出COM 所要求的四個基本函數:
1. 引出DllGetClassObject
STDAPI DllGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID * ppv
);
extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if (clsid == CLSID_Dictionary ) {
CDictionaryFactory *pFactory = new CDictionaryFactory; //建立元件類廠
if (pFactory == NULL) {
return E_OUTOFMEMORY ;
}
HRESULT result = pFactory->QueryInterface(iid, ppv);
return result;
} else {
return CLASS_E_CLASSNOTAVAILABLE;
}
}
2. STDAPI DllCanUnloadNow(void);
extern "C" HRESULT __stdcall DllCanUnloadNow(void)
{
if ((g_DictionaryNumber == 0) && (g_LockNumber == 0))
return S_OK;
else
return S_FALSE;
}
3.STDAPI DllRegisterServer(void);和STDAPI DllUnregisterServer(void);
// 這兩個函數在用regsvr32.exe 進行元件的注冊和反注冊很有用,在元件程式裡面必須自己實作
自注冊程序内元件程式必須引出的兩個函數還系統資料庫的建立操作
實作代碼如下:
extern "C" HRESULT __stdcall DllRegisterServer()
{
char szModule[1024];
DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, szModule, 1024);
if (dwResult == 0)
return SELFREG_E_CLASS;
return RegisterServer(CLSID_Dictionary,
szModule,
"Dictionary.Object",
"Dictionary Component",
NULL);
}
RegisterServer()函數包含系統資料庫的建立操作
extern "C" HRESULT __stdcall DllUnregisterServer()
{
return UnregisterServer(CLSID_Dictionary,
"Dictionary.Object",NULL);
}
下面我來解釋一下為什麼必須引出這四個函數
在客戶程式能用這個元件之前,我們必須對元件進行系統組成:
利用windows 系統給我們提供的regsvr32.exe , 這個可以再系統的systerm32目錄下找到
方法一:在 開始—>運作直接輸入 regsvr32 My.dll 注意這種方式需要my.dll放在windows下的Syetem32目錄下
方法二:在 開始—>運作直接輸入 regsvr32.exe D:/My.dll 注意當這種絕對路徑方法中含有空格的時候需要regsvr32 "D:/ My.dll"就行了。
在對元件進行注冊時候,系統會根據元件引出函數DllRegisterServer,把元件資訊寫入到系統資料庫相應的地方。
同理,反注冊時調用DllUnregisterServer,這也是為什麼這兩個函數必須要引出的原因。
下面來講一下客戶的調用方式:
當客戶調用COM庫函數裡面的CoCreateInstance時候内部會首先調用COM庫函數CoGetClassObject, CoGetClassObject函數内部在調用元件内引出函數DllGetClassObject來建立類廠對象,然後系統自動調用類廠對象的CreateInstance來建立元件對象。
注意:類廠的 CreateInstance必須由我們程式員來使用,見如下代碼
HRESULT CDictionaryFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
CDictionary * pObj;
HRESULT hr;
*ppv=NULL;
hr=E_OUTOFMEMORY;
if (NULL != pUnknownOuter)
return CLASS_E_NOAGGREGATION;
//Create the object passing function to notify on destruction.
pObj=new CDictionary();
if (NULL==pObj)
return hr;
//Obtain the first interface pointer (which does an AddRef)
hr=pObj->QueryInterface(iid, ppv);
if (hr != S_OK) {
//Kill the object if initial creation or FInit failed.
g_DictionaryNumber --; // Reference count g_cDictionary be added in constructor
delete pObj;
}
return hr;
參考書:<<COM技術内幕>>
<<COM原理與應用>>