The Ex22b Example: An MFC COM In-Process Component
The Ex22b example is an MFC regular DLL that incorporates a true COM version of the CSpaceship class you saw in Ex22a. The MFC DLL Wizard generated the Ex22b.cpp and Ex22b.h files, as described previously. The Interface.h file, shown in the following listing, declares the IMotion and IVisual interfaces. The code for the CSpaceship class is shown after the Interface.h file. Compare that code to the code in Ex22a. Do you see how the use of the MFC macros reduces code size? Note that the MFC CCmdTarget class takes care of the reference counting and QueryInterface logic.
Interface.h
struct IMotion : public IUnknown
{
STDMETHOD_(void, Fly) () = 0;
STDMETHOD_(int&, GetPosition) () = 0;
};
struct IVisual : public IUnknown
{
STDMETHOD_(void, Display) () = 0;
};
Spaceship.h
#pragma once
void ITrace(REFIID iid, const char* str);
// CSpaceship command target
class CSpaceship : public CCmdTarget
{
DECLARE_DYNCREATE(CSpaceship)
private:
int m_nPosition; // We can access this from all the interfaces
int m_nAcceleration;
int m_nColor;
public:
CSpaceship();
virtual ~CSpaceship();
virtual void OnFinalRelease();
protected:
DECLARE_MESSAGE_MAP()
DECLARE_OLECREATE(CSpaceship)
BEGIN_INTERFACE_PART(Motion, IMotion)
STDMETHOD_(void, Fly) ();
STDMETHOD_(int&, GetPosition) ();
END_INTERFACE_PART(Motion)
BEGIN_INTERFACE_PART(Visual, IVisual)
STDMETHOD_(void, Display) ();
END_INTERFACE_PART(Visual)
DECLARE_INTERFACE_MAP()
};
Spaceship.cpp
// Spaceship.cpp : implementation file
//
#include "stdafx.h"
#include "Ex22b.h"
#include "Interface.h"
#include "Spaceship.h"
// CSpaceship
// {692D03A4-C689-11CE-B337-88EA36DE9E4E}
static const IID IID_IMotion =
{ 0x692d03a4, 0xc689, 0x11ce,
{ 0xb3, 0x37, 0x88, 0xea, 0x36, 0xde, 0x9e, 0x4e } };
// {692D03A5-C689-11CE-B337-88EA36DE9E4E}
static const IID IID_IVisual =
{ 0x692d03a5, 0xc689, 0x11ce,
{ 0xb3, 0x37, 0x88, 0xea, 0x36, 0xde, 0x9e, 0x4e } };
IMPLEMENT_DYNCREATE(CSpaceship, CCmdTarget)
CSpaceship::CSpaceship()
{
TRACE("CSpaceship ctor\n");
m_nPosition = 100;
m_nAcceleration = 101;
m_nColor = 102;
// To keep the application running as long as an OLE automation
// object is active, the constructor calls AfxOleLockApp.
AfxOleLockApp();
}
CSpaceship::~CSpaceship()
{
TRACE("CSpaceship dtor\n");
// To terminate the application when all objects created with
// OLE automation, the destructor calls AfxOleUnlockApp.
AfxOleUnlockApp();
}
void CSpaceship::OnFinalRelease()
{
// When the last reference for an automation object is released
// OnFinalRelease is called. The base class will automatically
// delete the object. Add additional cleanup required for your
// object before calling the base class.
delete this;
}
BEGIN_MESSAGE_MAP(CSpaceship, CCmdTarget)
END_MESSAGE_MAP()
// Note: we add support for IID_ISpaceship to support typesafe binding
// from VBA. This IID must match the GUID that is attached to the
// dispinterface in the .IDL file.
// {E39B5EB0-A0DA-43F3-B9B0-206CF10890C1}
static const IID IID_ISpaceship =
{ 0xE39B5EB0, 0xA0DA, 0x43F3,
{ 0xB9, 0xB0, 0x20, 0x6C, 0xF1, 0x8, 0x90, 0xC1 } };
BEGIN_INTERFACE_MAP(CSpaceship, CCmdTarget)
INTERFACE_PART(CSpaceship, IID_IMotion, Motion)
INTERFACE_PART(CSpaceship, IID_IVisual, Visual)
END_INTERFACE_MAP()
// {13C4472C-84BB-4ED6-8164-83ED8EB136B5}
IMPLEMENT_OLECREATE_FLAGS(CSpaceship, "Ex22b.Spaceship",
afxRegApartmentThreading, 0x13c4472c, 0x84bb, 0x4ed6, 0x81,
0x64, 0x83, 0xed, 0x8e, 0xb1, 0x36, 0xb5)
STDMETHODIMP_(ULONG) CSpaceship::XMotion::AddRef()
{
TRACE("CSpaceship::XMotion::AddRef\n");
METHOD_PROLOGUE(CSpaceship, Motion)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CSpaceship::XMotion::Release()
{
TRACE("CSpaceship::XMotion::Release\n");
METHOD_PROLOGUE(CSpaceship, Motion)
return pThis->ExternalRelease();
}
STDMETHODIMP CSpaceship::XMotion::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
ITrace(iid, "CSpaceship::XMotion::QueryInterface");
METHOD_PROLOGUE(CSpaceship, Motion)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP_(void) CSpaceship::XMotion::Fly()
{
TRACE("CSpaceship::XMotion::Fly\n");
METHOD_PROLOGUE(CSpaceship, Motion)
TRACE("m_nPosition = %d\n", pThis->m_nPosition);
TRACE("m_nAcceleration = %d\n", pThis->m_nAcceleration);
return;
}
STDMETHODIMP_(int&) CSpaceship::XMotion::GetPosition()
{
TRACE("CSpaceship::XMotion::GetPosition\n");
METHOD_PROLOGUE(CSpaceship, Motion)
TRACE("m_nPosition = %d\n", pThis->m_nPosition);
TRACE("m_nAcceleration = %d\n", pThis->m_nAcceleration);
return pThis->m_nPosition;
}
STDMETHODIMP_(ULONG) CSpaceship::XVisual::AddRef()
{
TRACE("CSpaceship::XVisual::AddRef\n");
METHOD_PROLOGUE(CSpaceship, Visual)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CSpaceship::XVisual::Release()
{
TRACE("CSpaceship::XVisual::Release\n");
METHOD_PROLOGUE(CSpaceship, Visual)
return pThis->ExternalRelease();
}
STDMETHODIMP CSpaceship::XVisual::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
ITrace(iid, "CSpaceship::XVisual::QueryInterface");
METHOD_PROLOGUE(CSpaceship, Visual)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP_(void) CSpaceship::XVisual::Display()
{
TRACE("CSpaceship::XVisual::Display\n");
METHOD_PROLOGUE(CSpaceship, Visual)
TRACE("m_nPosition = %d\n", pThis->m_nPosition);
TRACE("m_nColor = %d\n", pThis->m_nColor);
}
void ITrace(REFIID iid, const char* str)
{
OLECHAR* lpszIID;
::StringFromIID(iid, &lpszIID);
CString strTemp(lpszIID);
TRACE("%s - %s\n", (const char*) strTemp, (const char*) str);
AfxFreeTaskMem(lpszIID);
}