首页 > 代码库 > 一个使用MFC实现Com聚合的例子

一个使用MFC实现Com聚合的例子

在网上搜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, 0x0, 0x3e, 0xe, 0xed } };

//////////////////////////////////////////////////////////////////////////////////////

// {30DF3432-0266-11cf-BAA6-00AA003E0EED}
extern const GUID IID_IOPerator;
//{ 0x30df3432, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed } };

class IOPerator:public IUnknown
{
public:

	virtual HRESULT _stdcall Add(int nParam1, int nParam2, int* pResult) =0;
	virtual HRESULT _stdcall Subtract(int nParam1, int nParam2, int* pResult) =0;
	virtual HRESULT _stdcall Multiple(int nParam1, int nParam2, int* pResult) =0;
	virtual HRESULT _stdcall Divide(int nParam1, int nParam2, int* pResult) =0;
};


// {30DF3433-0266-11cf-BAA6-00AA003E0EED}
extern const GUID IID_IAdvanceOPerator;
//{ 0x30df3433, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed } };

class IAdvanceOPerator:public IUnknown
{
public:

	virtual HRESULT _stdcall Abs(int nParam1, int* pResult) =0;
	virtual HRESULT _stdcall Power(int nParam1, int nParam2, 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 nParam2, int* pResult);
		STDMETHOD_(HRESULT, Subtract)(int nParam1, int nParam2, int* pResult);
		STDMETHOD_(HRESULT, Multiple)(int nParam1, int nParam2, int* pResult);
		STDMETHOD_(HRESULT, Divide)(int nParam1, int nParam2, int* pResult);
	END_INTERFACE_PART(OPerator)

	BEGIN_INTERFACE_PART(AdvanceOperator, IAdvanceOPerator)  
		STDMETHOD_(HRESULT, Abs)(int nParam1, int* pResult);
		STDMETHOD_(HRESULT, Power)(int nParam1, int nParam2, 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, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed }};

static const GUID IID_IAdvanceOPerator = 
{ 0x30df3433, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed }};

// CLSID_Math
IMPLEMENT_OLECREATE(CMyMath, "MyCom16.MyMath", 0x30df3430, 0x266, 0x11cf,  0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 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 nParam2, int* pResult )
{
	*pResult = nParam1 + nParam2;
	return S_OK;
}

HRESULT  CMyMath::XOPerator::Subtract( int nParam1, int nParam2, int* pResult )
{
	*pResult = nParam1 - nParam2;
	return S_OK;
}

HRESULT  CMyMath::XOPerator::Multiple( int nParam1, int nParam2, int* pResult )
{
	*pResult = nParam1 * nParam2;
	return S_OK;
}

HRESULT  CMyMath::XOPerator::Divide( int nParam1, int nParam2, 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 nParam2, 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, int High, float* pResult);
		STDMETHOD_(HRESULT, Square)(int lengh, float* pResult);
		STDMETHOD_(HRESULT, 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, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 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, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed }};


// CLSID_Math
IMPLEMENT_OLECREATE(CMyMath2, "MyCom9.MyMath2", 0x30df3450, 0x266, 0x11cf,  0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 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,CLSCTX_INPROC_SERVER,IID_IUnknown,(void **)&m_xInnerUnknown);
#endif
	return TRUE;
}


// CMyMath2 message handlers
HRESULT _stdcall CMyMath2::XArea::Triangle( int width, int High, 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, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed } };


static const GUID IID_IOPerator =
{ 0x30df3432, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed } };

static const GUID IID_IAdvanceOPerator =
{ 0x30df3433, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed } };

static const GUID CLSID_Math2 = 
{ 0x30df3450, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 0xed }};

static const GUID IID_IArea = 
{ 0x30df3452, 0x266, 0x11cf, { 0xba, 0xa6, 0x0, 0xaa, 0x0, 0x3e, 0xe, 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,IID_IOPerator,(void **)&pOPerator);
	pMathFactory->Release();

	pOPerator->Add(5,6,&nResult);
    cout<<"5+6 ="<<nResult<<endl;
	pOPerator->Multiple(5,6,&nResult);
	cout<<"5*6 ="<<nResult<<endl;
	pOPerator->Divide(5,6,&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, CLSCTX_SERVER, NULL, IID_IClassFactory, (void**) &pMathFactory);
	if(FAILED(hRes))
	{
		return 0;
	}
	pMathFactory->CreateInstance(NULL,IID_IArea,(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,6,&nResult);
	cout<<"5+6 ="<<nResult<<endl;
	pOPerator->Multiple(5,6,&nResult);
	cout<<"5*6 ="<<nResult<<endl;
	pOPerator->Divide(5,6,&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 **)&pUnknown);
	pOPerator->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;
}


一个使用MFC实现Com聚合的例子