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

2014-11-24 09:46:32 · 作者: · 浏览: 5
ory的虚表有五个特殊函数,它们是QueryInterface、AddRef、Release、CreateInstance和LockServer。注意IClassFactory有自己的QueryInterface、AddRef和Release函数,就像我们的IExample对象那样。当然,我们的IClassFactory也是一个COM对象,所有的COM对象的虚表都必须以这三个函数开始。(但是为了避免与IExmaple的函数名字冲突,我们在我们IClassFactory函数名前加上“class”前缀,例如classQueryInterface、classAddRef和classRelease。在IClassFactory虚表定义时,它的前三个成员为QueryInterface、AddRef和Release,)
真正重要的函数是CreateInstance。只要程序要我们创建一个IExample对象、初始化对象和返回对象时,它就会调用我们IClassFactory的CreateInstance。事实上,如果程序需要几个IExample对象,它可以调用CreateInstance几次。好,一个程序就可以这样获得我们的IExample对象。你可以要问“但是其它程序怎样获得我们的IClassFactory对象呢?”我们一会再开始。现在,让我们简单写一下我们的IClassFactroy的五个函数,构造它的虚表。构造虚表比较简单。不像我们的IExample对象的IExampleVtbl,我们不必定义我们的IClassFactory的虚表结构。微软已经在包含文件中为我们定义了一个IClassFactoryVtbl结构。我们需要做的是声明我们的虚表和用我们的五个IClassFactory的函数指针来填充它。让我们用IClassFactory_Vtbl变量名来创建一个静态的虚表并填充它:
[cpp
static constIClassFactoryVtbl IClassFactory_Vtbl = {classQueryInterface,
classAddRef,
classRelease,
classCreateInstance,
classLockServer};
同样的,创建一个实际的IClassFcactory对象是容易的,因为微软也已经定义了这个结构。我们仅仅需要他们中的一个,所以让我们用一个MyIClassFactoryObj变量名声明一个静态的IClassFactory,初始化它的lpVtble成员指向我们上面的虚表:
[cpp]
static IClassFactoryMyIClassFactoryObj = {&IClassFactory_Vtbl};
现在,我们只需要写上面的五个函数。我们的classAddRef和classRelease函数没什么用。因为实际上我们从不要分配我们的IClassFactory(也就是说,我们简单的把它声明为静态的),我们不需要释放任何东西。所以,classAddRef只是简单的返回一个1(指出总有一个IClassFactory存在)。ClassRelease也同样这么做,因为不需要释放它,对于我们的IclassFactroy也就不需要做引用计数。
[cpp]
ULONGSTDMETHODCALLTYPE classAddRef(IClassFactory *this)
{
return(1);
}
ULONGSTDMETHODCALLTYPE classRelease(IClassFactory *this)
{
return(1);
}
现在,让我们看看我们的QueryInterface。它要检查是否传给它的GUID是IUnkown的GUID(由于我们的IClassFactory有QueryInterface、AddRef和Release函数,它也可以装扮成一个IUknown对象)还是IClassFactory的GUID。另外,我们要做像我们在IExample的QueryInterface中做的同样的事情。
[cpp]
HRESULTSTDMETHODCALLTYPE classQueryInterface(IClassFactory *this,
REFIID factoryGuid,void **ppv)
{
// 检查GUID是否与IClassFactory或Iuknown的GUID匹配。
if(!IsEqualIID(factoryGuid, &IID_IUnknown) &&
!IsEqualIID(factoryGuid,&IID_IClassFactory))
{
// 不匹配,清除句柄,返回E_NOINTERFACE。
*ppv = 0;
return(E_NOINTERFACE);
}
// 匹配
// 首先,我们用它传给我们的同一个对象指针填充它的句柄。
// 这是它从我们这里获得的我们的IClassFactory(MyClassFactoryObj)
*ppv = this;
// 传递IClassFacory,调用我们的IClassFactory的AddRef。
this->lpVtbl->AddRef(this);
// 让他知道它确实拥有了一个IClassFactroy
return(NOERROR);
}
我们的IClassFactory的LockServer现在就是一个摆设:
[cpp]
HRESULT STDMETHODCALLTYPEclassLockServer(IClassFactory *this, BOOL flock)
{
return(NOERROR);
}
还有一个函数要写-CreateInstance。下面是它的定义:
[cpp]
HRESULT STDMETHODCALLTYPEclassCreateInstance(IClassFactory *,
IUnknown *, REFIID,void **);
通常,第一个参数会是一个指向我们的被用来调用CreateInstance的IClassFactory对象(MyIClassFactoryObj)指针。仅当我们实现了聚合,我们才使用第二个参数。我们现在先不理这个。如果它非零,就是有人要我们支持聚合,在这我们不支持,我们会通过返回一个错误来提示。第三个参数是这个IExample虚表的GUID(如果有人确实要我们来分配、初始化和返回一个IExample对象)。第四个参数是一个用于存放我们返回的我们创建的IExample对象的句柄。
现在让我们开始写我们的CreateInstance函数(被名字为classCreateInstance):
[cpp]
HRESULTSTDMETHODCALLTYPE classCreateInstance(IClassFac