COM接口定义和标识
《COM原理与应用》笔记
从技术上讲,接口是包含了一组函数的数据结构,客户程序用一个指向接口数据结构的指针来调用接口成员函数。如图2.2所示,接口指针实际指向另一个指针,第二个指针指向一组函数,称为接口函数表,接口函数表中每一项为4个字节长的函数指针,每个函数指针与对象的具体实现连接起来。通过这种方式,客户程序只要获得接口指针,就可以调用对象的实际功能。
接口函数表通常称为虚函数表(virtual function table,简称vtable),指向vtable的指针为pVtable。
对于一个接口来说,它的虚函数表vtable是确定的,因此接口的成员函数个数是不变的,而且成员函数的先后顺序也是不变的;对于每个成员函数来说,其参数和返回值也是确定的。在一个接口的定义中,所有这些信息都必须在二进制一级确定,不管什么语言,只要能支持这样的内存结构描述,就可以定义接口。
用C语言描述字典接口
struct IDictionaryVtbl;
struct IDictionary
{
IDictionaryVtbl *pVtbl;
};
struct IDictionaryVtbl
{
BOOL (*Initialize)(IDictionary *this);
BOOL (*LoadLibrary)(IDictionary *this, String);
BOOL (*InsertWord)(IDictionary *this, String, String);
void (*DeleteWord)(IDictionary *this, String);
BOOL (*LookupWord)(IDictionary *this, String, String *);
BOOL (*RestoreLibrary)(IDictionary *this, String);
void (*FreeLibrary)(IDictionary *this);
};
(1)每个接口成员函数的第一个参数为指向IDictionary的指针,这是因为接口本身并不独立使用,它必定存在于某个COM对象上,因此,该指针可以提供对象实例的属性信息,在被调用时,接口可以知道是对哪个COM对象在进行操作。所以,该this指针与C++类成员函数定义中隐藏的this指针非常类似。如果我们在一个应用系统中同时用到了两本字典,即存在两个字典对象,不同的字典对象其this指针不同。
(2)在接口成员函数中,字符串变量必须用Unicode字符指针,COM规范要求使用Unicode字符,而且COM库中提供的COM API函数也使用Unicode字符。所以,如果在组件程序内部用到了ANSI字符的话,应该对两种字符进行转换,操作系统或者C/C++编译库会提供这样的转换函数。
(3)不仅成员函数的参数类型是确定的,而且应该使用同样的函数调用方式。客户程序在调用成员函数之前,必须先把参数压入栈中,然后再进入成员函数,成员函数依次把参数从栈中取出,在函数返回之前或返回之后,必须恢复栈的当前位置,才能保证程序的正常运行。在Windows平台上有两种调用方式,分别为_cdecl和_stdcall(在有的编译器中称为pascal),采用_cdecl可以实现C语言中用到的函数可变参数的特性(例如printf函数),在这种调用方式下,由调用程序处理栈的恢复。由于大多数语言(除C/C++之外)都使用了_stdcall或pascal,而且大多数的系统API(支持可变参数的函数例外)也都使用这种调用方式,所以,COM规范也采用_stdcall和pascal,并且,所有的COM API函数也使用了_stdcall。当然,这不是绝对的,但必须保证调用方和被调用方使用一致的调用方式,如果接口成员函数使用了_cdecl,则C/C++之外的大多数语言就不能使用这样的接口,所以,除非要使用可变参数特性,否则就使用_stdcall。
(4)在C语言中,用这种结构只是描述了接口,并没有提供具体的实现,对于客户程序,它只需要这样的描述就可以调用COM对象的接口;而对于组件程序,基于这样的描述必须提供具体的实现过程,也就是说,如果一个COM对象实现了这个接口,则它所提供的接口指针IDictionary所指向的IDictionaryVtbl结构中,每个成员必须是有效的函数指针。
(5)从C语言的描述中我们可以看出,由于COM接口的这种二进制结构,只要一种编程语言能够支持“structure”或“record”类型,并且这种类型能够包含双重的指向函数指针表的成员,则它就可以支持接口的描述,从而可以用于编写COM组件或者使用COM组件。
---------------------------------------- 分割线 ----------------------------------------
COM接口也采用了全局唯一标识符,它被称为接口标识符(IID,interface identifier)。例如:
extern "C" const IID IID_IUnknown =
{ 0x00000000, 0x0000, 0x0000,
{ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }};
客户程序要使用接口,必须知道该接口的IID和接口提供的方法(接口成员函数)。
---------------------------------------- 分割线 ----------------------------------------
COM接口结构中的vtable与class的vtable(类的虚函数表)完全一致,因此,用class描述COM接口是最方便的手段。
用C++类重新定义IDictionary:
class IDictionary
{
virtual BOOL Initialize() = 0;
virtual BOOL LoadLibrary(String) = 0;
virtual BOOL InsertWord(String, String) = 0;
virtual void DeleteWord(String) = 0;
virtual BOOL LookupWord(String, String *) = 0;
virtual BOOL RestoreLibrary(String) = 0;
virtual void FreeLibrary() = 0;
};
class定义中隐藏了虚函数表vtable,每个成员函数隐藏了第一个参数this指针,this指针指向类的实例。图2.3显示了类IDictionary的内存结构:
类IDictionary使用了纯虚函数,因为接口只是一种描述,并不提供具体的实现过程。如果COM对象要实现接口IDictionary,则COM对象必须以某种方式把它自身与类IDictionary联系起来,然后将IDictionary的指针暴露给客户程序。
当客户程序获得了COM对象的接口指针pIDictionary之后,就可以调用接口的成员函数,例如:
pIDictionary->LoadLibrary("Eng_Ch.dict");
如果使用C语言的struct IDictionary,则应该这样:
pIDictionary->pVtbl->LoadLibrary(pIDictionary, "Eng_Ch.dict");
由C++语言class的特性可知上述两种调用完全等价。
---------------------------------------- 分割线 ----------------------------------------
用IDL描述接口IDictionary
interface IDictionary
{
HRESULT Initialize();
HRESULT LoadLibrary([in]string);
HRESULT InsertWord([in]string, [in]string);
HRESULT DeleteWord([in]string);
HRESULT LookupWord([in]string, [out]string *);
HRESULT RestoreLibrary([in]string);
HRESULT FreeLibrary();
};
COM接口定义和标识相关推荐
- 我的编码习惯 —— API 接口定义
工作中,少不了要定义各种接口,系统集成要定义接口,前后台掉调用也要定义接口.接口定义一定程度上能反应程序员的编程功底.列举一下工作中我发现大家容易出现的问题: 1. 返回格式不统一 同一个接口,有时候 ...
- usb接口定义引脚说明_PerfDogService使用说明
令牌申请教程:https://bbs.perfdog.qq.com/article-detail.html?id=55安装包下载:https://perfdog.qq.com/sdk一. 概述 Per ...
- ADAS自动驾驶辅助系统通讯协议「ADASIS Protocol」接口定义解析(二)详细
「ADASIS Protocol Introduction」 --信号接口解析 本文来自微信公众号:[阿波兹得][续]ADASIS Protocol介绍 (2) 信号解析https://mp.weix ...
- 接口定义语言IDL,COM
接口定义语言MIDL:Microsoft Interface Definition Language. MIDL是定义COM接口的说明性语言.是一种独立于语言的接口定义方式,从而产生RPC(Remot ...
- SAP工具箱 自动生成发出接口程序(二 接口定义表)
点击蓝字 关注我们 一 前言 前文介绍了发出接口程序的执行原理及怎么自动生成发出接口程序. 详见链接 无峰,公众号:ABAP 技巧与实战SAP工具箱 自动生成发出接口程序(一) 本文主要介绍生成发出接 ...
- 接口定义,常见的接口,常见的接口请求方式,put请求和patch请求的区别
接口定义:应用程序编程接口,指前后端数据交互的一套标准,包括软件内部之间的接口,硬件之间的接口或者是软件对外的接口. 常见的接口类型: 1,Webservice接口,主要用于服务端的接 ...
- Thrift的接口定义语言IDL
Thrift的IDL可以使用下面的语法来定义描述接口. 1 基本类型 bool:布尔值,true 或 false byte:8 位有符号整数 i16:16 位有符号整数 i32:32 位有符号整数 i ...
- 【C 语言】字符串模型 ( strstr-while 模型 | 抽象函数模型 | 业务子函数接口定义要点 | 形参指针间接赋值 | 返回值状态 | 形参指针处理 | 形参指针判空 | 形参返回值 )
文章目录 前言 一.业务子函数接口定义要点 二.完整代码示例 前言 字符串开发模型 : strstr-while/do-while 模型 : 在 字符串 中 查找 子串特征 ; 两头堵模型 : 两个指 ...
- JDK中提供的实现——通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例
JDK中提供的实现 在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例. 1 ...
最新文章
- pgsql 前10条_白沙湾南片区11条新建道路最新进度及建成时间,已建成一条!还有一条将通车...
- mysql之慢查询详解,mysqldumpslow的使用
- 天津科技大学计算机基础,天津科技大学大学计算机基础样卷
- matla工具箱 SerialLink 的一些最近发现的功能
- 随想录(人脸检测之dlib)
- android高德地图自动缩放比例,【Android】高德地图 缩放级别及像素以及地图上的点转化成屏幕上的点...
- 世界读书日,给你们送大福利!
- 计算机组成原理华中科技大学秦磊华,计算机组成原理(华科)chap1
- win10 android10之后高通芯片 adb和fastboot驱动无法识别问题
- 主机安全加固终端安全管理
- java web实现markdown_editormd实现Markdown编辑器写文章功能
- pdf在线免费去水印 以及图片去水印 方法
- 【Gazebo入门教程】第四讲 场景建模/建筑编辑器
- 同步BUCK死区时间产生电路原理及仿真
- 从零开始开发一个全栈Web应用实录
- Unity3d 中创建实时视频聊天
- 云主机和电脑主机服务器有什么区别?
- error C2448 函数样式初始值设定项类似函数定义
- bzoj1758 [Wc2010]重建计划
- 星志远电商:拼多多头像如何保存?
热门文章
- IDEA反编译出整个jar包源码
- Android面试问答题
- NS版块可下载资源综合(updated 2007.12.12)--百思论坛
- 【网络研讨会】MongoDB Vs 效仿者:选择MongoDB的理由
- (贪心5.3.2)POJ 1505 Copying Books()
- Linux 压缩解压命令
- @media媒体查询——详解
- python语法与函数
- Oracle 数据库入门之----------------------多表查询
- 小世界网络邻接矩阵生成——python