IDL 文件剖析

这些示例 IDL 文件演示接口定义的基本构造。 内存分配、自定义封送和异步消息传送只是可以在自定义 COM 接口中实现的一些功能。 MIDL 属性用于定义 COM 接口。 有关实现接口和类型库(包括 MIDL 属性摘要)的详细信息,请参阅 MIDL 程序员指南和参考中的 接口定义和类型库。 有关所有 MIDL 属性、关键字和指令的完整参考,请参阅 MIDL 语言参考

Example.idl

以下示例 IDL 文件定义了两个 COM 接口。 在此 IDL 文件中,Midl.exe 将生成代理/存根和封送代码和头文件。 逐行剖析遵循该示例。

//
// Example.idl 
//
import "mydefs.h","unknwn.idl"; 
[
object,
uuid(a03d1420-b1ec-11d0-8c3a-00c04fc31d2f),
] interface IFace1 : IUnknown
{
HRESULT MethodA([in] short Bread, [out] BKFST * pBToast);
HRESULT MethodB([in, out] BKFST * pBPoptart);
};
 
[
object,
uuid(a03d1421-b1ec-11d0-8c3a-00c04fc31d2f),
pointer_default(unique)
] interface IFace2 : IUnknown
{
HRESULT MethodC([in] long Max,
                [in, max_is(Max)] BkfstStuff[ ],
                [out] long * pSize,
                [out, size_is( , *pSize)] BKFST ** ppBKFST);
}; 
 

此处使用 IDL 导入 语句引入头文件 Mydefs.h,其中包含用户定义的类型,以及 Unknwn.idl,其中包含从中派生 IUnknown的定义。

对象 属性将接口标识为对象接口,并指示 MIDL 编译器生成代理/存根代码,而不是 RPC 客户端和服务器存根。 对象接口方法必须具有 HRESULT的返回类型,以便基础 RPC 机制报告由于网络问题而未能完成的调用的错误。

uuid 属性指定接口标识符(IID)。 每个接口、类和类型库都必须使用自己的唯一标识符进行标识。 使用实用工具 Uuidgen.exe 为接口和其他组件生成一组唯一 ID。

接口 关键字定义接口名称。 所有对象接口必须直接或间接地从 IUnknown派生。

方向参数中的指定仅由调用方设置的参数。 out 参数指定传回调用方的数据。 在一个参数上使用这两个方向属性指定参数既用于将数据发送到方法,又将数据传回调用方。

pointer_default 属性指定除参数列表中包括的所有指针之外的所有指针的默认指针类型(唯一refptr)。 如果未指定默认类型,MIDL 假定单个指针 唯一。 但是,如果具有多个级别的指针,则必须显式指定默认指针类型,即使希望默认类型 唯一也是如此。

在前面的示例中,数组 BkfstStuff[ ] 是一个 一致性数组,其大小在运行时确定。 max_is 属性指定包含数组索引最大值的变量。

size_is 属性还用于指定数组的大小,或如前面的示例中所示,指定多个级别的指针。 在此示例中,无需事先知道将返回多少数据,即可进行调用。

Example2.idl

以下 IDL 示例(重复使用上一 IDL 示例中所述的接口)显示了为接口生成类型库信息的各种方法。

//
// Example2.idl
//

import "example.idl","oaidl.idl"; 

[
uuid(a03d1422-b1ec-11d0-8c3a-00c04fc31d2f),
helpstring("IFace3 interface"),
pointer_default(unique);
dual,
oleautomation
] 
interface IFace3 : IDispatch
{
   HRESULT MethodD([in] BSTR OrderIn,
                   [out, retval] * pTakeOut);
}; //end IFace3 def

[
uuid(a03d1423-b1ec-11d0-8c3a-00c04fc31d2f),
version(1.0),
helpstring("Example Type Library"),
] library ExampleLib
{
  importlib("stdole32.tlb");
  interface IFace3;
  [
  uuid(a03d1424-b1ec-11d0-8c3a-00c04fc31d2f),
  helpstring("Breakfast Component Class")
  ] coclass BkfstComponent
    {
    [default]interface IFace1;
    interfaceIFace2
    }; //end coclass def

[
uuid(a03d1424-b1ec-11d0-8c3a-00c04fc31d2f),
helpstring("IFace4 interface"),
pointer_default(unique);
dual,
oleautomation
] 
interface IFace4 : IDispatch
{
[propput] HRESULT MethodD([in] BSTR OrderIn);
[propget] HRESULT MethodE([out, retval] * pTakeOut);
}; //end IFace4 def
 
}; //end library def
 

helpstring 属性是可选的;可以使用它简要描述对象或提供状态行。 这些帮助字符串可通过对象浏览器进行读取,例如随 Microsoft Visual Basic 一起提供的帮助字符串。

IFace3 上的 属性创建一个接口,该接口既是调度接口,也是 COM 接口。 由于它派生自 IDispatch,因此双接口支持自动化,这是 oleautomation 属性所指定的内容。 IFace3 导入 Oaidl.idl 以获取 IDispatch的定义。

语句定义 ExampleLib 类型库,该库有自己的 uuidhelpstring版本 属性。

在类型库定义中,importlib 指令引入已编译的类型库。 所有类型库定义都应引入 Stdole32.tlb 中定义的基类型库。

此类型库定义演示了在类型库中包括接口的三种不同的方法。 IFace3 只是通过在库语句中引用它来包含它。

coclass 语句定义一个全新的组件类 BkfstComponent,其中包括两个以前定义的接口(IFace1 和 IFace2)。 默认属性将 IFace1 指定为默认接口。

IFace4 在库语句中介绍。 MethodD 上的 propput 属性指示该方法对同名属性执行设置作。 propget 属性指示该方法从与该方法同名的属性中检索信息。 MethodD 中的 retval 属性指定包含函数返回值的输出参数。