您的位置:首页 > 其它

一个模拟的COM示例程序

2007-11-17 20:53 387 查看
我认为这是《Visual
c++技术内幕》这本书中讲的最为出色的一个示例,将COM的“面向接口”的思路讲述得相当清晰,再加上嵌套类和引用计数的使用,让COM初学者能一窥其实质。
就我的理解,COM就好比是一瓶“胶水“,把客户exe同所需要的DLL或者其他exe”黏合“起来,而这些工作对客户来说是透明的,客户只是按双方协商好的协议,使用特定的接口就行了,只要接口保持不变,客户就不需要跟随DLL等的变化而变化,是为”面向接口“,这一切都是COM的功劳,而且COM使用包容和集合来代替继承,更加符合面向对象的思想。// client.cpp
pseudo-OLE command-line application




Code
#include <stdio.h>
#include <stddef.h> // for offsetof in METHOD_PROLOGUE
#include <assert.h>
#include "interface.h"

//----------main program-----------------------------------------------
int main() // simulates OLE client program
{
TRACE("6 Entering client main/n"); //第6 步
IUnknown* pUnk; // If you declare these void*, you lose type-safety
IMotion* pMot;
IVisual* pVis;
IClassFactory* pClf;
GetClassObject(CLSID_CSpaceship, IID_IClassFactory, (void**) &pClf);
pClf->CreateInstance(IID_IUnknown, (void**) &pUnk);
pUnk->QueryInterface(IID_IMotion, (void**) &pMot); // All three pointers should work
pMot->QueryInterface(IID_IVisual, (void**) &pVis); //
TRACE("23 main: pUnk = %p, pMot = %p, pDis = %p/n", pUnk, pMot, pVis); //第23 步
// Test all the interface virtual functions
pMot->Fly();
int nPos = pMot->GetPosition();
TRACE("32 nPos = %d/n", nPos);//第32 步
pVis->Display();
pClf->Release();
pUnk->Release();
pMot->Release();
pVis->Release();
return 0;
}

// interface.h definitions that make our code look like MFC code




Code
#define BOOL int
#define DWORD unsigned int
#define TRUE 1
#define FALSE 0
#define TRACE printf
#define ASSERT assert
//----------definitions and macros-----------------------------------
#define CLSID_CSpaceship 10
#define IID_IUnknown 0
#define IID_IClassFactory 1
#define IID_IMotion 2
#define IID_IVisual 3
// this macro for 16-bit Windows only
#define METHOD_PROLOGUE(theClass, localClass) /
theClass* pThis = ((theClass*)((char*)(this) - /
offsetof(theClass, m_x##localClass))); /

BOOL GetClassObject(int nClsid, int nIid, void** ppvObj);

//----------interface declarations-----------------------------------
struct IUnknown
{
IUnknown()
{
TRACE("2 10 13 Entering IUnknown ctor %p/n", this); //第2 步 //第10 步//第13 步
}
virtual BOOL QueryInterface(int nIid, void** ppvObj) = 0;
virtual DWORD Release() = 0;
virtual DWORD AddRef() = 0;
};
struct IClassFactory : public IUnknown
{
IClassFactory()
{
TRACE("3 Entering IClassFactory ctor %p/n", this); //第3 步
}
virtual BOOL CreateInstance(int nIid, void** ppvObj) = 0;
};

struct IMotion : public IUnknown
{
IMotion()
{
TRACE("11 Entering IMotion ctor %p/n", this); //第11 步
}
virtual void Fly() = 0; // pure
virtual int& GetPosition() = 0;
};
struct IVisual : public IUnknown
{
IVisual()
{
TRACE("14 Entering IVisual ctor %p/n", this); //第14 步
}
virtual void Display() = 0;
};
class CSimulatedCmdTarget // 'simulated' CSimulatedCmdTarget
{
public:
DWORD m_dwRef;
protected:
CSimulatedCmdTarget()
{
TRACE("1 9 Entering CSimulatedCmdTarget ctor %p/n", this); //第1 步 //第9 步
m_dwRef = 1; // implied first AddRef
}
virtual ~CSimulatedCmdTarget()
{
TRACE("47 49 Entering CSimulatedCmdTarget dtor %p/n", this); //第47 步//第49 步
}

DWORD ExternalRelease()
{
//第18 步//第38 步//第40 步//第42 步//第44 步
TRACE("18 38 40 42 44 Entering CSimulatedCmdTarget::ExternalRelease--RefCount = %ld/n",m_dwRef);
if (m_dwRef == 0)
return 0;
if(--m_dwRef == 0L)
{
TRACE("45 deleting/n"); //第45 步
delete this;
return 0;
}
return m_dwRef;
}
DWORD ExternalAddRef()
{
return ++m_dwRef;
}
};

// Spaceship.h




Code
class CSpaceship;
//----------class declarations-----------------------------------------------
class CSpaceshipFactory : public CSimulatedCmdTarget
{
public:
CSpaceshipFactory()
{
TRACE("5 Entering CSpaceshipFactory ctor %p/n", this); //第5 步
}
~CSpaceshipFactory()
{
TRACE("48 Entering CSpaceshipFactory dtor %p/n", this); //第48 步
}
BOOL ExternalQueryInterface(int lRid, void** ppvObj);
class XClassFactory : public IClassFactory
{
public:
XClassFactory()
{
TRACE("4 Entering XClassFactory ctor %p/n", this); //第4 步
}
virtual BOOL QueryInterface(int lRid, void** ppvObj);
virtual DWORD Release();
virtual DWORD AddRef();
virtual BOOL CreateInstance(int lRid, void** ppvObj);
} m_xClassFactory;
friend class XClassFactory;
};
class CSpaceship : public CSimulatedCmdTarget
{
private:
int m_nPosition; // We can access these from all the interfaces
int m_nAcceleration;
int m_nColor;
public:
CSpaceship()
{
TRACE("16 Entering CSpaceship ctor %p/n", this); //第16 步
m_nPosition = 100;
m_nAcceleration = 101;
m_nColor = 102;
}
~CSpaceship()
{
TRACE("46 Entering CSpaceship dtor %p/n", this); //第46 步
}
BOOL ExternalQueryInterface(int lRid, void** ppvObj);
class XMotion : public IMotion
{
public:
XMotion()
{
TRACE("12 Entering XMotion ctor %p/n", this); //第12 步
}
virtual BOOL QueryInterface(int lRid, void** ppvObj);
virtual DWORD Release();
virtual DWORD AddRef();
virtual void Fly();
virtual int& GetPosition();
} m_xMotion;
class XVisual : public IVisual
{
public:
XVisual()
{
TRACE("15 Entering XVisual ctor/n"); //第15 步
}
virtual BOOL QueryInterface(int lRid, void** ppvObj);
virtual DWORD Release();
virtual DWORD AddRef();
virtual void Display();
} m_xVisual;
friend class XVisual; // These must be at the bottom!
friend class XMotion;
friend class CSpaceshipFactory::XClassFactory;
};

// Spaceship.cpp
pseudo-OLE command-line application




Code
#include <stdio.h>
#include <stddef.h> // for offsetof in METHOD_PROLOGUE
#include <ASSERT.h>
#include "Interface.h"
#include "Spaceship.h"
CSpaceshipFactory g_factory;
//----------member functions-----------------------------------------
BOOL CSpaceshipFactory::ExternalQueryInterface(int nIid,void** ppvObj)
{
TRACE("7 Entering CSpaceshipFactory::ExternalQueryInterface--nIid = %d/n" ,nIid); //第7 步
switch (nIid)
{
case IID_IUnknown:
case IID_IClassFactory:
*ppvObj = &m_xClassFactory;
break;
default:
*ppvObj = NULL;
return FALSE;
}
ExternalAddRef();
return TRUE;
}
BOOL CSpaceshipFactory::XClassFactory::QueryInterface(int nIid,void** ppvObj)
{
TRACE("Entering CSpaceshipFactory::XClassFactory::QueryInterface--nIid = %d/n", nIid);
METHOD_PROLOGUE(CSpaceshipFactory, ClassFactory) // makes pThis
return pThis->ExternalQueryInterface(nIid, ppvObj); // delegate to CSpaceshipFactory
}
BOOL CSpaceshipFactory::XClassFactory::CreateInstance(int nIid,void** ppvObj)
{
TRACE("8 Entering CSpaceshipFactory::XClassFactory::CreateInstance/n"); //第8 步
METHOD_PROLOGUE(CSpaceshipFactory, ClassFactory) // makes pThis
CSpaceship* pObj = new CSpaceship();
if (pObj->ExternalQueryInterface(nIid, ppvObj))
{
pObj->ExternalRelease(); // balance reference count
return TRUE;
}
return FALSE;
}
DWORD CSpaceshipFactory::XClassFactory::Release()
{
TRACE("37 Entering CSpaceshipFactory::XClassFactory::Release/n"); //第37 步
METHOD_PROLOGUE(CSpaceshipFactory, ClassFactory) // makes pThis
return pThis->ExternalRelease(); // delegate to CSimulatedCmdTarget
}
DWORD CSpaceshipFactory::XClassFactory::AddRef()
{
TRACE("Entering CSpaceshipFactory::XClassFactory::AddRef/n");
METHOD_PROLOGUE(CSpaceshipFactory, ClassFactory) // makes pThis
return pThis->ExternalAddRef(); // delegate to CSimulatedCmdTarget
}
BOOL CSpaceship::ExternalQueryInterface(int nIid, void** ppvObj)
{
TRACE("17 20 22 Entering CSpaceship::ExternalQueryInterface--nIid = %d/n",nIid); //第17 步//第20 步//第22 步
switch (nIid)
{
case IID_IUnknown:
case IID_IMotion:
*ppvObj = &m_xMotion; // Both IMotion and IVisual are derived
break; // from IUnknown, so either pointer will do
case IID_IVisual:
*ppvObj = &m_xVisual;
break;
default:
*ppvObj = NULL;
return FALSE;
}
ExternalAddRef();
return TRUE;
}
BOOL CSpaceship::XMotion::QueryInterface(int nIid, void** ppvObj) {
TRACE("19 21 Entering CSpaceship::XMotion::QueryInterface--nIid = %d/n", nIid); //第19 步//第21 步
METHOD_PROLOGUE(CSpaceship, Motion) // makes pThis
return pThis->ExternalQueryInterface(nIid, ppvObj); // delegate to CSpaceship
}
DWORD CSpaceship::XMotion::Release() {
TRACE("39 41 Entering CSpaceship::XMotion::Release/n"); //第39 步//第41 步
METHOD_PROLOGUE(CSpaceship, Motion) // makes pThis
return pThis->ExternalRelease(); // delegate to CSimulatedCmdTarget
}
DWORD CSpaceship::XMotion::AddRef() {
TRACE("Entering CSpaceship::XMotion::AddRef/n");
METHOD_PROLOGUE(CSpaceship, Motion) // makes pThis
return pThis->ExternalAddRef(); // delegate to CSimulatedCmdTarget
}
void CSpaceship::XMotion::Fly() {
TRACE("24 Entering CSpaceship::XMotion::Fly/n"); //第24 步
METHOD_PROLOGUE(CSpaceship, Motion) // makes pThis
TRACE("25 this = %p, pThis = %p/n", this, pThis); //第25 步
TRACE("26 m_nPosition = %d/n", pThis->m_nPosition); //第26 步
TRACE("27 m_nAcceleration = %d/n", pThis->m_nAcceleration);//第27 步
}
int& CSpaceship::XMotion::GetPosition() {
TRACE("28 Entering CSpaceship::XMotion::GetPosition/n"); //第28 步
METHOD_PROLOGUE(CSpaceship, Motion) // makes pThis
TRACE("29 this = %p, pThis = %p/n", this, pThis); //第29 步
TRACE("30 m_nPosition = %d/n", pThis->m_nPosition); //第30 步
TRACE("31 m_nAcceleration = %d/n", pThis->m_nAcceleration);//第31 步
return pThis->m_nPosition;
}
BOOL CSpaceship::XVisual::QueryInterface(int nIid, void** ppvObj) {
TRACE("Entering CSpaceship::XVisual::QueryInterface--nIid = %d/n", nIid);
METHOD_PROLOGUE(CSpaceship, Visual) // makes pThis
return pThis->ExternalQueryInterface(nIid, ppvObj); // delegate to
// CSpaceship
}
DWORD CSpaceship::XVisual::Release() {
TRACE("43 Entering CSpaceship::XVisual::Release/n"); //第43 步
METHOD_PROLOGUE(CSpaceship, Visual) // makes pThis
return pThis->ExternalRelease(); // delegate to CSimulatedCmdTarget
}
DWORD CSpaceship::XVisual::AddRef() {
TRACE("Entering CSpaceship::XVisual::AddRef/n");
METHOD_PROLOGUE(CSpaceship, Visual) // makes pThis
return pThis->ExternalAddRef(); // delegate to CSimulatedCmdTarget
}
void CSpaceship::XVisual::Display() {
TRACE("33 Entering CSpaceship::XVisual::Display/n"); //第33 步
METHOD_PROLOGUE(CSpaceship, Visual) // makes pThis
TRACE("34 this = %p, pThis = %p/n", this, pThis); //第34 步
TRACE("35 m_nPosition = %d/n", pThis->m_nPosition); //第35 步
TRACE("36 m_nColor = %d/n", pThis->m_nColor); //第36 步
}
//----------simulates COM component ----------------------------------
// In real COM, this would be DllGetClassObject, which would be called
// whenever a client called CoGetClassObject
BOOL GetClassObject(int nClsid, int nIid, void** ppvObj)
{
ASSERT(nClsid == CLSID_CSpaceship);
ASSERT((nIid == IID_IUnknown) || (nIid == IID_IClassFactory));
return g_factory.ExternalQueryInterface(nIid, ppvObj);
// refcount is 2, which prevents accidental deletion
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: