加载COM的方式
通常我们都是使用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
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
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++都可以很好的工作。
15:06 2008-11-19 liz