2

Visual Studio2012に付属するMSIDLバージョンでは、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ファイル内のすべてのタイプを分析しています。「runtimeclass」が実装しているインターフェイスと、デフォルトのインターフェイスがどのインターフェイスであるかを確認するにはどうすればよいですか。

4

1 に答える 1

5

「ランタイムクラス」が実装しているインターフェイスを確認するにはどうすればよいですか?

Windowsメタデータファイルはリレーショナルデータベースで構成されています。これは基本的に相互に関連するテーブルのセットです。論理スキーマの仕様は、ECMA335のPartitionIIにあります。

すべてのランタイムクラスとインターフェイスは、メタデータデータベースのTypeDefテーブルの行で表されます。「タイプXはインターフェイスIおよびJを実装します」の関係は、タイプ定義を実装するインターフェイスにマップするInterfaceImplテーブルの行で表されます。

型によって実装されるインターフェイスのセットを計算することは、いくつかの理由から非常に困難であることがわかりました。XAMLButtonコントロールによって実装されたインターフェイスのセットを計算するとします。次のすべての手順が必要です。

  1. を定義するメタデータファイルを見つけてロードしますButton。これを行うには、を呼び出しRoGetMetaDataFileます。

  2. タイプのメタデータトークンを見つけますButton。これは事実上、そのタイプの一意の識別子です。これは、を呼び出すことで取得できますFindTypeDefByName

  3. タイプによって直接実装されたすべてのインターフェースを計算する必要がありますButton。これは、を呼び出すことで実行できますEnumInterfaceImpls

  4. タイプはButtonタイプから派生しButtonBaseます。これは、TypeDefテーブルのextendsフィールドで指定されます。このフィールドは、を呼び出すことで取得できますGetTypeDefProps。実装するすべてのインターフェースを計算する必要があります。次に、クラス階層のずっと上まで同じことを行う必要があります。たとえば、Buttonこれは多くのタイプです :、、、、、および。ContentControlControlFrameworkElementUIElementDependencyObject

    これらのタイプの一部は、別のメタデータファイルで定義されている場合があることに注意してください。その場合、InterfaceImplは、TypeDefトークンではなく、TypeRefトークンを介してインターフェイスを参照します。TypeRefテーブルには、タイプへの参照が含まれています。その参照を解決し、正しいメタデータファイルをロードして、そのメタデータファイルでターゲットタイプを見つける必要があります。これは、に対してすでに実行した手順を使用して実行できますButton

  5. 各インターフェイスは他のインターフェイスも実装する可能性があるため、これまでにリストに蓄積したインターフェイスごとに、そのインターフェイスに必要なインターフェイスのセットを取得する必要があります。これは、これらの各インターフェイスのInterfaceImplsを再帰的に取得することによって行われます。

    基本クラスの場合と同様に、実装されたインターフェースも別のメタデータファイルで定義される場合があることに注意してください。したがって、基本クラスで使用されるのと同じプロセスを使用して、これらも解決する必要があります。

    追加の課題として、Windowsランタイムは汎用インターフェイスをサポートしています。インターフェイスがインスタンス化されたジェネリックインターフェイスを実装している場合、そのインスタンス化されたインターフェイスはTypeSpecテーブルの行で表され、blobストリームの署名が付随します。署名を解析する必要があります。これを行うプロセスはかなり複雑ですが、データ形式はECMA335で完全に指定されています。

この時点で、タイプによって実装されたインターフェイスの完全なセットができあがります。Buttonデフォルトのインターフェースは、タイプに直接関連付けられているInterfaceImplsを調べることで見つけることができます。デフォルトのインターフェースがDefaultAttribute適用されます(カスタム属性はインターフェースタイプではなく、InterfaceImplに適用されることに注意してください)。を使用して、各InterfaceImplのカスタム属性を列挙できますEnumCustomAttributes

ですから、それは非常に多くの作業であり、多くのコードを必要とします。インターフェースとその友達は扱いにくいと感じたので、BoostライセンスのCxxReflectライブラリIMetaDataImport用に自分で作成しました。CxxReflectメタデータライブラリは、署名の解析に必要なロジックよりも優れたタイプチェックを提供します。それほど速くはありませんが、近づいています。IMetaDataImportIMetaDataImport

CxxReflect Reflectionライブラリには、メタデータファイルの境界を越えてタイプを解決し、Windowsランタイムと統合するためのロジックのほとんどが含まれています。まだアルファ品質の段階ですが、一般的なタスクではかなりうまく機能します(現在、リファクタリング以外の用途で型解決ロジックを再利用できるようにするために、いくつかのリファクタリングが行われています)。

確かにこれを自分で行うロジックを実装することはできますが、それは非常に面倒です。CxxReflectの開発中に何度か、私が説明していなかったさらに別のコーナーケースを見つけ、大幅な手直しをしなければなりませんでした。仕様は完全ですが、物事がどのように機能するかは必ずしも明らかではありません。

于 2012-10-15T18:51:39.620 に答える