一个模拟的COM示例程序

      我认为这是《Visual c++技术内幕》这本书中讲的最为出色的一个示例,将COM的“面向接口”的思路讲述得相当清晰,再加上嵌套类和引用计数的使用,让COM初学者能一窥其实质。

      就我的理解,COM就好比是一瓶“胶水“,把客户exe同所需要的DLL或者其他exe”黏合“起来,而这些工作对客户来说是透明的,客户只是按双方协商好的协议,使用特定的接口就行了,只要接口保持不变,客户就不需要跟随DLL等的变化而变化,是为”面向接口“,这一切都是COM的功劳,而且COM使用包容和集合来代替继承,更加符合面向对象的思想。

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

ContractedBlock.gif ExpandedBlockStart.gif 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

ContractedBlock.gif ExpandedBlockStart.gif 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

ContractedBlock.gif ExpandedBlockStart.gif 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

ContractedBlock.gif ExpandedBlockStart.gif 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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值