开始先说一句,学习com之前要学好c++ 对象模型。

QueryInterface的使用:

QueryInterface是IUnknown的一个成员函数,客户可以通过此函数来查询某个组件是否支持某个特定的接口。

QueryInterface成功返回一个指向此接口的指针。     错误返回一个错误代码。

HRESULT _stdcall QueryInterface(const IID& iid, void **ppv);

下面是一个QueryInterface的使用实例:(可知道相应的组件是否支持某个特定的接口)

void ceshi(IUnknown * pI)
{
IX* pIX = NULL;
HRESULT hr = pI->QueryInterface(IID_IX, (void**)&pIX);
if(SUCCEEDED(hr))
{
pIX->Fx();
}
}

我们查询pI 是否支持由IID_IX所标识的接口。

代码中主意的是   pIX需要初始化为NULL, 这是一种比较好的编程方法,在后面的实现中我们会看到  QueryInterface在失败时将把返回的接口指针置为NULL。

由于QueryInterface是由程序员而不是由系统实现的,因此某些组件可能并不会在查询失败时将此指针置为NULL。    为了安全,在程序中还是我们自己将其置为NULL比较好。

QueryInterface的实现:

他的实现需要完成的不过是根据某个给定的IID返回指向相应接口的指针。

若组件支持客户指定的接口,那么应返回S_OK 以及相应的指针。

若不支持,返回值应为: E_NOINTERFACE 并将相应的指针返回值置为NULL。

HRESULT _stdcall CA::QueryInterface(const IID& iid, void ** ppv)
{
if(iid == IID_IUnknown)
{
*ppv = static_cast<IX*>(this);
}else if(iid == IID_IX)
{
*ppv = static_cast<IX*>(this);
}else if(iid == IID_IY)
{
*ppv = static_cast<IY*>(this)
}else
{
*ppv = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppv)->AddRed();
return S_OK;
}

QueryInterface 的末尾调用AddRef实际上没有任何作用,后面讨论 AddRef;

QueryInterface的实现规则:

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

2.若客户曾经获取过某个接口,那么它将总能获取此接口。

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

4.客户可以返回到起始接口。

5.若能从某个接口获取某特定接口,那么可以从任意接口都将可以获取此接口。

QueryInterface定义了组件:

QueryInterface是COM最为重要的部分,因为一个组件实际上就是由QueryInterface定义了,组件所支持的接口集就是QueryInterface能够为之返回接口指针的那些接口。

这是由QueryInterface的实现决定的,而不是由实现组件的C++类决定的。

客户不知道QueryInterface的实现,他将无法知道一个组件所支持的所有接口。   客户了解组件所支持接口的唯一方法是进行查询。

COM类似于在某次社交聚会上同某人会面,而与对他们进行工作面试有很大不同,当进行工作面试时,被试者将提交一份介绍他情况的个人简历。这份简历类似于c++类的定义。而社交聚会上会面时,没有人会给对方提供个人简历。为了了解情况,必须询问。   这一点类似于COM组件。

新版本的处理:

Com中,接口是不会发生改变的,当组件发布一个接口并被某个客户使用之后,此接口将绝不会发生任何变化,而将永远保持不变。

每一个接口都有一个唯一的接口标识符IID,  一般情况下,我们不会改变接口,而可以建立一个新接口并为之指定一个新的IID。

当QueryInterface 接收到对老IID  的查询时,他将返回老接口,   而当他收到对新的IID的查询时,他将返回新的接口。

对QueryInterface 而言, 一个IID 就是一个接口。

新的接口可以继承老接口,他也可以同老接口完全不同。  由于老接口仍然保持不变,已有客户的运行将不会收到任何影响。

新客户可以自行决定是使用老接口还是新接口,因为他可以自由决定到底查询那个接口。

接口的IID  据定了它的版本,当客户获取某个接口时,由于不同版本的接口实际上是不同的接口,他们各自具有不同的ID,因此客户仍能取得正确的版本的接口。

我们何时需要建立一个新版本?

当改变下列条件中的任何一个时,就应该给新街口指定新的id。

1、接口中函数的数目;

2、接口中函数的顺序;

3、某个函数的参数;

4.、某个函数参数的顺序;

5、某个函数参数的类型;

6、函数可能的返回值;

7、函数返回值的类型;

8、函数参数的含义;

9、接口中函数的含义。

只要是所做的修改会导致已有客户的正常运行,就需要接口指定新的ID。

2013.8.4

jofranks 于南昌

【COM学习】之一、QueryInterface的更多相关文章

  1. Direct3D11学习:(三)Direct3D11初始化

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 做完一系列的准备工作之后,我们就正式进入Direct3D11的学习了.我们就从Direct3D11的初始化工作开 ...

  2. IRP IO_STACK_LOCATION 《寒江独钓》内核学习笔记(1)

    在学习内核过滤驱动的过程中,遇到了大量的涉及IRP操作的代码,这里有必要对IRP的数据结构和与之相关的API函数做一下笔记. 1. 相关阅读资料 <深入解析 windows 操作系统(第4版,中 ...

  3. COM学习笔记

    2015-10-22 10:24 在第八章学习Aggregation的时候搞晕了,所以就建了一个Workspace名为"COMAggregationDemo"来调试一下,使用的源码 ...

  4. com学习(五)——实现多接口

    从第五回开始到第七回,咱们用 ATL 写了一个简单的 COM 组件,之所以说简单,是因为在组件中,只实现了一个自定义(custom)的接口 IFun.当然如果想偷懒的话,我们可以把 200 个函数都加 ...

  5. C++内存管理学习笔记(7)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  6. COM学习(一)——COM基础思想

    概述 学习微软技术COM是绕不开的一道坎,最近做项目的时候发现有许多功能需要用到COM中的内容,虽然只是简单的使用COM中封装好的内容,但是许多代码仍然只知其然,不知其所以然,所以我决定从头开始好好学 ...

  7. CentOS 简单学习 firewalld的使用

    1. centos7 开始 使用firewalld 代替了 iptables 命令工具为 firewall-cmd 帮助信息非常长,简单放到文末 2. 简单使用 首先开启 httpd 一般都自带安装了 ...

  8. 《C#高级编程》学习笔记------什么是COM组件

    COM是Component Object Model (组件对象模型)的缩写. 用户需要什么样的软件产品?这是一个多选题,但高效,健壮是肯定会被选中的.作为一名软件开发人员如何做才能满足用户的需要呢? ...

  9. WinForm引用ActiveX组件,对Com组件的学习

    1.WinForm引用Adobe PDF Reader 工作中写WinForm程序经常会引用第三方的组件,包括引用Com组件,做了一个桌面程序需要展示PDF,看了些其它的开源组件对PDF的兼容性都不是 ...

随机推荐

  1. rest-简介

    一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...

  2. ASP.NET的WebConfig

    转:http://blog.csdn.net/q3498233/article/details/8137364 WebConfig 花了点时间整理了一下ASP.NET Web.config配置文件的基 ...

  3. java获取对象属性类型、属性名称、属性值 【转】

    /** * 根据属性名获取属性值 * */ private Object getFieldValueByName(String fieldName, Object o) { try { String ...

  4. 无法升级数据库....因为此版本的 SQL Server 不支持该数据库的非发布版本(539) 解决方案

    使用SQL2012附加一个数据库时报出了以下错误:“无法升级数据库....因为此版本的 SQL Server 不支持该数据库的非发布版本(539).不能打开与此版本的 sqlserver.exe 不兼 ...

  5. javascript 操作符类型隐性转换

    javascript 操作符类型隐性转换 (一).一元操作符只能操作一个值的操作符叫做一元操作符1.递增和递减操作符a. 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减1的操作 ...

  6. 【windows开发实现记事本程序——逻辑篇1】

    1. 主要内容 从本节开始介绍windows开发实现记事本程序的逻辑实现部分.本节的主要内容有以下3点: 1. 主窗口定义  -- 主要介绍记事本主界面窗口对应的窗口类及实现方案 2. RichEdi ...

  7. Android动画 fillAfter和fillBefore

    fillBefore是指动画结束时画面停留在此动画的第一帧; fillAfter是指动画结束是画面停留在此动画的最后一帧. java代码设置如下: /*****动画结束时,停留在最后一帧******* ...

  8. 深入浅出理解QTimeLine类

    网上找了下QTimeLIne类的介绍,要么就是代码一贴自己看去,要么就是说不到重点,正巧自己项目遇到这个类,在这里写一下,给需要的同学看下. 因为我最近需要有动画方面配合时间间隔触发QGraphics ...

  9. asp.net Server.HtmlEncode和HtmlDecode

    <html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">< ...

  10. C语言基础学习基本数据类型-字符专属的输入输出函数

    可以使用%c说明符以及scanf()和printf()函数来输入输出字符.现在我们将学习专门为面向字符而设计的一对函数:getchar()和putchar().getchar()函数没有参数,它返回来 ...