代码改变世界

跨入COM世界的第一步

2004-09-07 21:11  FantasySoft  阅读(...)  评论(...编辑  收藏

        我们都知道.NET被称为更好的COM,而OLE、ActiveX等技术是以COM为基础的,大名鼎鼎的DirectX也大量使用了COM。尽管.NET战略让COM的地位日益下降,我们还是需要将足够的注意力放到COM的上面。由于工作的需要,我要开始关注DirectX的内容了,而COM又是基础,了解COM就成了首要的任务。
        以前觉得COM很神秘,只是知道一些基本的概念:COM是Component Object Model的缩写;COM不是一种新的语言
,而是一种标准;标准定义了对象的模型以及对构造对象的语言的要求,只要依据这样的标准而设计的软件都会具备跨语言和跨进程的对象交互能力,即二进制级别的代码共享。
        这些基本的概念只能够给人一点抽象的认识,那么依照COM的标准实现的代码会是怎么样的呢?
        第一、COM包含了COM Object和COM Interface两部分,在COM Interface定义了一组函数原型,但没有提供这些函数的具体实现,而implementation(具体实现)则留给了COM Object。一个COM Object可以实现一个或者多个COM Inteface,而且一旦实现某个接口,就必须提供该接口定义的所有方法的实现,这样的行为在C++中是通过纯虚函数来实现的。如果你有Java的基础会发现,这跟Java中的Interface的行为是何等的相似;
        第二、通过COM Interface的指针对COM Object进行访问。系统会维护一张与Interface相应的Function Table,而这张表实质就是一个function pointer的数组,这个数组里面包含的函数指针指向了相应的Interface的实现方法,如下图所示:

        
        一个COM Object可能会实现多个Interface,如图中的ObjectB,而一个Interface有可能有多个COM Object提供了实现,如图中的InterfaceX;
        第三、一个COM Interface必须继承IUnknown接口,而在IUnknown接口中包含了三个很重要的函数:QueryInterface、AddRef和Release。这三个函数会在后面给出的例子中看到。
        讲了那么多,还是没有看到COM的庐山真面目啊,就让我们用一段代码来揭开它的面纱吧:       

#include <objbase.h>

// {806E1B52-5100-4766-ADD7-E1765AF2A08B}
static const IID IID_IX = 
0x806e1b520x51000x47660xad0xd70xe10x760x5a0xf20xa00x8b } };

// {F86FE046-C8C0-4a9b-8936-D747269C1981}
static const IID IID_IY = 
0xf86fe0460xc8c00x4a9b0x890x360xd70x470x260x9c0x190x81 } };

interface InterfaceX : IUnknown
{
    
virtual void Fx() = 0;
}
;

interface InterfaceY : IUnknown
{
    
virtual void Fy() = 0;
}
;

                                                                    (SimpleInterface.hpp)  

#include "SimpleInterface.hpp"

class ComObject : public InterfaceX,
                                
public InterfaceY
{
private:
    ULONG refCount;

public:
    
virtual HRESULT __stdcall QueryInterface(const IID &iid, void ** iface);
    
virtual ULONG __stdcall AddRef();
    
virtual ULONG __stdcall Release();
    
void Fx();
    
void Fy();
}
;

                                                                     (FirstCOM.hpp)

#include "FirstCOM.hpp"
#include 
<iostream>

using namespace std;

HRESULT __stdcall ComObject::QueryInterface(
const IID &iid, void ** iface)
{
    
if(iid == IID_IX)
       
*iface = (InterfaceX*this;
    
else 
        
if (iid == IID_IY)
            
*iface = (InterfaceY*this;
    
else
        
*iface = 0;
        
return E_NOINTERFACE;
    ((IUnknown
*) (*iface))->AddRef();
    
return (S_OK);
}


ULONG __stdcall ComObject::AddRef()
{
    cout 
<< "Add one reference" << endl;
    
return(refCount++);
}


ULONG __stdcall ComObject::Release()
{
    cout 
<< "Release one reference" << endl;
    
if (--refCount == 0)
    
{
        delete 
this;
        
return 0;
    }

    
else
        
return refCount;
}


void ComObject::Fx()
{
    cout 
<< "Fx() is being called!" << endl;
}


void ComObject::Fy()
{
    cout 
<< "Fy() is being called!" << endl;
}

                                                                           (FirstCOM.cpp)   

#include "FirstCOM.hpp"

void main()
{
    InterfaceX 
*ix = NULL;
    InterfaceY 
*iy = NULL;

    ComObject
* comObject = new ComObject;
    comObject 
-> QueryInterface(IID_IX, (void **&ix);
    ix
-> Fx();
    ix
-> Release();
    comObject 
-> QueryInterface(IID_IY, (void **&iy);
    iy 
-> Fy();
    iy 
-> Release();
    comObject 
->Release();

}

                                                                           (Test.cpp)   
        以上代码中的COM Object并没有什么实际的意义,但是从中我们可以知道COM Inteface和COM Object是个什么模样。诚然这只是冰山一角,至少我们和COM的距离已经不再是那样遥远了。
        PS:因为是刚刚开始接触COM,写得不对的地方,还请各位高手多多指教了。/Bow