`
h_rain
  • 浏览: 121616 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
文章分类
社区版块
存档分类
最新评论

深入分析D语言接口与COM接口的关系

阅读更多
    前两天为了解决dxpcom项目中遇到的xpcom接口兼容性问题,看了一下DMD编译器的源码,对D的接口有了一些了解,现在总结出来,备忘。

    D中有了专门用于标识接口的关键字interface,而不用象C++中使用抽象类来代替。
interface ITest
{
int test();
}

class ITest
{
int test()=0;
}


    而D中的接口与C++中的接口不同之处是,D中的接口仍然含有ClassInfo,存放在虚表的0项上。

    从DMD的源码中可以得知,D中的类,接口都在虚表的0项上保存了ClassInfo指针。
    这样,D中的接口是无法与C++接口兼容的,则D就无法调用Windows的COM对象,至少是无法“优雅”的调用(仍然可以使用struct进行二进制兼容代替)。

    为了解决这个问题,DMD就需要能够表示出与C++兼容的COM接口,即需要一个虚表是"干净"的接口。又由于,从一个COM接口继承的接口仍然是一个COM接口,而COM模型的实现上又恰好定义了一个“IUnknown”根接口(COM体系中的所有的接口都是继承了IUnknown)。

    所以,出于简单实现的原则,DMD区分一个接口是D接口还是COM接口,关键就是判断这个接口是不是叫做IUnknown,以及这个接口是否继承自IUnknown,虽然接口都是通过Interface关键字声明。更有趣的是,DMD仅仅判断接口的名字是否为"IUnknown"而根本不管接口中的方法如何定义。

    以上所述内容在进行Windows COM编程时,几乎不会被察觉,因为Windows的所有接口都是继承自IUnknown,只要正常使用就可以了。

    而在进行Mozilla xpcom编程的时候,xpcom的根接口叫做ISupports,DMD根本就不会认为这是需要编译为C++兼容的COM接口,而仍然会将虚表的0项进行保留,结果给使用者造成了虚表指针偏移了的印象。

    基于D的这个识别COM接口的方式,在dxpcom项目中,qiezi使用了别名的方式进行了变换,既将dxpcom项目中的所有的接口名称进行了优雅的统一,又能够使DMD生成正确的COM接口:
extern(Windows)
interface IUnknown {
  static const char[] IID_STR = NS_ISUPPORTS_IID_STR;
  static const nsIID IID = NS_ISUPPORTS_IID;

  /* void QueryInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
  nsresult QueryInterface(nsIID * uuid, void * *result);

  /* [noscript, notxpcom] nsrefcnt AddRef (); */
  nsrefcnt AddRef();

  /* [noscript, notxpcom] nsrefcnt Release (); */
  nsrefcnt Release();

}

alias IUnknown nsISupports;


   这个现象同时也很好的说明了,D中的别名(alias)在符号的处理方面仅仅是一个符号的替换,同C/C++中的#define的作用相同。

    下面的两段代码就能很好的诠释本文的内容(感谢qiezi提供)

    代码一,无法通过运行期断言,因为接口IInterface仍然为标准D接口,虚表的0项为ClassInfo指针无法被显示的调用,在执行的结果中就表现为虚表进行了偏移。
extern(Windows):   
int test1(IInterface p)   
{   
    return 1;   
}   
  
int test2(IInterface p)   
{   
    return 2;   
}   
  
int test3(IInterface p)   
{   
    return 3;   
}   
  
struct InterfaceVtbl   
{   
extern(Windows):   
    int function(IInterface) test1;   
    int function(IInterface) test2;   
    int function(IInterface) test3;   
}   
  
struct Interface   
{   
    InterfaceVtbl* vtbl;   
  
    InterfaceVtbl vtbl_;   
  
    static Interface opCall()   
    {   
        Interface res;   
        res.vtbl_.test1 = &test1;   
        res.vtbl_.test2 = &test2;   
        res.vtbl_.test3 = &test3;   
        res.vtbl = &res.vtbl_;   
        return res;   
    }   
}   
  
interface IInterface   
{   
    int test1();   
    int test2();   
    int test3();   
}   
  
extern (D):   
  
void main()   
{   
    Interface i = Interface();   
    assert(i.vtbl.test1(cast(IInterface)&i) == 1);   
    assert(i.vtbl.test2(cast(IInterface)&i) == 2);   
    assert(i.vtbl.test3(cast(IInterface)&i) == 3);   
  
    IInterface ii = cast(IInterface)&i;   
    assert(ii.test1() == 1);   
    assert(ii.test2() == 2);   
    assert(ii.test3() == 3);   
}


    代码二,与代码一的结构完全一致,却能够通过运行时断言的检查。唯一的不同仅仅是IInterface的名字换成了IUnknown!!
extern(Windows):   
int test1(IUnknown p)   
{   
    return 1;   
}   
  
int test2(IUnknown p)   
{   
    return 2;   
}   
  
int test3(IUnknown p)   
{   
    return 3;   
}   
  
struct InterfaceVtbl   
{   
extern(Windows):   
    int function(IUnknown) test1;   
    int function(IUnknown) test2;   
    int function(IUnknown) test3;   
}   
  
struct Interface   
{   
    InterfaceVtbl* vtbl;   
  
    InterfaceVtbl vtbl_;   
  
    static Interface opCall()   
    {   
        Interface res;   
        res.vtbl_.test1 = &test1;   
        res.vtbl_.test2 = &test2;   
        res.vtbl_.test3 = &test3;   
        res.vtbl = &res.vtbl_;   
        return res;   
    }   
}   
  
interface IUnknown   
{   
    int test1();   
    int test2();   
    int test3();   
}   
  
extern (D):   
  
void main()   
{   
    Interface i = Interface();   
    assert(i.vtbl.test1(cast(IUnknown)&i) == 1);   
    assert(i.vtbl.test2(cast(IUnknown)&i) == 2);   
    assert(i.vtbl.test3(cast(IUnknown)&i) == 3);   
  
    IUnknown ii = cast(IUnknown)&i;   
    assert(ii.test1() == 1);   
    assert(ii.test2() == 2);   
    assert(ii.test3() == 3);   
}


    另外需要说明的是extern(D),extern(Windows),extern(Pascal)等特征,只是用来描述函数的调用约定,与接口的类型无关。
    一句话:D中的类与标准D接口都有ClassInfo在虚表的0项上,而COM接口的虚表是干净的;而将一个接口声明为COM接口的方式为:将这个接口命名为IUnknown或继承自IUnknown。
分享到:
评论
5 楼 tomqyp 2007-10-05  
收藏~
4 楼 ideage 2007-04-23  
不错!好文章!
3 楼 qiezi 2007-04-23  
原以为要Hack DMD的,现在省了不少事。
2 楼 player7 2007-04-23  
不错,好方法.  这种重要的东西应该专门建文档保存呀
1 楼 oldrev 2007-04-22  
nice article!

相关推荐

    D语言中文文档 D语言中文文档

    7. **元编程**:D语言的元编程能力非常强大,允许在编译时进行代码生成和分析,大大扩展了语言的灵活性。 8. **模块化**:D语言的模块系统使得代码组织清晰,便于维护和重用。每个源文件都可以视为一个独立的模块,...

    java包与接口实验报告

    ### Java包与接口实验报告知识点总结 #### 一、Java包的作用及结构 - **包的概念**:在Java中,包是一种将相关的类和接口组织在一起的方式,它可以帮助开发者更好地管理类库,避免命名冲突,并控制类之间的可见性...

    D语言操作Sqlite

    在这个"D语言操作Sqlite"的主题中,我们可以深入探讨以下几个关键知识点: 1. **D语言基础**:D语言由Walter Bright创建,具有C/C++语法的相似性,但提供了更多现代编程语言的特性,如垃圾回收、模板元编程、自动...

    D语言编程参考手册

    通过对这个样例的分析,可以深入了解D语言的基本语法和编程习惯。 #### 四、D语言在Win32平台下的应用 - **调用约定**:在Win32平台上编写D语言程序时,需要了解不同的调用约定,如C调用约定和标准调用约定。 - **...

    D语言操作Excel

    首先,要使用D语言操作Excel,你需要了解如何与Microsoft Office的COM接口进行交互。COM(Component Object Model)是一种允许不同应用程序之间共享数据和服务的技术。在D语言中,你可以使用`std.com`库来创建和操作...

    微型计算机原理与接口技术第四版课后习题答案

    《微型计算机原理与接口技术》是一本深入探讨计算机硬件与接口技术的专业教材,由周荷琴编著,由中国科学技术大学出版社出版。这本书旨在帮助学生和专业人士理解计算机内部工作原理,掌握微处理器、存储系统、输入...

    微机原理与接口技术.pdf

    《微机原理与接口技术》是一门深入探讨微型计算机系统结构、工作原理及接口技术的课程。这门课程是计算机科学和技术、电子信息工程等相关专业的重要基础课,它为学生提供了理解计算机硬件与软件交互的基础,有助于...

    《微机原理与接口技术》 学习感想

    在学习《微机原理与接口技术》这门课程的过程中,我深感其复杂性和挑战性。初接触时,面对诸多专业术语和理论问题,确实感到困惑。然而,随着时间的推移,我逐渐找到了学习的脉络。理解微机的整机概念是突破难点的...

    PIC16F87X单片机实用软件与接口技术-汇编语言及其应用

    根据提供的标题“PIC16F87X单片机实用软件与接口技术-汇编语言及其应用”以及描述,我们可以推断出这份资料主要聚焦于介绍如何在PIC16F87X系列单片机上使用汇编语言进行编程,并探讨了相关的软件工具和技术。...

    单片机原理与接口技术教程 习题答案

    最后,“单片机原理与接口技术[电子教案]”是教学辅助材料,通常包含课程大纲、讲义、实例分析等内容,教师和学生都可以从中获取更深入的教学指导和学习资源。 通过全面学习这个教程,不仅可以掌握单片机的基本工作...

    单片机原理及接口技术课后习题答案

    接口技术涉及单片机如何与各种外部设备连接,如串行通信接口(UART)、并行接口(如GPIO)、A/D转换器、D/A转换器等。掌握这些接口的设计和应用,可以扩展单片机的功能,实现复杂系统。 七、课程习题解答 书中课后...

    D_语言_2.0_编程参考手册

    D语言是一种现代的系统级编程语言,兼顾了高性能与高生产力,广泛应用于游戏开发、系统软件、网络应用等领域。 在D语言2.0中,语法简洁明了,支持面向对象、函数式以及过程式编程,同时具备C++的高效性和Python的...

    tibco ems C 语言接口说明

    ### TIBCO Enterprise Message Service (EMS) C 语言接口说明 #### 一、引言 TIBCO Enterprise Message Service(TIBCO EMS)是TIBCO Software Inc.提供的一款高性能消息中间件产品,用于实现分布式应用程序之间的...

    微机原理与接口课设

    【微机原理与接口技术课设】是一门深入学习计算机硬件与软件交互的课程,它涵盖了微处理器的工作原理、汇编语言编程、I/O接口设计等多个核心知识点。在这个课设中,学生通常需要通过实际操作来理解并应用这些理论...

    《汇编语言与接口技术》复习提纲.(推荐文档).doc

    《汇编语言与接口技术》复习提纲涵盖了汇编语言的基本知识、程序设计、DOS内部调用以及接口技术的相关内容。...通过深入学习和练习这些知识点,可以为汇编语言与接口技术的考试或实际项目开发做好充分准备。

    微机接口 课程完整课件

    4. **中断系统**:深入分析中断请求、中断响应和中断处理过程,以及中断向量表的作用。探讨中断的分类,如可屏蔽中断和不可屏蔽中断,以及中断优先级。 5. **定时器/计数器**:讲述定时器和计数器的工作原理,以及...

    单片机原理及其接口技术(第3版).rar

    书中会介绍并行接口、串行接口(如UART、SPI、I2C)、A/D转换器和D/A转换器等常见接口的设计与应用,以及如何通过编程控制这些接口实现数据传输。 此外,书中还涵盖了单片机程序设计,包括汇编语言和C语言编程。...

Global site tag (gtag.js) - Google Analytics