IMetaDataImport和WinRT运行时类接口

时间:2012-10-15 18:16:23

标签: reflection windows-runtime idl

在Visual Studio 2012附带的MS IDL版本中,对WinRT的支持添加了这样的结构:

        [activatable(Windows.Networking.Sockets.IControlChannelTriggerFactory,
                     0x06020000)]
        [threading(mta)]
        [marshaling_behavior(agile)]
        [version(0x06020000)]
        runtimeclass ControlChannelTrigger
        {
            [default] interface Windows.Networking.Sockets.IControlChannelTrigger;
            interface Windows.Foundation.IClosable;
        }

我正在使用IMetaDataImport来分析winmd文件中的所有类型。如何找出“运行时类”实现的接口,以及默认接口的接口是什么?

1 个答案:

答案 0 :(得分:5)

  

如何找出“运行时类”实现的接口?

Windows元数据文件由关系数据库组成:它基本上是一组相互关联的表。您可以在ECMA 335的分区II中找到逻辑架构的规范。

每个运行时类和接口都由元数据数据库的TypeDef表中的一行表示。 “类型X实现接口I和J”关系由InterfaceImpl表中的行表示,它将类型定义映射到它们实现的接口。

由于多种原因,计算由类型实现的接口集非常困难。假设我们想要计算由XAML Button控件实现的接口集。需要执行以下所有步骤:

  1. 查找并加载定义Button的元数据文件。您可以致电RoGetMetaDataFile

  2. 查找Button类型的元数据标记。这实际上是该类型的唯一标识符。您可以致电FindTypeDefByName

  3. 我们需要计算Button类型直接实现的所有接口。这可以通过致电EnumInterfaceImpls

  4. 来完成
  5. Button类型来自ButtonBase类型。这由TypeDef表的 extends 字段指定,您可以通过调用GetTypeDefProps获取该字段。我们需要计算它实现的所有接口。然后我们需要在类层次结构中一直这样做 - 对于Button,这有很多类型:ContentControlControlFrameworkElement,{{ 1}}和UIElement

    请注意,其中一些类型可能在另一个元数据文件中定义。在这种情况下,InterfaceImpl将通过TypeRef令牌引用接口,而不是TypeDef令牌。 TypeRef表包含对类型的引用。您需要解析该引用,加载正确的元数据文件,并在该元数据文件中查找目标类型。这可以使用我们为DependencyObject执行的步骤来完成。

  6. 每个接口也可以实现其他接口,因此对于我们目前在列表中累积的每个接口,我们需要获取接口所需的接口集。这是通过递归获取每个接口的InterfaceImpls来完成的。

    请注意,与基类的情况一样,实现的接口也可以在另一个元数据文件中定义。因此,您还需要使用与基类相同的过程来解决这些问题。

    对于增加的挑战,Windows运行时支持通用接口。如果接口实现实例化的通用接口,则该实例化的接口将由TypeSpec表中的行表示,并且将在blob流中伴随签名。您需要解析签名。执行此操作的过程相当复杂,但数据格式在ECMA 335中完全指定。

  7. 此时,您将拥有该类型实现的完整接口集。通过检查与Button类型直接关联的InterfaceImpls可以找到默认接口:默认接口将应用DefaultAttribute(请注意,自定义属性应用于InterfaceImpl,而不是接口类型)。您可以使用EnumCustomAttributes枚举每个InterfaceImpl的自定义属性。

    所以,这是一项非常多的工作,而且需要大量的代码。我发现Button界面及其朋友处理起来相当不友好,所以我为Boost许可的CxxReflect library编写了自己的界面。 CxxReflect元数据库提供比IMetaDataImport更好的类型检查,并包括解析签名所需的逻辑。它不如IMetaDataImport快,但它已经接近了。

    CxxReflect Reflection库包含用于跨元数据文件边界解析类型以及与Windows运行时集成的大部分逻辑。它仍处于alpha质量阶段,但它对于常见任务非常有效(它目前正在进行一些重构,以使类型解析逻辑可以重复用于反射以外的用途)。

    你当然可以自己实现逻辑,但这非常繁琐。在CxxReflect的开发过程中,我发现了几次我没有考虑到的另一个角落案例,我不得不做大量的返工。规范已经完成,但事情并不总是很明显。