一、COM原理与实现
多重继承方式
class CDictionary : public IDictionary , public ISpellCheck
{
public :
CDictionary();
~CDictionary();
public :
// IUnknown member function
virtual HRESULT QueryInterface(const IID& iid, void **ppv) ;
virtual ULONG AddRef() ;
virtual ULONG Release() ;
......
private :
int m_Ref ;
......
};
依次查询iid是否对应(如果接口较多?)
HRESULT CDictionary::QueryInterface(const IID& iid,
void **ppv)
{
if ( iid == IID_IUnknown ) {
*ppv = static_castthis ;
((IDictionary *)(*ppv))->AddRef() ;
}
else if ( iid == IID_Dictionary ) {
*ppv = static_castthis ;
((IDictionary *)(*ppv))->AddRef() ;
}
else if ( iid == IID_SpellCheck ) {
*ppv = static_castthis ;
((ISpellCheck *)(*ppv))->AddRef() ;
}
else {
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;}
return S_OK;
}
CreatObject
BOOL _stdcall CreateObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if (clsid == CLSID_Dictionary ) {
CDictionary *pObject = new CDictionary;
HRESULT result = pobject->QueryInterface(id, ppv);
return (result == S_OK) ? TEUR : FALSE;
}
类厂(COM规定每一对象类均应有相应的类厂)
struct IClassFactory : public IUnknown
{
virtual HRESULT _stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid,
void** ppvObject ) = 0;
virtual HRESULT _stdcall LockServer( BOOL bLock ) = 0;};
类厂使用: HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv );
参考:http://blog.csdn.net/guogangj/archive/2006/10/30/1357576.aspx
CoGetClassObject / CoCreatInstance / CoCreatInstanceEX
CoCreatInstance
二、COM特性
包容与聚合
定义接口:
class ISomeInterface : public IUnknown
{
public:
virtual HRESULT __stdcall SomeFunction() = 0;
};
class IOtherInterface : public IUnknown
{
public:
virtual HRESULT __stdcall OtherFunction() = 0;
};
包容:外部对象定义
class CB : public ISomeInterface , public IOtherInterface
{
private :
ISomeInterface *m_pSomeInterface;
};
包容:外部对象的实现
HRESULT CB::Init()
{
HRESULT result = ::CoCreateInstance(CLSID_ComponentA, NULL,
CLSCTX_INPROC_SERVER, IID_ISomeInterface, (void **)&m_pSomeInterface) ;
}
包容:外部对象类厂的实现
HRESULT CBFactory::CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv)
{
CB *pObj; HRESULT hr; *ppv=NULL;
if (pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
pObj=new CB (); if (pObj == NULL) return E_OUTOFMEMORY; hr = pObj->Init();
if (FAILED(hr) ) {g_ObjectNumber --; delete pObj;}
//Obtain the first interface pointer (which does an AddRef)
hr=pObj->QueryInterface(iid, ppv); return hr;
}
聚合:外部对象的定义
class CB : public IOtherInterface
{
HRESULT Init();
private :
IUnknown *m_pUnknownInner; // pointer to A's IUnknown
};
聚合:外部对象的QueryInterface
HRESULT CB::QueryInterface(const IID& iid, void **ppv)
{
if ( iid == IID_IUnknown ) {*ppv = (IUnknown *) this ;((IUnknown *)(*ppv))->AddRef() ;
} else if ( iid == IID_OtherInterface ) {*ppv = (IOtherInterface *) this ;((IOtherInterface *)(*ppv))->AddRef() ;
} else if ( iid == IID_SomeInterface ) {return m_pUnknownInner->QueryInterface(iid, ppv) ;
} else {*ppv = NULL;return E_NOINTERFACE ;}
return S_OK;
}
聚合:定义两种 IUnknown接口
解决IUnknown接口指针不一致的问题(因为C++类不能同时继承实现两个IUnknown,所以为非委托接口定义一个新的类)。而且被聚合接口ISomeInterface请求不到聚合接口IOtherInterface,这与COM规范矛盾:对象创建函数CoCreateInstance的第二个参数pUnknownOuter用于解决聚合中IUnknown接口的问题。当其为NULL时表示正常使用,不为NULL时被聚合使用。内部对象实现两个IUnknown 分别用于这两种情况:委托IUnknown和非委托IUnknown(delegating unknown和nondelgating unknown)。
class INondelegationUnknown
{
public:
virtual HRESULT __stdcall NondelegationQueryInterface(const IID& iid, void **ppv) = 0 ;
virtual ULONG __stdcall NondelegationAddRef() = 0;
virtual ULONG __stdcall NondelegationRelease() = 0;
};
内部对象的定义
class CA : public ISomeInterface, public INondelegationUnknown
{
protected:
ULONG m_Ref;
public:
CA ( IUnknown *pUnknownOuter);
~ CA ( );
public :
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef() ;
virtual ULONG __stdcall Release() ;
virtual HRESULT __stdcall NondelegationQueryInterface(const IID& iid, void **ppv) ;
virtual ULONG __stdcall NondelegationAddRef() ;
virtual ULONG __stdcall NondelegationRelease() ;
…….
private :
IUnknown *m_pUnknownOuter; // pointer to outer IUnknown
};
聚合:非委托IUnknown接口的实现
AddRef和Release与正常情况相同
HRESULT CA:: NondelegationQueryInterface(const IID& iid, void **ppv)
{
if ( iid == IID_IUnknown ) {*ppv = (INondelegatingUnknown *) this ;((IUnknown *)(*ppv))->AddRef() ;
} else if ( iid == IID_SomeInterface ) {*ppv = (ISomeInterface *) this ;((ISomeInterface *)(*ppv))->AddRef() ;
} else {*ppv = NULL;return E_NOINTERFACE ;}
return S_OK;}
聚合:委托IUnknown接口的实现
ULONG CA:: AddRef ()
{ if ( m_pUnknownOuter != NULL ) return m_pUnknownOuter->AddRef();
else return NondelegatingAddRef(); }
HRESULT CA:: QueryInterface(const IID& iid, void **ppv)
{ if ( m_pUnknownOuter != NULL ) return m_pUnknownOuter->QueryInterface(iid, ppv);
else return NondelegatingQueryInterface(iid, ppv); }
聚合:外部对象的创建
外部对象类厂在构造了CB之后,调用Init函数,类厂的CreateInstance函数与包容模型相同.但CB::Init函数不同:
HRESULT CB::Init()
{ IUnknown *pUnknownOuter = (IUnknown *)this;
HRESULT result = ::CoCreateInstance(CLSID_ComponentA, pUnknownOuter, CLSCTX_INPROC_SERVER,
IID_IUnknown, (void **)& m_pUnknownInner) ;
if (FAILED(result)) return E_FAIL;
else return S_OK; }
聚合:外部对象的析构
CB::~CB ( ) { if (m_pUnknownInner ! = NULL) m_pUnknownInner->Release() ; }
内部对象的创建
HRESULT CAFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
// iid must be IID_IUnknown for aggregating
if ( ( pUnknownOuter != NULL ) && ( iid != IID_IUnknown ) ) { return CLASS_E_NOAGGREGATION; }
*ppv=NULL; //Create the object passing function to notify on destruction.
CA *pObj=new CA (pUnknownOuter); if (pObj == NULL) return E_OUTOFMEMORY; //Obtain the first interface pointer (which does an AddRef)
HRESULT hr = pObj->NondelegatingQueryInterface(iid, ppv); return hr;
}
聚合:内部对象的构造函数
CA::CA (IUnknown *pUnknownOuter)
{ m_pUnknownOuter = pUnknownOuter; }
聚合:外部对象的创建(修订)
HRESULT CB::Init()
{
IUnknown *pUnknownOuter = (IUnknown *)this;
HRESULT result = ::CoCreateInstance(CLSID_CompA, pUnknownOuter,
CLSCTX_INPROC_SERVER,
IID_IUnknown, (void **)& m_pUnknownInner) ;
if (FAILED(result)) return E_FAIL;
result = m_pUnknownInner->QueryInterface(IID_ISomeInterface,
(void **)&m_pSomeInterface);
if (FAILED(result)) {
m_pUnknownInner->Release();
return E_FAIL;
}
pUnknownOuter->Release();
return S_OK;
}
聚合:外部对象的创建(修订)
HRESULT CBFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
CB *pObj; HRESULT hr; *ppv=NULL;
if (NULL != pUnknownOuter) return CLASS_E_NOAGGREGATION;
pObj=new CB ();
if (pObj == NULL) return E_OUTOFMEMORY;
pObj->AddRef(); // The Reference count of pObj is 1
hr = pObj->Init();
if (FAILED(hr) ) { g_CompBNumber --; delete pObj;
return E_FAIL; }
hr=pObj->QueryInterface(iid, ppv);
pObj->Release(); // The Reference count of pObj is 1
return hr;
}
聚合:外部对象的析构(修订)
CB::~CB ( )
{
m_Ref = 1;
IUnknown *pUnknownOuter = this;
pUnknownOuter->AddRef ( );
if (m_pSomeInterface != NULL)
m_pSomeInterface->Release();
if (m_pUnknownInner != NULL)
m_pUnknownInner->Release() ;
}
用嵌套类实现COM接口
class CDictionary
{
…… //构造函数和析构函数
用嵌套类实现COM接口
class CDictionary
{
//构造函数和析构函数
HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObj);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
class XDictionaryObj : public IDictionary {
public:
CDictionary * m_pParent;
virtual HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual BOOL __stdcall Initialize();
...
virtual void __stdcall FreeLibrary();
} m_dictionaryObj;
class XSpellCheckObj : public ISpellCheck {
public:
CDictionary * m_pParent;
virtual HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual BOOL __stdcall CheckWord (String word, String *);
} m_spellCheckObj;
private :
struct DictWord *m_pData;
char *m_DictFilename[128];
int m_Ref ;
int m_nWordNumber, m_nStructNumber;};
CDictionary::CDictionary()
{
// Initializtion
m_dictionaryObj. m_pParent = this;
m_spellCheckObj. m_pParent = this;
}
HRESULT CDictionary::QueryInterface(const IID& iid, void **ppvObj)
{
if (iid == IID_IUnknown || iid == IID_Dictionary) {*ppvObj = &m_dictionaryObj;AddRef();return S_OK;
} else if (iid == IID_SpellCheck) {*ppvObj = &m_spellCheckObj;AddRef();return S_OK;}
*ppv = NULL; return E_NOINTERFACE ;
}
ULONG CDictionary::XDictionaryObj::QueryInterface(const IID& iid, void **ppvObj)
{ return m_pParent->QueryInterface(iid, ppvObj); }
......
MFC与COM
接口映射表的宏定义
#define BEGIN_INTERFACE_MAP(theClass, theBase) /
const AFX_INTERFACEMAP* PASCAL theClass::_GetBaseInterfaceMap() /
{ return &theBase::interfaceMap; } /
const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const /
{ return &theClass::interfaceMap; } /
AFX_COMDAT const AFX_DATADEF /
AFX_INTERFACEMAP theClass::interfaceMap = /
{ &theClass::_GetBaseInterfaceMap, &theClass::_interfaceEntries[0], }; /
AFX_COMDAT const AFX_DATADEF
AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = /
{ /
#define INTERFACE_PART(theClass, iid, localClass) /
{ &iid, offsetof(theClass, m_x##localClass) }, /
#define END_INTERFACE_MAP() /
{ NULL, (size_t)-1 } /}; /
CCmdTarget类实现IUnknown
public:
// data used when CCmdTarget is made OLE aware
long m_dwRef;
LPUNKNOWN m_pOuterUnknown; // external controlling unknown if != NULL
DWORD m_xInnerUnknown; // place-holder for inner controlling unknown
public:
// advanced operations
void EnableAggregation(); // call to enable aggregation
void ExternalDisconnect(); // forcibly disconnect
LPUNKNOWN GetControllingUnknown();
// get controlling IUnknown for aggregate creation
public:
// these versions do not delegate to m_pOuterUnknown
DWORD InternalQueryInterface(const void*, LPVOID* ppvObj);
DWORD InternalAddRef();
DWORD InternalRelease();
// these versions delegate to m_pOuterUnknown
DWORD ExternalQueryInterface(const void*, LPVOID* ppvObj);
DWORD ExternalAddRef();
DWORD ExternalRelease();
DWORD CCmdTarget::InternalQueryInterface(const void* iid, LPVOID* ppvObj)
{ // check local interfaces
if ((*ppvObj = GetInterface(iid)) != NULL) { ExternalAddRef(); return S_OK; } // interface was found -- add a reference
// check aggregates
if ((*ppvObj = QueryAggregates(iid)) != NULL) return S_OK;
return (DWORD)E_NOINTERFACE; // interface ID not found, fail the call
}
CCmdTarget中ExternalXXX成员实现
DWORD CCmdTarget::ExternalAddRef()
{ // delegate to controlling unknown if aggregated
if (m_pOuterUnknown != NULL) return m_pOuterUnknown->AddRef();
return InternalAddRef();
}
DWORD CCmdTarget::ExternalRelease() // …...
// QueryInterface that is exported to normal clients
DWORD CCmdTarget::ExternalQueryInterface(const void* iid, LPVOID* ppvObj)
{
// delegate to controlling unknown if aggregated
if (m_pOuterUnknown != NULL) return m_pOuterUnknown->QueryInterface(*(IID*)iid, ppvObj);
return InternalQueryInterface(iid, ppvObj);
}
嵌套类内部实现IUnknown的成员函数
STDMETHODIMP_(ULONG) CDictionary::XDictionary::QueryInterface (
const void* iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CDictionary, Dictionary)
return pThis->ExternalQueryInterface (iid, ppvObj);
}
COM引出函数和类厂实现
在AppWizard中选中"Automation"检查框
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return AfxDllGetClassObject(rclsid, riid, ppv);
}
STDAPI DllCanUnloadNow(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return AfxDllCanUnloadNow();
}
// by exporting DllRegisterServer, you can use regsvr.exe
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
COleObjectFactory::UpdateRegistryAll();
return S_OK;
}
前两个函数是COM程序所必须的。
MFC提供了通用的类厂COleObjectFactory,由CCmadTarget派生。
MFC版本的字典对象类定义
CCmdTarget实现了内部和外部IUnknown分别对应聚合模型中的非委托与委托IUnknown。
class CDictionary : public CCmdTarget
{
DECLARE_DYNCREATE(CDictionary)
CDictionary(); // protected constructor used by dynamic creation
DECLARE_INTERFACE_MAP()
......
// IDictionary
BEGIN_INTERFACE_PART(Dictionary, IDictionary)
INIT_INTERFACE_PART(CDictionary, Dictionary)
STDMETHOD_(BOOL, Initialize)();
……
STDMETHOD_(void, FreeLibrary)();
END_INTERFACE_PART_STATIC(Dictionary)
// ISpellCheck
BEGIN_INTERFACE_PART(SpellCheck, ISpellCheck)
INIT_INTERFACE_PART(CDictionary, SpellCheck)
STDMETHOD_(BOOL, CheckWord)(LPOLESTR, LPOLESTR *);
END_INTERFACE_PART_STATIC(SpellCheck)
};
MFC版本的字典对象类实现
STDMETHODIMP_(ULONG) CDictionary::XDictionary::AddRef()
{
METHOD_PROLOGUE_EX_(CDictionary, Dictionary)
return pThis->ExternalAddRef();
}
三、自动化对象
New Class: CMyAutoObj
base Class : CCmdTarget
Automation: Createable by type ID: (AutoComp.MyAutoObj)
加入属性x,y,方法MoveTo
.h文件中
//{{AFX_DISPATCH(CPointObj)
afx_msg long GetX();
afx_msg void SetX(long nNewValue);
afx_msg void MoveTo(long nx, ong ny);
//}}AFX_DISPATCH
.cpp文件中
BEGIN_DISPATCH_MAP(CCalcDlg, CDialog)
//{{AFX_DISPATCH_MAP(CCalcDlg)
DISP_PROPERTY_EX(CPointObj, "X", GetX, SetX, VT_I4)
DISP_PROPERTY_EX(CPointObj, "Y", GetY, SetY, VT_I4)
DISP_FUNCTION(CPointObj, "MoveTo", MoveTo, VT_EMPTY, VTS_I4 VTS_I4)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
COleDispatchDriver类
class IPointObj : public COleDispatchDriver
{
public:
IPointObj(){}
IPointObj(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
IPointObj(const IPointObj& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
public:
long GetX();
void SetX(long);
long GetY();
void SetY(long);
public:
void MoveTo(long nx, ong ny);
}
long IPointObj::GetX(long propVal)
{
long result;
GetProperty(0x1, VT_14, (void*)&result);
return result;
}
void IPointObj::SetX()
{
SetProperty(0x1, VT_14, propVal);
}
void IPointObj::MoveTo(long nx, ong ny)
{
static BYTE parms[] = VTS_I4, VTS_I4;
InvokeHelper(0x3, DISPATCH_METHOD, VT_EMPTY, NULL, parms, nx, ny);
}