通常我們都是使用CoCreateInstance或CoGetClassObject獲得接口,再通過接口訪問他的成員方法。在C++支持下,從來不會有任何問題。但是如果使用Win32模式,純粹C風格編程,就會出現問題了。
通過研究我發現其實上述訪問方式本身就存在問題。標准的訪問方式,如D3D一樣,接口的初始化必須在Com提供的API基礎上完成。COM設計者需要提供一個API,像DLL的導出函數一樣,供給外部程序調用。
具體設計:
下面是一個gdi擴展函數庫gdiex,GdIExCreate就是創建接口的一個函數,如同Direct3DCreate9一樣,調用這個函數可以立刻創建一個接口指針。
在COM內部設計導出函數,如:
HRESULT WINAPI GdiexCreate(LPVOID *lplpGdIEx)
{
HRESULT hr;
ISaveDDCtl * pCtrl = NULL;
hr = CoCreateInstance( CLSID_SaveDDCtl, NULL, CLSCTX_SERVER, IID_ISaveDDCtl, (void**) &pCtrl);
if(FAILED(hr))
{
MessageBox(NULL, "GdiexCreate Failed!", "gdIExPS", MB_OK|MB_ICONSTOP);
return hr;
}
*lplpGdIEx = (LPVOID) pCtrl;
return S_OK;
}
該函數可以放在主要cpp文件中。
在導出的頭文件(gdIEx.h)中作出聲明:
HRESULT WINAPI GdiexCreate(LPVOID *lplpGdIEx);
只要不重新生成COM,這個頭文件中都會包含該API。
下來在gdIEx.def增加這個API名字,以便外部訪問。
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObjectPRIVATE
DllRegisterServerPRIVATE
DllUnregisterServerPRIVATE
GdIExCreate
調用的時候,只需要在工程中包含gdiex.h, 輸入gdIEx.lib,就可以調用到這個API
ISaveDDCtl * pCtl = NULL;
CoInitialize( NULL );
hr = GdIExCreate( (LPVOID*) &pCtl );
if(FAILED( hr )) {
return hr;
}
... ...
GdiexFree( (LPVOID) &pCtl ); //gdiex釋放API,在gdIEx模塊中定義。
CoUninitialize();
就是這樣,調用者沒有出現多余的訪問,就可以獲得接口。而且C/C++都可以很好的工作。