在网上搜Com聚合的例子,发现都比较少,要么是使用ATL,要么是模拟ATL的方式,要么就是模拟MFC的方式,大多偏于原理性的介绍。由于模拟MFC 和真正使用MFC时,在查询IUnknown接口时,流程上有所不同,所以模拟MFC的方式与直接从CCmdTarget派生时,在流程上有较大的差别。即使懂了Com聚合的原理,也可能无法直接使用MFC实现Com 聚合,本人经过一番摸索,终于实现了直接使用MFC实现COM聚合,例子如下:
1.被聚合的组件
1.1 接口声明
#pragma once
typedef long HRESULT;
// {30DF3430-0266-11cf-BAA6-00AA003E0EED}
extern const GUID CLSID_Math;
//{ 0x30df3430,0x266,0x11cf,{ 0xba,0xa6,0x0,0xaa,0x3e,0xe,0xed } };
//////////////////////////////////////////////////////////////////////////////////////
// {30DF3432-0266-11cf-BAA6-00AA003E0EED}
extern const GUID IID_IOPerator;
//{ 0x30df3432,0xed } };
class IOPerator:public IUnknown
{
public:
virtual HRESULT _stdcall Add(int nParam1,int nParam2,int* pResult) =0;
virtual HRESULT _stdcall Subtract(int nParam1,int* pResult) =0;
virtual HRESULT _stdcall Multiple(int nParam1,int* pResult) =0;
virtual HRESULT _stdcall Divide(int nParam1,int* pResult) =0;
};
// {30DF3433-0266-11cf-BAA6-00AA003E0EED}
extern const GUID IID_IAdvanceOPerator;
//{ 0x30df3433,0xed } };
class IAdvanceOPerator:public IUnknown
{
public:
virtual HRESULT _stdcall Abs(int nParam1,int* pResult) =0;
virtual HRESULT _stdcall Power(int nParam1,int* pResult) =0;
};
// CMyMath command target
class CMyMath : public CCmdTarget
{
DECLARE_DYNCREATE(CMyMath)
public:
CMyMath();
virtual ~CMyMath();
virtual void OnFinalRelease();
protected:
DECLARE_OLECREATE(CMyMath)
DECLARE_MESSAGE_MAP()
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(OPerator,IOPerator)
STDMETHOD_(HRESULT,Add)(int nParam1,int* pResult);
STDMETHOD_(HRESULT,Subtract)(int nParam1,Multiple)(int nParam1,Divide)(int nParam1,int* pResult);
END_INTERFACE_PART(OPerator)
BEGIN_INTERFACE_PART(AdvanceOperator,IAdvanceOPerator)
STDMETHOD_(HRESULT,Abs)(int nParam1,Power)(int nParam1,int* pResult);
END_INTERFACE_PART(AdvanceOperator)
};
1.2 组件实现
#include "stdafx.h"
#include "MyCom16.h"
#include "MyMath.h"
// CMyMath
IMPLEMENT_DYNCREATE(CMyMath,CCmdTarget)
CMyMath::CMyMath()
{
EnableAutomation();
EnableAggregation();
}
CMyMath::~CMyMath()
{
}
void CMyMath::OnFinalRelease()
{
// When the last reference for an automation object is released
// OnFinalRelease is called. The base class will automatically
// deletes the object. Add additional cleanup required for your
// object before calling the base class.
CCmdTarget::OnFinalRelease();
}
BEGIN_MESSAGE_MAP(CMyMath,CCmdTarget)
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CMyMath,CCmdTarget)
END_DISPATCH_MAP()
// Note: we add support for IID_IMyMath to support typesafe binding
// from VBA. This IID must match the GUID that is attached to the
// dispinterface in the .IDL file.
// {7259EA0F-0E64-4FF9-BBA1-332E82AFA0D3}
static const IID IID_IMyMath =
{ 0x7259EA0F,0xE64,0x4FF9,{ 0xBB,0xA1,0x33,0x2E,0x82,0xAF,0xA0,0xD3 } };
static const GUID IID_IOPerator =
{ 0x30df3432,0xed }};
static const GUID IID_IAdvanceOPerator =
{ 0x30df3433,0xed }};
// CLSID_Math
IMPLEMENT_OLECREATE(CMyMath,"MyCom16.MyMath",0x30df3430,0xba,0xed)
BEGIN_INTERFACE_MAP(CMyMath,CCmdTarget)
INTERFACE_PART(CMyMath,IID_IMyMath,Dispatch)
INTERFACE_PART(CMyMath,IID_IOPerator,OPerator)
INTERFACE_PART(CMyMath,IID_IAdvanceOPerator,AdvanceOperator)
END_INTERFACE_MAP()
// CMyMath message handlers
ULONG CMyMath::XOPerator::AddRef()
{
METHOD_PROLOGUE(CMyMath,OPerator);
return pThis->ExternalAddRef();
}
ULONG CMyMath::XOPerator::Release()
{
METHOD_PROLOGUE(CMyMath,OPerator);
return pThis->ExternalRelease();
}
HRESULT CMyMath::XOPerator::QueryInterface(REFIID riid,void** ppObject)
{
METHOD_PROLOGUE_EX_(CMyMath,OPerator);
return pThis->ExternalQueryInterface((void *)&riid,ppObject);
}
HRESULT CMyMath::XOPerator::Add( int nParam1,int* pResult )
{
*pResult = nParam1 + nParam2;
return S_OK;
}
HRESULT CMyMath::XOPerator::Subtract( int nParam1,int* pResult )
{
*pResult = nParam1 - nParam2;
return S_OK;
}
HRESULT CMyMath::XOPerator::Multiple( int nParam1,int* pResult )
{
*pResult = nParam1 * nParam2;
return S_OK;
}
HRESULT CMyMath::XOPerator::Divide( int nParam1,int* pResult )
{
*pResult = nParam1 / nParam2;
return S_OK;
}
ULONG CMyMath::XAdvanceOperator::AddRef()
{
METHOD_PROLOGUE(CMyMath,AdvanceOperator);
return pThis->ExternalAddRef();
}
ULONG CMyMath::XAdvanceOperator::Release()
{
METHOD_PROLOGUE(CMyMath,AdvanceOperator);
return pThis->ExternalRelease();
}
HRESULT CMyMath::XAdvanceOperator::QueryInterface(REFIID riid,void** ppObject)
{
METHOD_PROLOGUE(CMyMath,AdvanceOperator);
return pThis->ExternalQueryInterface((void *)&riid,ppObject);
}
HRESULT _stdcall CMyMath::XAdvanceOperator::Abs( int nParam1,int* pResult )
{
if(nParam1 < 0)
*pResult = -nParam1;
else
*pResult = nParam1;
return S_OK;
}
HRESULT _stdcall CMyMath::XAdvanceOperator::Power( int nParam1,int* pResult )
{
*pResult =1;
for(int i=0;i<nParam2;i++)
*pResult *=nParam1;
return S_OK;
}
2 聚合组件
2.1接口声明
#pragma once
typedef long HRESULT;
class IArea:public IUnknown
{
public:
virtual HRESULT _stdcall Triangle(int width,int High,float* pResult) =0;
virtual HRESULT _stdcall Square(int lengh,float* pResult) =0;
virtual HRESULT _stdcall Cirle(int r,float* pResult) =0;
};
#pragma once
#include "IArea.h"
// CMyMath2 command target
class CMyMath2 : public CCmdTarget
{
DECLARE_DYNCREATE(CMyMath2)
public:
CMyMath2();
virtual ~CMyMath2();
virtual void OnFinalRelease();
virtual BOOL OnCreateAggregates();
BEGIN_INTERFACE_PART(Area,IArea)
STDMETHOD_(HRESULT,Triangle)(int width,float* pResult);
STDMETHOD_(HRESULT,Square)(int lengh,Cirle)(int r,float* pResult);
END_INTERFACE_PART(Area)
protected:
DECLARE_OLECREATE(CMyMath2)
DECLARE_MESSAGE_MAP()
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
};
2.2 接口实现
#include "MyMath2.h"
#include <iostream>
using namespace std;
const float PI = 3.14;
static const GUID CLSID_Math =
{ 0x30df3430,0xed } };
// CMyMath2
IMPLEMENT_DYNCREATE(CMyMath2,CCmdTarget)
CMyMath2::CMyMath2()
{
EnableAutomation();
}
CMyMath2::~CMyMath2()
{
}
void CMyMath2::OnFinalRelease()
{
// When the last reference for an automation object is released
// OnFinalRelease is called. The base class will automatically
// deletes the object. Add additional cleanup required for your
// object before calling the base class.
if(m_xInnerUnknown !=NULL)
{
IUnknown *pUnk =(IUnknown *)m_xInnerUnknown;
pUnk->Release();
}
CCmdTarget::OnFinalRelease();
}
BEGIN_MESSAGE_MAP(CMyMath2,CCmdTarget)
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CMyMath2,CCmdTarget)
END_DISPATCH_MAP()
// Note: we add support for IID_IMyMath2 to support typesafe binding
// from VBA. This IID must match the GUID that is attached to the
// dispinterface in the .IDL file.
// {60B1DE57-1DE8-4759-B220-C35E03B2049D}
static const IID IID_IMyMath2 =
{ 0x60B1DE57,0x1DE8,0x4759,{ 0xB2,0x20,0xC3,0x5E,0x3,0xB2,0x4,0x9D } };
static const GUID IID_IArea =
{ 0x30df3452,0xed }};
// CLSID_Math
IMPLEMENT_OLECREATE(CMyMath2,"MyCom9.MyMath2",0x30df3450,0xed)
BEGIN_INTERFACE_MAP(CMyMath2,CCmdTarget)
INTERFACE_PART(CMyMath2,IID_IMyMath2,Dispatch)
INTERFACE_PART(CMyMath2,IID_IArea,Area)
INTERFACE_AGGREGATE(CMyMath2,m_xInnerUnknown) //CMyMath2聚合了CMyMath
END_INTERFACE_MAP()
//CMyMath2聚合了CMyMath
BOOL CMyMath2::OnCreateAggregates()
{
#if 0
//这里是关键,不能这样写
::CoCreateInstance(CLSID_Math,(IUnknown *)this,CLSCTX_INPROC_SERVER,IID_IUnknown,(void **)&m_xInnerUnknown);
#else
LPUNKNOWN pUnk = GetControllingUnknown();
::CoCreateInstance(CLSID_Math,(IUnknown *)pUnk,(void **)&m_xInnerUnknown);
#endif
return TRUE;
}
// CMyMath2 message handlers
HRESULT _stdcall CMyMath2::XArea::Triangle( int width,float* pResult )
{
*pResult =width*High *1.0/2;
return S_OK;
}
HRESULT _stdcall CMyMath2::XArea::Square( int lengh,float* pResult )
{
*pResult =lengh *lengh*1.0/2;
return S_OK;
}
HRESULT _stdcall CMyMath2::XArea::Cirle( int r,float* pResult )
{
*pResult = PI *r*r;
return S_OK;
}
ULONG CMyMath2::XArea::AddRef()
{
METHOD_PROLOGUE(CMyMath2,Area);
return pThis->ExternalAddRef();
}
ULONG CMyMath2::XArea::Release()
{
METHOD_PROLOGUE(CMyMath2,Area);
return pThis->ExternalRelease();
}
HRESULT CMyMath2::XArea::QueryInterface(REFIID riid,void** ppObject)
{
METHOD_PROLOGUE_EX_(CMyMath2,Area);
return pThis->ExternalQueryInterface((void *)&riid,ppObject);;
}
3.测试代码
#include "../MyCom16/Operator.h"
#include "../MyCom9/IArea.h"
using namespace std;
static const GUID CLSID_Math =
{ 0x30df3430,0xed } };
static const GUID IID_IOPerator =
{ 0x30df3432,0xed } };
static const GUID IID_IAdvanceOPerator =
{ 0x30df3433,0xed } };
static const GUID CLSID_Math2 =
{ 0x30df3450,0xed }};
static const GUID IID_IArea =
{ 0x30df3452,0xed }};
int _tmain(int argc,_TCHAR* argv[])
{
CLSID clsId;
IClassFactory *pMathFactory = NULL;
IUnknown* pUnknown = NULL;
IUnknown* pUnk = NULL;
IOPerator *pOPerator = NULL;
IAdvanceOPerator *pAdvanceOperator = NULL;
IArea *pArea = NULL;
IArea *pArea2 = NULL;
IAdvanceOPerator *pAdvanceOperator2 = NULL;
int nResult = 0;
HRESULT hRes;
CoInitialize(NULL);
///////////////////////Test MyCom1///////////////////////////////////////////////////////////////////
#if 1
//CLSIDFromProgID(_T("Testcom1 Server"),&clsId);
hRes = CoGetClassObject(CLSID_Math,CLSCTX_SERVER,NULL,IID_IClassFactory,(void**) &pMathFactory);
if(FAILED(hRes))
{
return 0;
}
pMathFactory->CreateInstance(NULL,(void **)&pOPerator);
pMathFactory->Release();
pOPerator->Add(5,6,&nResult);
cout<<"5+6 ="<<nResult<<endl;
pOPerator->Multiple(5,&nResult);
cout<<"5*6 ="<<nResult<<endl;
pOPerator->Divide(5,&nResult);
cout<<"5/6 ="<<nResult<<endl;
pOPerator->QueryInterface(IID_IAdvanceOPerator,(void **)&pAdvanceOperator);
pAdvanceOperator->Abs(-123,&nResult);
cout<<"Abs(-123) ="<<nResult<<endl;
pAdvanceOperator->Power(5,3,&nResult);
cout<<"Power(5,3) ="<<nResult<<endl;
pAdvanceOperator->QueryInterface(IID_IUnknown,(void **)&pUnknown);
pOPerator->QueryInterface(IID_IUnknown,(void **)&pUnk);
pUnk->QueryInterface(IID_IAdvanceOPerator,(void **)&pAdvanceOperator2);
if(pUnk == pUnknown)
cout<<"They are the same com obj"<<endl;
else
cout<<"They not equal obj" <<endl;
pUnknown->Release();
pUnk->Release();
pAdvanceOperator->Release();
pOPerator->Release();
pAdvanceOperator2->Release();
pOPerator = NULL;
pAdvanceOperator = NULL;
pUnk = NULL;
pUnknown = NULL;
pAdvanceOperator2 =NULL;
#endif
/*
对聚合进行测试
Com9 聚合了Com1
*/
#if 1
pOPerator = NULL;
pAdvanceOperator = NULL;
pUnk =NULL;
pUnknown = NULL;
//CLSIDFromProgID(_T("Testcom1 Server"),&clsId);
hRes = CoGetClassObject(CLSID_Math2,(void **)&pArea);
pMathFactory->Release();
float fResult =0.0f;
pArea->Triangle(3,4,&fResult);
cout<<"Triangle(3,4) = "<<fResult<<endl;
pArea->Cirle(5,&fResult);
cout<<"Cirle(5) = "<<fResult<<endl;
pArea->QueryInterface(IID_IOPerator,(void **)&pOPerator);
pOPerator->Add(5,&nResult);
cout<<"5+6 ="<<nResult<<endl;
pOPerator->Multiple(5,&nResult);
cout<<"5/6 ="<<nResult<<endl;
pOPerator->QueryInterface(IID_IAdvanceOPerator,(void **)&pAdvanceOperator);
pAdvanceOperator->QueryInterface(IID_IArea,(void **)&pArea2);
if(pArea == pArea2)
cout<<"They are the same com obj"<<endl;
else
cout<<"They not equal obj" <<endl;
pArea->QueryInterface(IID_IUnknown,(void **)&pUnk);
if(pUnk ==pUnknown)
cout<<"They are the same com obj"<<endl;
else
cout<<"They not equal obj" <<endl;
pUnknown->Release();
pUnk->Release();
pArea->Release();
pOPerator->Release();
pAdvanceOperator->Release();
pArea2->Release();
#endif
::CoUninitialize();
return 0;
}
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|