ActiveX的前身是MFC OLE,而后发展出来COM组件模型,COM组件模型是一个windows的动态运行组件标准。ActiveX控件是MFC对于COM组件标准的具体实现,以下简要介绍下COM组件模型。
COM组件本质上是一个动态链接库,组件中实现了不同功能的函数,这些函数可以划分为不同的函数集,每个函数集都是对一个纯虚基类的实现,该纯虚基类称为接口,最基本的一个纯虚基类如下所示:
//interface IUnknown
struct IUnknown{
virtual HRESULT QueryInterface(cosnt IID& iid, void ** ppv) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
HRESULT是一个32 bit的整数,每一个位表示相应的状态,IID是统一资源标识符UUID,128 bit的常数,用于在注册表中唯一标识一个资源,如函数、程序、类名等。QueryInterface函数用于查询某个组件是否支持某个iid标识的接口,如果支持该函数集,那么QueryInterface在ppv中返回该接口的指针。AddRef函数用于增加引用计数。Release函数用于减少引用计数,当引用计数为0时,组件进行自我销毁。
所有其他的接口都继承IUnknown,例如:
//interface IX, assume iid is IID_IX
struct IX :public IUnknown{
virtual void Fx()=0;
};
//interface IY, assume iid is IID_IY
struct IY:public IUnknown{
virtual void Fy() = 0;
};
一个具体的组件例子如下:
//componenet CA, assume iid is IID_CA
IUnknown* CreateInstance()
{
IUnknown* p = new CA;
p->AddRef();
return p;
}
class CA:public IX, public IY{
public:
HRESULT QueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown)
*ppv = static_cast<IX*>(this);
else if(iid == IID_IX)
*ppv = static_cast<IX*>(this);
else if(iid == IID_IY)
*ppv = static_cast<IY*>(this);
else if(iid == IID_CA)
*ppv = static_cast<CA*>(this);
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG AddRef()
{
return ++m_refc;
}
ULONG Release()
{
if(0 == --m_refc)
delete this;
return m_refc;
}
void Fx(){::std::cout<< "fx"<<endl;}
void Fy(){::std::cout<< "fy" << endl;}
private:
ULONG m_refc;
public:
CA():m_refc(0){}
~CA(){}
};
所有的组件提供了相同的几个函数:CreateInstance、QueryInterface、AddRef、Release,所有使用COM组件的程序都可以使用这些函数,并且可以通过QueryInterface查询组件支持的接口,从而使用对应接口中的函数功能。
接口的声明文件interface.h(用于在客户程序和组件之间共享接口信息)
IUnknown* CreateInstance();
struct IUnknown{
virtual HRESULT QueryInterface(cosnt IID& iid, void ** ppv) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
//interface IX, assume iid is IID_IX
struct IX :public IUnknown{
virtual void Fx()=0;
};
//interface IY, assume iid is IID_IY
struct IY:public IUnknown{
virtual void Fy() = 0;
};
extern const IID IID_IUnknown;
extern const IID IID_X;
extern const IID IID_Y;//(IID是一个128bit的数据结构,定义独一无二的接口ID)
一个使用组件的程序如下:
int main()
{
::std::cout << "main" << endl;
IUnknown* pKnown = CreateInstance();
IX* pIx = NULL;
IY* pIy = NULL;
pKnown->QueryInterface(IID_IX,pIx);
pIx->Fx();
pIx->Release();
pKnown->QueryInterface(IID_IY,pIy);
pIy->Fy();
pIy->Release();
pKnown->Release();
}
在实际运行中,com组件被编译成动态链接库,客户程序在使用com组件时加载该动态链接库,调用QueryInterface函数确定com组件支持的接口,继而调用对应接口的函数。