适用于 COM 和 .NET 的 C++ 属性

Microsoft 定义了一组 C++ 特性,可用于简化 COM 编程和 .NET Framework 公共语言运行时开发。 当你在源文件中包含特性时,编译器可使用提供程序 DLL 插入代码或修改生成的对象文件中的代码。 这些特性有助于创建 .idl 文件、接口、类型库和其他 COM 元素。 在集成开发环境 (IDE) 中,特性受到向导和“属性”窗口的支持。

虽然特性使你无需编写 COM 对象所需的一些详细编码,但需要具备 COM 基础知识的背景才能充分利用特性。

注意

如果要查找 C++ 标准特性,请参阅特性

特性用途

特性可在不破坏 C++ 经典结构的情况下,在当前无法实现的方向上扩展 C++。 特性允许提供程序(单独的 DLL)动态地扩展语言功能。 特性的主要目标是简化 COM 组件的创建,同时提高组件开发人员的工作效率。 特性可以应用于几乎任何 C++ 构造,例如类、数据成员或成员函数。 下面的内容重点介绍了这项新技术提供的优势:

  • 公开熟悉且简单的调用约定。

  • 使用插入的代码(与宏不同,它可被调试器识别)。

  • 允许从基类轻松派生,而无需繁琐的实现详细信息。

  • 将 COM 组件所需的大量 IDL 代码替换为一些简洁的特性。

例如,若要为泛型 ATL 类实现简单的事件接收器,可以将 event_receiver 特性应用于特定类,例如 CMyReceiver。 然后,Microsoft C++ 编译器将编译 event_receiver 特性,将正确的代码插入到对象文件中。

[event_receiver(com)]
class CMyReceiver
{
   void handler1(int i) { ... }
   void handler2(int i, float j) { ... }
}

然后,你可以设置 CMyReceiver 方法 handler1handler2 来处理来自事件源的事件(使用内部函数 __hook),该事件源可以使用 event_source 来创建。

特性的基本机制

可通过三种方法将特性插入项目中。 首先,可以手动将它们插入源代码中。 其次,可以使用项目中对象的属性网格进行插入。 最后,可以使用各种向导进行插入。 有关使用“属性”窗口和各种向导的详细信息,请参阅 Visual Studio 项目 - C++

与以前一样,生成项目时,编译器会分析每个 C++ 源文件,并生成一个对象文件。 但是,当编译器遇到特性时,会对其进行分析和语法验证。 然后,编译器会动态地调用特性提供程序,以插入代码或在编译时进行其他修改。 提供程序的实现因特性类型而异。 例如,ATL 相关特性是由 Atlprov.dll 实现的。

下图演示了编译器与特性提供程序之间的关系。

显示组件属性通信的关系图。

注意

特性的用法不会改变源文件的内容。 生成的特性代码唯一可见的时间是在调试会话期间。 此外,对于项目中的每个源文件,可以生成一个显示特性替换结果的文本文件。 有关此过程的详细信息,请参阅/Fx(合并注入的代码)调试注入的代码

与大多数 C++ 构造一样,特性具有一组可定义其正确用法的特征。 这称为特性的上下文,并在每个特性引用主题的特性上下文表中进行寻址。 例如,coclass 特性只能应用于现有类或结构,cpp_quote 特性则与之相反,它可以在 C++ 源文件中的任何位置插入。

生成特性化程序

将 Visual C++ 特性放入源代码后,你可能希望 Microsoft C++ 编译器为你生成类型库和 .idl 文件。 以下链接器选项可帮助你生成 .tlb 和 .idl 文件:

一些项目包含多个独立的 .idl 文件。 这些文件用于生成两个或更多个 .tlb 文件,并选择性地将它们绑定到资源块中。 Visual C++ 目前不支持此方案。

此外,Visual C++ 链接器会将所有与 IDL 相关的特性信息输出到单个 MIDL 文件。 没有办法从单个项目生成两个类型库。

特性上下文

可以使用四个基本字段来描述 C++ 特性:它们可应用到的目标(“应用于”)、它们是否可重复(“可重复”)、需要存在的其他特性(“必需的特性”)以及与其他特性的不兼容性(“无效特性”)。 这些字段在每个特性的引用主题中的随附表中列出。 下面对这些字段的每一个进行了介绍。

应用于

此字段描述了不同的 C++ 语言元素,这些元素是指定特性的法定目标。 例如,如果特性在“应用于”字段中指定“类”,表示该特性只能应用于合法的 C++ 类。 如果该特性应用于类的成员函数,则会导致语法错误。

有关详细信息,请参阅按用法的特性

可重复

此字段指示该特性是否可以重复应用于同一目标。 大多数特性是不可重复的。

必需的属性

此字段列出了需要存在的其他特性(即应用于同一目标),以使指定的特性正常工作。 特性在此字段具有条目的情况并不常见。

无效特性

此字段列出了与指定的特性不兼容的其他特性。 特性在此字段具有条目的情况并不常见。

调试插入的代码

使用特性可大大简化 C++ 编程。 有关详细信息,请参阅概念。 某些特性由编译器直接解释。 其他特性则向程序源中插入代码,然后由编译器进行编译。 此类插入的代码通过减少你必须编写的代码量使编程变得更容易。 但有时 bug 可能导致应用程序在执行插入的代码时失败。 发生这种情况时,您可能希望查看插入的代码。 Visual Studio 提供两种查看插入的代码的方法:

  • 可以在“反汇编”窗口中查看插入的代码

  • 使用 /Fx 可以创建合并的源文件,其中包含原始代码和插入的代码。

“反汇编”窗口显示与源代码和特性所插入代码对应的汇编语言指令。 此外,“反汇编”窗口还可以显示源代码批注

打开源批注

  • 右键单击“反汇编”窗口,然后从快捷菜单中选定“显示源代码”

    如果知道属性在源窗口中的位置,则可以使用快捷菜单在“反汇编”窗口中查找插入的代码

查看插入的代码

  1. 调试器必须处于中断模式。

  2. 在源代码窗口中,将光标放在要查看其插入代码的特性前面。

  3. 右键单击并从快捷菜单中选择“转到反汇编”

    如果属性位置在当前执行点附近,则可以从“调试”菜单选择“反汇编”窗口

查看当前执行点处的反汇编代码

  1. 调试器必须处于中断模式。

  2. 从“调试”菜单中选择“窗口”,然后单击“反汇编”

本节内容

特性编程常见问题解答
按组分的特性
按用法分的特性
按字母顺序的特性参考