• COM组件多接口对象模型


    COM组件有两种接口类型,Dual and Custom,如下图所示。本文说的是Custom。所谓多接口COM对象是指此COM对象实现了多于一个的自定义接口,即Custom接口。

    接口图如下:

    需要注意的是最终实现的COM对象用的不是虚继承而是普通的多继承,因为被多继承的IUnknown接口是不含任何数据成员,只有纯虚函数,继承的子接口也是这样。还有为了实现跨语言或平台的调用,最终没用虚继承。更多的原因请参考本文最后的链接。

    这里给出多接口COM对象的模型:

    很清楚地看到COM是实现了两个接口,也就是多继承子两个父接口,有两个虚函数表,其中IUnknown的三个函数指针在两个虚函数表里都各有一份。但是从我下面的打印结果来看指向的地址不太一样,不是很清楚真正的COM对象是怎么实现的。留着以后再研究吧。

    示例程序。使用时会有assert dialog弹出来,直接点忽略就行了。

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class  IUnknown
     5 {
     6 public:
     7     virtual long  QueryInterface(  long riid, void * * ppvObject) = 0;
     8     virtual long  AddRef( void) = 0;
     9     virtual long  Release( void) = 0;
    10 };
    11 
    12 class  IMyMath :  public IUnknown
    13 {
    14 public:
    15     virtual long Add(long n1, long n2, long* pVal) = 0;
    16 };
    17 
    18 class  IStr :  public IUnknown
    19 {
    20 public:
    21     virtual long Cat(char* _Dest, const char* _Source) = 0;
    22 };
    23 
    24 class CMyTest: public IMyMath, public IStr
    25 {
    26 public:
    27     long  QueryInterface(  long riid, void * * ppvObject) { cout<<"QueryInterface"<<endl; return 1;}
    28     long  AddRef( void) { cout<<"AddRef"<<endl; return 1;}
    29     long  Release( void) { cout<<"Release"<<endl; return 1;}
    30 
    31     long Add(long n1, long n2, long* pVal) { cout<<"Add"<<endl; return 1;}
    32     long Cat(char* _Dest, const char* _Source){ cout<<"Cat"<<endl; return 1;}
    33 };
    34 
    35 typedef long  (*QueryInterfaceType)(  long riid, void * * ppvObject);
    36 typedef long  (*AddRefType)( void);
    37 typedef long  (*ReleaseType)( void);
    38 
    39 typedef long  (CMyTest::*QueryInterfaceClassType)(  long riid, void * * ppvObject);
    40 
    41 void main()
    42 {
    43     CMyTest * pTest = new CMyTest;
    44     //pTest->AddRef();
    45 
    46     int* pFirst = (int*)( *(int*)(pTest));
    47 
    48     cout<<"IMyMath virtual table call"<<endl;
    49     for(int i=0; i<4; i++)
    50     {
    51         ((QueryInterfaceType)(*(pFirst+i)))(0, NULL);
    52         cout<<int((QueryInterfaceType)(*(pFirst+i)))<<endl;
    53     }
    54 
    55     cout<<endl<<"--------------------------------------------------"<<endl<<endl;
    56 
    57     cout<<"IStr virtual table call"<<endl;
    58     for(int i=0; i<4; i++)
    59     {
    60         int* pFirst2 = (int*)( *((int*)(pTest)+1));
    61         ((QueryInterfaceType)(*(pFirst2+i)))(0, NULL);
    62         cout<<int((QueryInterfaceType)(*(pFirst2+i)))<<endl;
    63     }
    64 }

    后记:

    之前提出一个问题,IUnknown的三个函数地址在两个虚函数表里都各有一份,但是地址值打印出来不一样,用VS command prompt打印class layout如下图,下面的IStr的虚函数表里多了个this -= 4,这里的4是IStr与实际对象指针也就是this指针的偏移量。

     参考文章:

    http://bbs.csdn.net/topics/390223914

    http://blog.csdn.net/wxc1987821/article/details/5958325

  • 相关阅读:
    DevOps工具链
    内网穿透工具
    SVN无法检出项目
    IDEA安装插件
    实习过程中学到关于各版本操作系统的知识(2)
    实习过程中学到关于各版本操作系统的知识(1)
    lib1funcs.S(用于解决裸板实现 printf 中的问题: undefined reference to `__aeabi_uidivmod' 和 undefined reference to `__aeabi_uidiv')
    交叉编译工具参数笔记
    vim 源码安装
    Git clone 下载慢解决方案
  • 原文地址:https://www.cnblogs.com/dirichlet/p/3236322.html
Copyright © 2020-2023  润新知