MIDL 和 MkTypLib 之间的差异

注意

Mktyplib.exe工具已过时。 请改用 MIDL 编译器。

 

有几个关键方面,MIDL 编译器与 MkTypLib 不同。 之所以出现这些差异,是因为 MIDL 更倾向于 C 语法,而不是 MkTypLib。

一般情况下,需要在 IDL 文件中使用 MIDL 语法。 但是,如果需要编译现有的 ODL 文件,或以其他方式保持与 MkTypLib 的兼容性,请使用 /mktyplib203 MIDL 编译器选项强制 MIDL 的行为类似于 Mkktyplib.exe 版本 2.03。 (这是 MkTypLib 工具的最后一个版本。) 具体而言, /mktyplib203 选项解决了这些差异:

  • 复杂数据类型的 typedef 语法

    在 MkTypLib 中,以下两个定义都会为类型库中的“this_struct”生成TKIND_RECORD。 标记“struct_tag”是可选的,如果使用,则不会显示在类型库中。

    typedef struct struct_tag { ... } this_struct;
    typedef struct { ... } that_struct;
    

    如果缺少可选标记,MIDL 将生成该标记,从而有效地将标记添加到用户提供的定义中。 由于第一个定义具有标记,因此 MIDL 将为“this_struct”生成一个TKIND_RECORD,并为“this_struct”生成一个TKIND_ALIAS, (将“this_struct”定义为“struct_tag”) 的别名。 由于第二个定义中缺少标记,因此 MIDL 将为 MIDL 内部的乱写名称生成一个TKIND_RECORD,该名称对用户没有意义,并且为“that_struct”生成TKIND_ALIAS。

    这对类型库浏览器具有潜在影响,这些浏览器只是在其用户界面中显示记录的名称。 如果预期TKIND_RECORD具有真实名称,则用户界面中可能会出现无法识别的名称。 此行为也适用于 联合枚举 定义,MIDL 编译器分别生成TKIND_UNIONs和TKIND_ENUMs。

    MIDL 还允许 C 样式 的结构联合枚举 定义。 例如,以下定义在 MIDL 中是合法的:

    struct my_struct { ... };
    typedef struct my_struct your_struct;
    
  • Boolean 数据类型

    在 MkTypLib 中, 布尔 基类型和 MkTypLib 数据类型 BOOL 等同于VT_BOOL,它映射到VARIANT_BOOL,定义为 short。 在 MIDL 中, 布尔 基类型等效于 VT_UI1(定义为 无符号字符),BOOL 数据类型定义为 long。 如果在同一文件中混合使用 IDL 语法和 ODL 语法,同时仍尝试保持与 MkTypLib 的兼容性,这会导致困难。 由于数据类型大小不同,因此封送代码与类型信息中描述的代码不匹配。 如果要在类型库中VT_BOOL,则应使用 VARIANT_BOOL 数据类型。

  • 头文件中的 GUID 定义

    在 MkTypLib 中,GUID 在头文件中定义,其中包含一个宏,该宏可按条件编译以生成 GUID 预定义或实例化 GUID。 MIDL 通常将 GUID 预定义放在其生成的头文件中,而 GUID 实例化仅放在 由 /iid 开关生成的文件中。

使用 /mktyplib203 开关无法解决以下行为差异:

  • 事例敏感性

    MIDL 区分大小写,OLE 自动化不区分大小写。

  • 枚举声明中符号的范围

    在 MkTypLib 中,枚举中的符号范围是局部的。 在 MIDL 中,枚举中的符号范围是全局的,就像在 C 中一样。例如,以下代码将在 MkTypLib 中编译,但在 MIDL 中生成重复的名称错误:

    typedef struct { ... } a;
    enum {a=1, b=2, c=3};
    
  • 公共属性的范围

    如果将 公共 属性应用于接口块,MkTypLib 会将该接口块中的每个 typedef 视为公共。 MIDL 要求将 公共 属性显式应用于需要公共的那些 typedef。

  • Importlib 搜索顺序

    如果导入多个类型库,并且这些库包含重复引用,则 MkTypLib 将使用找到的第一个引用来解决此问题。 MIDL 将使用找到的最后一个引用。 例如,给定以下 ODL 语法,如果使用 MkTypLib 进行编译,库 C 将使用库 A 中的 MOO typedef,如果使用 MIDL 编译,则使用库 B 中的 MOO typedef:

    [...]library A
    {
        typedef struct tagMOO
        {...}MOO
    }
    
    [...]library B
    {
        typedef struct tagMOO
        {...} MOO
    }
    
    [...]library C
    {
        importlib (A.TLB)
        importlib (B.TLB)
        typedef struct tagBAA
        {MOO y;}BAA
    }
    

    适当的解决方法是使用正确的导入库名称限定每个此类引用,如下所示:

    typedef struct tagBAA
        {A.MOO y;}BAA
    
  • 无法识别 VOID 数据类型

    MIDL 识别 C 语言 void 数据类型,并且无法识别 OLE 自动化 VOID 数据类型。 如果有使用 VOID 的 ODL 文件,请将此定义放在文件顶部:

#define VOID void“”

  • 指数表示法

    MIDL 要求用指数表示法表示的值包含在引号内。 例如,“-2.5E+3”

  • LCID 值和常量

    通常,在分析文件时,MIDL 不会考虑 LCID。 若要强制对某个值执行此行为,或者在定义常量时需要使用特定于区域设置的表示法,请将该值或常量括在引号中。

有关详细信息,请参阅 /mktyplib203/iid封送 OLE 数据类型