C++ COM编程之QueryInterface函数(二)

前言

在COM编程——认识组件中也总结了,COM是一个说明如何建立可动态互变组件的规范,它提供了为保证能够互操作,客户和组件应遵循的一些标准。而在实现和使用QueryInterface时,就需要去遵守一些规则,只有遵守了这些规则,才能是一个正确的COM组件;只有了解了这些规则,才能会真正的了解COM开发。

QueryInterface的实现规则

实现QueryInterface需要遵从以下五条规则:

1.QueryInterface总是返回同一IUnknown指针

组件的实例只有一个IUnknown接口。因为当查询组件实例的IUnknown接口时,不论通过哪个接口,所得到的均将是同一指针值。为确定两个接口是否指向同一个组件,可以通过这两个接口查询IUnknown接口,然后将返回值进行比较。

这条规则是非常重要的,如果QueryInterface的实现不遵循这条规则的话,则将没法决定两个接口是否指向同一组件;

2.如果客户曾经获取过某个接口,那么它将总能获得该接口

这条规则限定了对于一个组件实例,它的QueryInterface的不变性;你可以想象,如果组件实例的接口集不是固定的,客户将无法通过编程的方法来决定一个组件到底具有一些什么样的功能;客户就会对你的COM组件失去耐心,你的COM组件都没有人去使用了,这还有什么意义。

3.客户可以再次获取已经拥有的接口

如果客户拥有一个IX接口,则可以通过它来再次查询IX接口指针,并且一定可以成功的。通过自己查询自己,听起来多少有点奇怪,但是这是必须可以的。

4.客户可以从任何接口返回到起始接口

如果客户拥有一个IX接口指针,并成功地使用它来查询了一个IY接口,那么它将可以使用这个IY接口来查询一个IX接口,这条规则在实际的项目开发时很有用。

5.如果能够从某接口获取某特定接口,则从任意接口都将能获取此接口

如果能够从某个组件获取某特定接口,那么客户将可以通过此组件所支持的任意接口获取此接口。例如:如果可以通过接口IX得到接口IY,通过IY可以得到IZ,那么通过IX也将可以得到IZ。这条规则使得QueryInterface是可用的。

综上所有规则,其内在的重点在于不管组件实现了多少个接口,组件都只实现了一个QueryInterface,所以,在所有的接口的vtbl中,对应的QueryInterface都是组件实现的QueryInterface的地址,所有接口指针调用QueryInterface进行查询时,都是调用的同一个QueryInterface,所以,这就满足了上述的规则。大家在阅读上面的这些规则时,难免会有些无所谓的感觉,觉得都是文字,很枯燥,我开始的时候也是这样的;就是因为如此,在实际的开发中,吃过不少的苦头,所以,今天又在这里把这些规则重新的整理一遍,希望大家不要在实际的项目中栽了跟头再回来寻找原因,何不防范于未然呢?

添加新的接口

以前的博文也总结过了,COM中接口是不会发生变化的。当组件发布一个接口并被某个客户使用之后,此接口将决不会发生任何变化,而将永远保持不变。这里说的不变,具体是什么意思呢?由于每一个接口都有一个唯一对应的接口标识符IID。一般情况下,我们不会改变接口,而可以建立一个新接口并为之指定一个新的IID。当QueryInterface接收到对老的IID的查询时,它将返回老的接口;而当它收到对新的IID的查询时,它将返回新的接口。对于QueryInterface而言,一个IID就是一个接口。

所以同某个IID相应的接口将绝不会发生变化。新接口可以继承老的接口,它也可以同老接口完全不同。由于老的接口仍然保持不变,已有客户的运行将不会受到任何影响。而新客户则可以自行决定是使用老接口还是新接口,因它可以自由决定到底是查询哪个接口。

新接口命名

虽然每个人的命名规则,每个公司命名规则都是要求不同的,但是对于COM接口的命名大体上都是一致的,例如:原来的接口名为IX,则新的接口名为IX2,而不是IXEx之类的。我经历了这么多的项目,写过、也调用过很多的COM组件,基本都是遵循的这个规则,即在老名称的后面加上一个数字。

总结

这篇文章总结的是理论,让那些不喜欢理论的人会有点失望。但是,道理就是那样的,没有理论作为基础的实践,都是乱搞。做什么事情,都要有一定的理论基础,所以,我通过了两篇博文,对QueryInterface进行详细的总结。希望对大家有一定的帮助,最后,也希望大家提出你的想法和我分享。我坚信,交流是一种非常给力的学习方法。

(0)

相关推荐

  • C++ COM编程之QueryInterface函数(一)

    前言 组件对外公布的是接口:一个组件可以实现多个接口,也就是说可以对外公布多个接口,之前也总结过了,你很少会100%的去完全了解一个组件的所有接口,就像你去学习编程一样,你几乎不可能去成为编程中的全才.那么,既然我们不能去完全的了解一个组件提供的所有接口,那么我们在实际开发中,如何去判断一个组件是否提供对应的接口呢?看文档?是的,是个好主意,在文档的海洋,找到一个知识点,真的很难,浪费时间和精力:其实,组件本身就提供对自己查询的一个接口,让客户去询问组件,问它是否支持某个接口,在经过多次的这种询

  • C++ COM编程之QueryInterface函数(二)

    前言 在COM编程--认识组件中也总结了,COM是一个说明如何建立可动态互变组件的规范,它提供了为保证能够互操作,客户和组件应遵循的一些标准.而在实现和使用QueryInterface时,就需要去遵守一些规则,只有遵守了这些规则,才能是一个正确的COM组件:只有了解了这些规则,才能会真正的了解COM开发. QueryInterface的实现规则 实现QueryInterface需要遵从以下五条规则: 1.QueryInterface总是返回同一IUnknown指针 组件的实例只有一个IUnkno

  • socket编程之bind()函数使用示例详解

    目录 正文 端口号具体是怎么绑定 老代码 端口被占用的问题解决 正文 当你创建了socket之后,你会想要把这个socket和你本机上的某个端口号(port)进行关联. 端口号是内核用来确认将收到的数据包交给哪个具体进程的socket descriptor的依据. 通常在写服务端程序的时候我们才需要进行关联,客户端程序不需要我们手动绑定端口,直接connect()就好了. 端口号具体是怎么绑定 #include <sys/types.h> #include <sys/socket.h&g

  • Linux服务器编程之utime()函数修改文件存取时间

    C语言utime()函数:修改文件的存取时间和更改时间 头文件: #include <sys/types.h> #include <utime.h> 定义函数: int utime(const char * filename, struct utimbuf * buf); 函数说明:utime()用来修改参数filename 文件所属的inode 存取时间.结构utimbuf 定义如下: struct utimbuf { time_t actime; time_t modtime;

  • linux编程之pipe()函数详解

    管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次都需要提供两个文件描述符来操作管道.其中一个对管道进行写操作,另一个对管道进行读操作.对管道的读写与一般的IO系统函数一致,使用write()函数写入数据,使用read()读出数据. #include<unistd.h> int pipe(int filedes[2]); 返回值:成功,返回0,否则返回-1.参数数组包含pipe使用的两个文件的描述符.fd[0]:读管道,fd[

  • Python编程之Re模块下的函数介绍

    re模块下的函数 compile(pattern):创建模式对象 import re pat=re.compile('A') m=pat.search('CBA') #等价于 re.search('A','CBA') print m <_sre.SRE_Match object at 0x9d690c8> #匹配到了,返回MatchObject(True) m=pat.search('CBD') print m None #没有匹配到,返回None(False) search(pattern,

  • python 编程之twisted详解及简单实例

    python 编程之twisted详解 前言: 我不擅长写socket代码.一是用c写起来比较麻烦,二是自己平时也没有这方面的需求.等到自己真正想了解的时候,才发现自己在这方面确实有需要改进的地方.最近由于项目的原因需要写一些Python代码,才发现在python下面开发socket是一件多么爽的事情. 对于大多数socket来说,用户其实只要关注三个事件就可以了.这分别是创建.删除.和收发数据.python中的twisted库正好可以帮助我们完成这么一个目标,实用起来也不麻烦.下面的代码来自t

  • Python网络编程之ZeroMQ知识总结

    一.ZeroMQ概述 ZeroMQ(又名ØMQ,MQ,或zmq)像一个可嵌入的网络库,但其作用就像一个并发框架. ZeroMQ类似于标准Berkeley套接字,其提供了各种传输工具,如进程内.进程间.TCP和组播中进行原子消息传送的套接字 可以使用各种模式实现N对N的套接字连接,这些模式包括:发布-订阅.任务分配.请求-应答. ZeroMQ的速度足够快,因此可充当集群产品的结构. ZeroMQ的异步I/O模型提供了可扩展的多核应用程序,用异步消息来处理任务 ZeroMQ核心由C语言编写,支持C.

  • Java并发编程之LockSupport类详解

    一.LockSupport类的属性 private static final sun.misc.Unsafe UNSAFE; // 表示内存偏移地址 private static final long parkBlockerOffset; // 表示内存偏移地址 private static final long SEED; // 表示内存偏移地址 private static final long PROBE; // 表示内存偏移地址 private static final long SEC

  • Python多线程编程之threading模块详解

    一.介绍 线程是什么?线程有啥用?线程和进程的区别是什么? 线程是操作系统能够进行运算调度的最小单位.被包含在进程中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 二.Python如何创建线程 2.1 方法一: 创建Thread对象 步骤: 1.目标函数 2.实例化Thread对象 3.调用start()方法 import threading # 目标函数1 def fun1(num): for i in range(

随机推荐