在网上搜Com聚合的例子,发现都比较少,要么是使用ATL,要么是模拟ATL的方式,要么就是模拟MFC的方式,大多偏于原理性的介绍。由于模拟MFC 和真正使用MFC时,在查询IUnknown接口时,流程上有所不同,所以模拟MFC的方式与直接从CCmdTarget派生时,在流程上有较大的差别。即使懂了Com聚合的原理,也可能无法直接使用MFC实现Com 聚合,本人经过一番摸索,终于实现了直接使用MFC实现COM聚合,例子如下:
#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) };
#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; }
#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() };
#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);; }
#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; }
原文地址:http://blog.csdn.net/smartfox80/article/details/39959471