跨入COM世界的第一步

尽管.NET战略使COM地位下降,但因工作需关注DirectX,了解COM成首要任务。文章介绍了COM基本概念,包括其是一种标准,具备跨语言和跨进程交互能力。还阐述了COM包含的两部分及实现方式,最后用代码示例展示COM Interface和COM Object模样。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

None.gif#include <objbase.h>
None.gif
None.gif
// {806E1B52-5100-4766-ADD7-E1765AF2A08B}
None.gif
static const IID IID_IX = 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif0x806e1b520x51000x4766dot.gif0xad0xd70xe10x760x5a0xf20xa00x8b } };
None.gif
None.gif
// {F86FE046-C8C0-4a9b-8936-D747269C1981}
None.gif
static const IID IID_IY = 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif0xf86fe0460xc8c00x4a9bdot.gif0x890x360xd70x470x260x9c0x190x81 } };
None.gif
None.gif
interface InterfaceX : IUnknown
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
virtual void Fx() = 0;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
interface InterfaceY : IUnknown
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
virtual void Fy() = 0;
ExpandedBlockEnd.gif}
;

                                                                    (SimpleInterface.hpp)  

None.gif#include "SimpleInterface.hpp"
None.gif
None.gif
class ComObject : public InterfaceX,
None.gif                                
public InterfaceY
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
private:
InBlock.gif    ULONG refCount;
InBlock.gif
InBlock.gif
public:
InBlock.gif    
virtual HRESULT __stdcall QueryInterface(const IID &iid, void ** iface);
InBlock.gif    
virtual ULONG __stdcall AddRef();
InBlock.gif    
virtual ULONG __stdcall Release();
InBlock.gif    
void Fx();
InBlock.gif    
void Fy();
ExpandedBlockEnd.gif}
;

                                                                     (FirstCOM.hpp)

None.gif#include "FirstCOM.hpp"
None.gif#include 
<iostream>
None.gif
None.gif
using namespace std;
None.gif
None.gifHRESULT __stdcall ComObject::QueryInterface(
const IID &iid, void ** iface)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(iid == IID_IX)
InBlock.gif       
*iface = (InterfaceX*this;
InBlock.gif    
else 
InBlock.gif        
if (iid == IID_IY)
InBlock.gif            
*iface = (InterfaceY*this;
InBlock.gif    
else
InBlock.gif        
*iface = 0;
InBlock.gif        
return E_NOINTERFACE;
InBlock.gif    ((IUnknown
*) (*iface))->AddRef();
InBlock.gif    
return (S_OK);
ExpandedBlockEnd.gif}

None.gif
None.gifULONG __stdcall ComObject::AddRef()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    cout 
<< "Add one reference" << endl;
InBlock.gif    
return(refCount++);
ExpandedBlockEnd.gif}

None.gif
None.gifULONG __stdcall ComObject::Release()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    cout 
<< "Release one reference" << endl;
InBlock.gif    
if (--refCount == 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        delete 
this;
InBlock.gif        
return 0;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
InBlock.gif        
return refCount;
ExpandedBlockEnd.gif}

None.gif
None.gif
void ComObject::Fx()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    cout 
<< "Fx() is being called!" << endl;
ExpandedBlockEnd.gif}

None.gif
None.gif
void ComObject::Fy()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    cout 
<< "Fy() is being called!" << endl;
ExpandedBlockEnd.gif}

                                                                           (FirstCOM.cpp)   

None.gif#include "FirstCOM.hpp"None.gif
None.gif
None.gif
void main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    InterfaceX 
*ix = NULL;
InBlock.gif    InterfaceY 
*iy = NULL;
InBlock.gif
InBlock.gif    ComObject
* comObject = new ComObject;
InBlock.gif    comObject 
-> QueryInterface(IID_IX, (void **&ix);
InBlock.gif    ix
-> Fx();
InBlock.gif    ix
-> Release();
InBlock.gif    comObject 
-> QueryInterface(IID_IY, (void **&iy);
InBlock.gif    iy 
-> Fy();
InBlock.gif    iy 
-> Release();
InBlock.gif    comObject 
->Release();
InBlock.gif
ExpandedBlockEnd.gif}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值