There are few examples of searching com aggregation on the Internet, either using ATL, simulating ATL, or simulating MFC. Most of them are based on principles. Since the process for querying the iunknown interface is different when you simulate MFC and when you actually use MFC, the method for simulating MFC is different from that for directly deriving from csf-target, there are major differences in the process. Even if you understand the principle of COM aggregation, you may not be able to directly use MFC to implement COM aggregation. After some exploration, I finally achieved the direct use of MFC to implement COM aggregation. The example is as follows:
1. the aggregated component 1.1 interface declaration
#pragma oncetypedef 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 targetclass 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 Component implementation
#include "stdafx.h"#include "MyCom16.h"#include "MyMath.h"// CMyMathIMPLEMENT_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_MathIMPLEMENT_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 handlersULONG 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. Aggregation component 2.1 interface declaration
#pragma oncetypedef 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 targetclass 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 interface implementation
#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 } };// CMyMath2IMPLEMENT_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_MathIMPLEMENT_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聚合了CMyMathEND_INTERFACE_MAP()//CMyMath2聚合了CMyMathBOOL CMyMath2::OnCreateAggregates(){#if 0//这里是关键,不能这样写::CoCreateInstance(CLSID_Math,(IUnknown *)this,CLSCTX_INPROC_SERVER,IID_IUnknown,(void **)&m_xInnerUnknown);#elseLPUNKNOWN pUnk = GetControllingUnknown();::CoCreateInstance(CLSID_Math,(IUnknown *)pUnk,CLSCTX_INPROC_SERVER,IID_IUnknown,(void **)&m_xInnerUnknown);#endifreturn TRUE;}// CMyMath2 message handlersHRESULT _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. Test code
#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;elsecout<<"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 1pOPerator = 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;elsecout<<"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;elsecout<<"They not equal obj" <<endl;pUnknown->Release();pUnk->Release();pArea->Release();pOPerator->Release();pAdvanceOperator->Release();pArea2->Release();#endif::CoUninitialize();return 0;}
An example of using MFC to implement COM Aggregation