用C++类来编写COM对象有两种技术:“多重继承”和”嵌套类“。MFC使用“嵌套类”技术来实现COM接口。
1、嵌套类
以下为嵌套类技术实例,CComClass类为实现了IMath和ISpelling接口的MFC类,并且每个接口都有方法InIt,需要定义两个子类,每个子类实现一个接口:
class CComClass:public IUnknown
{
protected:
long m_lRef;
class CMath:public IMath
{
[...]
};
CMath m_objMath;
class CSpelling:public ISpelling
{
[...]
};
CSpelling m_obgSpell;
public:
CComClass();
virtual ~CComClass()
//IUnknown methods
virtual HRESULT__stdcall QueryInterface(REFIID riid, void**ppv);
virtual ULONG__stdcall AddRef();
virtual ULONG__stdcall Release();
};
class CMath:public IMath
{
protected:
CComClass* m_pParent;
public:
CMath();
virtual ~CMath();
//IUnknown methods
virtual HRESULT__stdcall QueryInterface(REFIID riid, void**ppv);
virtual ULONG__stdcall AddRef();
virtual ULONG__stdcall Release();
//IMath methods
virtual HRESULT__stdcall Add(int a, int b, int *pResult);
virtual HRESULT__stdcall Subtract(int a, int b, int *pResult);
virtual HRESULT__stdcall Init() = 0;
};
class CSpelling:public ISpelling
{
protected:
CComClass* m_pParent;
public:
CSpelling();
virtual ~CSpelling();
//IUnknown methods
virtual HRESULT__stdcall QueryInterface(REFIID riid, void**ppv);
virtual ULONG__stdcall AddRef();
virtual ULONG__stdcall Release();
//ISpelling methods
virtual HRESULT__stdcall CheckSpelling(wchar_t pString);
virtual HRESULT__stdcall Init() = 0;
};
如果调用CComClall的QueryInterface来请求IMath指针,则会获得指向CMath对象的指针:
*ppv = (IMath*)&m_objMath;
同样,
如果调用CComClall的QueryInterface来请求ISpelling指针,则会获得指向CSpelling对象的指针:
*ppv = (ISpelling*)&m_objSpell;
子对象会将对它的IUnknown方法的调用委派给父类中同样的方法,因为每个嵌套类都保存了一个CComClass指针,该指针是一个回溯指针,指向子对象的父亲,通过回溯指针调用CComClass的IUnknown方法,从而实现了委派。
通常在父亲的构造函数中初始化回溯指针:
CComClass::CComClass()
{
[...]
m_objMath.m_pParent = this;
m_obgSpell.m_pParent = this;
}
嵌套类的IUnknown代码:
HRESULT__stdcall CComClass::CMath::QueryInterface(REFIID riid, void**ppv)
{
return m_pParent->QueryInterface(riid, ppv);
}
ULONG__stdcall CComClass::CMath::AddRef()
{
return m_pParent->AddRef();
}
ULONG__stdcall CComClass::CMath::Release()
{
return m_pParent->release();
}
2、MFC中的嵌套类
MFC类中利用宏隐藏了嵌套类。如MFC COM类COleDropTarget,它只实现了一个标准接口IDropTarget。在COleDropTarget类声明的结尾处有以下代码:
BEGIN_INTERFACE_PART(DropTarget, IDropTarget)
INIT_INTERFACE_PART(COleDropTarget, DropTarget)
STDMETHOD(DragEnter)(LPDATAOBJECT, DWORD, POINTL, LPDWORD);
STDMETHOD(DragOver)(DWORD, POINTL, LPDWORD);
STDMETHOD(DragLeave)();
STDMETHOD(Drop)(LPDATAOBJECT, DWORD, POINTL pt, LPDWORD);
END_INTERFACE_PART(DropTarget)
其中,BEGIN_INTERFACE_PART宏定义实现了一个COM接口的嵌套类,类名称是参数列表中第一个参数加上X,即XDropTarget,END_INTERFACE_PART宏声明了一个成员变量,它是这个嵌套类的实例。
BEGIN_INTERFACE_PART和
END_INTERFACE_PART之间为嵌套类的方法:包含三个IUnknown方法以及DragEnter、DragOver、DragLeave、Drop。
3、MFC和类厂