用标准C编写COM(一)(九)

2014-11-24 09:46:32 · 作者: · 浏览: 6
化COM。它只需要初始化一次,所以在程序一开始的地方做比较好。
接下来,程序通过调用CoGetClassObject来获得IExample.dll的IClassFactory对象指针。注意我们传递IExample对象的GUID作为第一个参数。我们也传递一个我们的classFactory变量指针,如果一切正确,IClassFactory指针会通过classFactroy返回给我们。
一旦我们拥有了一个IClassFactory对象,我们可以调用它的CreateInstance函数来获得一个IExample对象。注意我们用IClassFactory调用它的CreateInstance函数的方法。我们通过IClassFactory的虚表(也就是它的lpVtbl成员)来得到这个函数。同时注意我们传IClassFactory指针作为第一个参数。记住这是一个标准的COM。
注意我们传递IExample的虚表的GUID作为第三个参数。对于第四个参数,我们传入一个我们的exampleObj的变量指针,如果一切正确,IExample对象指针会通过exampleObj返回给我们。
一旦我们拥有了一个IExample对象,我们可以释放IClassFactory对象。记住当程序使用完对象时必须调用对象的Release函数。IClassFactory是一个对象,就像IExample是一个对象一样。每个对象有自己的Release函数,当我们使用完对象时必须调用它。我们不再需要IClassFactory了。我们不再需要获得IExample对象了,也不需要调用IClassFactory的其它函数了,所以现在我们可以释放它了。注意它根本不影响我们的IExample对象。
所以接下来我们调用IClassFactory的Release函数。一旦我们这样做了,我们的classFactory变量不再包含一个有效的指针。它现在是一个垃圾了。
但我们还拥有IExmaple指针。我们还没有释放它。所以接下来我们决定调用IExample的函数。我们调用SetString。然后我们接着调用GetString。注意我们使用IExmaple指针调用它的SetString函数的方法。我们通过IExmaple的虚表获得这个函数。也要注意我们传递IExample指针作为第一个参数。因为它是一个标准的COM。
当我们最后使用完IExample后,我们要释放它。一旦我们这样做了,我们的exampleObj变量不再包含一个有效的指针。
最后,我们必须调用CoUninitialize让COM来清除内部的垃圾。它只需要做一次,所以它最好放在我们程序的结尾(但只有CoInitialize调用成功才需要这么做)。
也可以用CoCreateInstance函数替换CoGetClassObject(来获得DLL的IClassFactory),然后调用IClassFactory的CreateInstance。CoCreateInstance本身会调用CoGetClassObject,然后调用IClassFactory的CrateInstance。CoCreateInstance直接返回IExample,绕过获得 IClassFactory。这是使用的一个例子。
[cpp]
if((hr = CoCreateInstance(&CLSID_IExample, 0,
CLSCTX_INPROC_SERVER,&IID_IExample, &exampleObj)))
MessageBox(0, "Can't create IExampleobject",
"CoCreateInstanceerror",
MB_OK|MB_ICONEXCLAMATION);
C++实例程序
IExampleCplusApp 目录下包含一个C++例程。它是像C例子一样正确。但你要注意有些重要的不同之处。首先,因为在IExample.h中宏把IExmaple定义为一个C ++类(而不是一个结构),并且因为C++用特殊的方式处理类,C++程序以不同的格式调用我们的IExample函数。
在C中我们直接通过访问虚表(通过lpVtble成员)来获得IExample函数,我们总是传入IExample作为第一个参数。
C++编译器知道把一个类的虚表作为它的第一个成员,自动访问它的lpVtbl成员来获得它里面的函数。所以我们不必指定lpVtbl部分。C++编译器也会自动传递这个对象作为第一个参数。
那么尽管在C中,我们的代码:
[cpp]
classFactory->lpVtbl->CreateInstance(classFactory,0,
&IID_IExample,&exampleObj);
而在C++中,我们代码改为:
[cpp]
classFactory->CreateInstance(0,IID_IExample, &exampleObj);
注意:我们也省略IID_IExample的GUID的&。C++的GUID宏不需要指定它。
修改代码
创建你自己的对象,给IExample目录作个拷贝。删除Debug和Release子目录,还有下面的文件也得删除:
[cpp]
IExample.dsp
IExample.dsw
IExample.ncb
IExample.opt
IExample.plg
在剩下的文件(IExample.c、IExample.h、IExample.def)中搜索IExample字符串并用你自己的对象名替换它(例如,IMyObject.c等)。在这个目录下以你的新对象名创建一个新的VisulaC++工程,工程的类型要选“Win32 Dynamic-Link Library”。创建一个空的工程,然后把上面的三个文件加到工程中。你一定要用GUIDGEN.EXE给你的对象和它的虚表生成你自己的GUID。不要用我生成的GUID。替换.H文件中的GUID宏(同时记住也要替换GUID宏的<>部分)。删除.C和.H文件中的SetString和GetString函数,添加你自己的函数。修改.H文件你添加的函数定义的INTERFACE宏。修改MyRealIExample的数据成员为你需要的。修改安装程序源文件中的前三个字符串。在这个例子程序中,搜索并替换IExample为你的对象名。
接下来是什么?
虽然一个C或者C++程序,或者一个用大部分编译语言编写的程序,可以使用我们的COM对象,我们必须添加一些东东来支持大多数解释性语言来使用我们的对象,例如VisualBasic、VBScript、Jscript、 Python等。这会是这个系列第二部分的主题。