无论编写哪种类型的组件程序,最终目的都是为了服务于客户程序。客户程序对COM对象的调用通常是通过调用COM API函数来进行,最为核心的COM API函数是CoGetClassObject,下面是这个函数的原型。
HRESULT CoGetClassObject(REFCLSID rclsid, DWORD dwClsCtx,
COSERVERINFO *pcsi,
REFIID riid, void **ppvClsObj);
通过调用这个COM API函数,可以得到COM组件的类工厂指针。只要得到了类工厂指针,就可以按照前面所讲过的实例化对象的过程(如图5-3所示)来访问所感兴趣的组件方法了。下面是范例代码:
int main( int argc, char *argv[] )
{
// 初始化COM库(必须步骤,不可或缺)
CoInitialize(0);
// 从ProgID得到CLSID,以便COM API调用
CLSID clsid;
// CLSIDFromProgID函数可以从给定的ProgID中得到CLSID
//CLSD::CLSIDFromProgID( L"MyCOM.SimpleMath.1", &clsid );
// 得到与我们感兴趣的COM 类配对的类工厂
IClassFactory* pCF;
//****************************************//
// 注意CoGetClassObject函数的使用方法,
// CoGetClassObject的调用触发组件DLL的
// DllGetObject输出函数
//****************************************//
HRESULT hr;
hr = CoGetClassObject( clsid,
CLSCTX_INPROC,
NULL,
IID_IClassFactory,
(void**) &pCF );
if ( FAILED( hr ))
{
cout << "函数调用失败!" << endl;
return –1;
}
// 使用成功返回的类工厂指针,访问核心CreateInstance方法
// 创建COM对象实例
IUnknown* pUnk;
hr = pCF->CreateInstance( NULL, IID_IUnknown, (void**) &pUnk );
pCF->Release();
if ( FAILED( hr ))
{
cout << "不能成功的创建COM对象实例!" << endl;
return –1;
}
ISimpleMath* pISM = 0;
pUnk->QueryInterface( IID_ISimpleMath, (LPVOID*)&pISM );
pUnk->Release();
long lRet;
// 调用真正感兴趣的COM服务
pISM->Add( 100, 200, &lRet );
cout << lRet << endl;
…
// 对其他函数的调用略
CoUninitialize();
return 0;
}
从上面的代码中,不难看出有关COM对象调用所需的必要步骤。当然,使用其他COM API也可以创建COM对象实例,如CoCreateInstance和CoCreateInstanceEx。但事实上,上述两个COM API函数都在内部调用了CoGetClassObject,同样要经历前面讲述的每一个步骤,所以从调用机制上来讲并没有本质的不同。
得到 类工厂-〉创建实例(得到IUnknow接口)->通过iunknow接口查找相关的接口-〉调用接口方法