プライマリ相互運用アセンブリ (PIA)

January 2002

要約: このドキュメントでは、既存の COM 型のセットを共通言語ランタイムと相互運用させるためのメタデータを作成するプロセスについて説明します。

目次

メタデータと共通言語ランタイム
PIA に関する一般的な質問
   PIA とは?
   PIA が重要な理由は?
   自分の COM タイプ ライブラリ用の PIA を作成する方法は?
   PIA を使用しなかった場合にはどうなるか?
   PIA をカスタマイズする方法は?
   共通言語ランタイムと Visual Studio での PIA の扱われ方の違いは?
   複数の PIA を 1 つのファイルにまとめることは可能か?
   PIA に使用すべき名前空間は?
   PIA に使用すべきファイル名は?
   PIA に署名するためのキーの入手方法は?
   PIA を開発者に配布する方法は?
   出荷後に PIA を変更または改訂することはできるか?
   PIA のための発行者ポリシーを作成することはできるか?
   PIA を使わなくてもかまわない状況は?
   Microsoft プロダクトと Microsoft 以外のプロダクトの PIA を入手する方法は?

メタデータと共通言語ランタイム

共通言語ランタイムは、既存の COM 型と相互運用するためには、これらの型に関して理解可能な形式での記述を必要とします。共通言語ランタイムが理解する型情報の形式はメタデータと呼ばれ、マネージ アセンブリの中に格納されています。つまり、アプリケーションが COM 型と相互運用を行うためには、使用される型に関するメタデータ記述が必要となります。

このドキュメントでは、既存の COM 型のセットを記述するメタデータの作成プロセスについて説明します。このメタデータは、基本的に COM タイプ ライブラリの実行時における等価物と言うことができます。既存の COM 型を使用するためにはメタデータが必須となるので、COM タイプ ライブラリを公開している開発者は、COM タイプ ライブラリのためのメタデータの作成方法に特に注意を払わなくてはなりません。

PIA に関する一般的な質問

PIA とは?

他のマネージ アセンブリと同様に、相互運用アセンブリは、1 つの単位として配置、バージョニング、および構成が行われる型のコレクションです。しかし、他のマネージ アセンブリとは異なり、相互運用アセンブリは、すでに COM の中に定義されている型の (実装ではなく) 型定義を含んでいます。これらの型定義により、マネージ アプリケーションはコンパイル時に COM 型をバインドすることができ、共通言語ランタイムは実行時の型のマーシャリング方法についての情報を得ることができます。

特定の COM 型を記述する相互運用アセンブリは、いくつ存在していてもかまいませんが、そのうちの 1 つの相互運用アセンブリだけが PIA として指定されます。PIA は、これらの型の発行者によって定義された、型のオフィシャルな定義を含んでいます。PIA には、その型をマネージ コードから使いやすくする一定のカスタマイゼーションも含めることができます。PIA はつねに元の COM 型の発行者によって署名されています。

COM 型の発行者によって提供されたものでない相互運用アセンブリは非オフィシャルなものと見なし、使用を避けるべきです。このようなアセンブリに定義されている型は、PIA の発行者によって署名されていないので、PIA で提供されている定義との互換性がありません。

PIA が重要な理由は?

PIA が重要なのは、これが一意の型アイデンティティを提供するからです。PIA はオフィシャルな型定義を、他の相互運用アセンブリが提供する偽の定義と区別します。単一の型アイデンティティを持つことで、PIA に定義されている型を共有するアプリケーション間での型の互換性が保証されます。PIA はその発行者によって署名され、PrimaryInteropAssembly 属性で指定されているため、同じ型を定義している他の相互運用アセンブリと区別することができます。

自分の COM タイプ ライブラリ用の PIA を作成する方法は?

ほとんどの場合、PIA の作成は簡単です。Microsoft® .NET Framework に付属している Tlbimp (Type Library Importer) ツールは、既存のタイプ ライブラリから相互運用アセンブリを作成することができます。Tlbimp の /primary スイッチは PIA の作成に使用されます。すべての PIA はその発行者によって署名されなくてはなりませんので、/keyfile スイッチを使って発行者キーも指定する必要があります。次に例を示します。

  TlbImp Widget.tlb /primary /keyfile:AcmeKey.snk /out:WidgetLib.dll

上の例で、Widget.tlb はインポートされるタイプ ライブラリ、AcmeKey.snk は Acme Company のパブリック キーを含んでいるキーファイル、WidgetLib.dll は生成される PIA です。SN ユーティリティを使用すると、テスト用のキーファイルを生成することができます (SN.EXEk AcmeKey.snk)。アセンブリを実際に配置する前に、会社の本物のキーで署名するようにしてください。1 つの会社のすべてのアセンブリへの署名に、同じキーを使用するようにします。

PIA は他の PIA しか参照できません。このため、親アセンブリの PIA を生成する前に、依存アセンブリの PIA を生成するようにしてください。場合によっては、自分のアセンブリの PIA を生成するために、別の会社から PIA を入手しなくてはならないことがあります。すべての依存アセンブリの PIA を生成したら、Tlbimp/reference スイッチを使って、これらへの参照を追加することができます。

  TlbImp WidgetUtil.tlb /primary /keyfile:AcmeKey.snk /out:WidgetUtil.dll
TlbImp Widget.tlb /primary /keyfile:AcmeKey.snk 
            /reference:WidgetUtil.dll /out:WidgetLib.dll

ほとんどの場合、相互運用アセンブリは Tlbimp ツールによって生成されます。しかし、マネージ ソース コード (C# など) から相互運用アセンブリが生成されることもあります。ソース コードから生成される相互運用アセンブリは、アセンブリに PrimaryInteropAssembly 属性Guid 属性を追加することで PIA にすることができます。次に例を示します。

// アセンブリにタイプ ライブラリの Guid を割り当てる
[assembly:Guid("97d25db0-0363-1cf-abc4-02608 c9e7553"] 

// このアセンブリが tlb のバージョン 4.2 の PIA であることを指定する
[assembly:PrimaryInteropAssembly(4, 2)]

PIA を使用しなかった場合にはどうなるか?

PIA を使用しないと、カスタマの側で型の互換性の問題が生じます。たとえば、A 社が自社のマネージ アプリケーションの中で、Acme Company が提供している COM Widget オブジェクトを使用していたとします。A 社は、Acme Company が提供している PIA を使用する代わりに、Acme の Widget ライブラリの定義を含んだ別の相互運用アセンブリを生成することにしました。

B 社は Widget ライブラリの PIA を Acme Company から直接に入手し、これを自社のマネージ アプリケーションの中で使用しています。どちらのアプリケーションも単独では正常に動作しますが、A 社と B 社の共通のカスタマは、A 社から B 社にウィジェットを渡そうとすると、型の不一致のエラーが発生するという問題に遭遇します。

この型の不一致が生じるのは、A 社の使用している Widget 型が B 社の使用している Widget 型とまったく異なるためです。どちらも同じ名前を持っていますが、個々の相互運用アセンブリは異なる発行者によって署名されているため、型は互換性を持たなくなります。両方の会社が Acme Company が提供している PIA を使用するようにすれば、この問題は簡単に解決されます。

PIA をカスタマイズする方法は?

発行者が自分の PIA をカスタマイズしたいと考える状況には、次のようなものが考えられます。

  • アセンブリ内の特定の要素の名前を変更したい、または隠したいと思った場合。
  • 属性を追加して、マーシャリングの動作を変更したいと思った場合。

バージョン 1.0 リリースでは、カスタム PIA を作成する方法が 2 つあります。

  1. ソース コードの中で、マネージ言語と各種のカスタム属性を使って、PIA のための型定義を作成する。
  2. Tlbimp を使って PIA を生成し、Tlbimp が生成した Microsoft 中間言語 (MSIL) 型定義を変更することでカスタマイズを行う。

このような変更を加えるためのツールには、ILDASM と ILASM があります。このためのプロセスを次に示します。

  1. 通常どおり、Tlbimp を使ってタイプ ライブラリをインポートします。

    TlbImp MyLib.tlb /primary /out:MyLib.dll
    
  2. ILDasm を使って、アセンブリのための MSIL ソース コードを生成します。

    ILDASM MyLib.dll /out=MyLib.il
    
  3. 必要に応じて、適当なテキスト エディタで MSIL コードを変更します。

    Notepad MyLib.il
    
  4. ILASM コンパイラを使って MSIL を再コンパイルします。

    ILAsm /DLL /KEY=MyKey.snk MyLib.il 
    

上のステップ 2 では、アセンブリ内にリソースが見つかれば、RES ファイルも生成されます。RES ファイルが生成された場合には、ステップ 4 で、ILASM の /resource オプションを使って、アセンブリに戻す必要があります。

共通言語ランタイムと Visual Studio での PIA の扱われ方の違いは?

共通言語ランタイムと Microsoft® Visual Studio® は、可能な限り PIA が使用されるように、PIA を他のアセンブリとはいくぶん違った方法で扱います。

登録時: PIA は RegAsm ツールを使って登録します。RegAsm は、個々のタイプ ライブラリ キーの下に、自動的にそのアセンブリが PIA であることを示すレジストリ項目を作成します。たとえば、あるアセンブリが、ADODB タイプ ライブラリのバージョン 1.0、1.5、および 2.0 の PIA である場合には、登録されたアセンブリをそのタイプ ライブラリの PIA として識別する項目が、個々のタイプ ライブラリ キーの下に作成されます。

Visual Studio: ユーザーが登録済みの PIA を持つタイプ ライブラリへの参照を追加しようと試みると、Visual Studio は、Tlbimp を使ってタイプ ライブラリを再インポートする代わりに、登録済みの PIA を自動的に使用します。この方法で、PIA が可能な限り使用されるようにしています。

ユーザーが登録済みの PIA を持たないタイプ ライブラリへの参照を追加しようと試みると、PIA が存在しないという警告が表示され、PIA を入手するための MSDN サイトが紹介され、Visual Studio はその時点でタイプ ライブラリをインポートする機会が与えられます。Visual Studio にタイプ ライブラリをインポートさせた場合、ユーザーは PIA と、PIA の作成者が加えたすべてのカスタマイゼーションをバイパスすることになります。これは勧められません。

複数の PIA を 1 つのファイルにまとめることは可能か?

Tlbimp は、複数のアセンブリを 1 つの PIA にまとめる手段を提供していません。ただし、ILDASM が生成した MSIL を、他のアセンブリの MSIL とマージすることで、アセンブリを結合することは可能です。このアプローチを使用するためには、MSIL に関する基本的な知識が必要です。

PIA に使用すべき名前空間は?

PIA の名前空間はインポート時に定義されます。既定の設定では、名前空間はタイプ ライブラリ名と同じになります (タイプ ライブラリのファイル名ではなく、タイプ ライブラリの中の名前)。名前空間は、Tlbimp の /namespace オプションを使って変更できます。

適切な名前空間を決めるのは難しいことがあります。以下に注意すべき点をいくつか示します。

  • 既存の Microsoft® Visual Basic® 6.0 コードは、型のスコープをタイプ ライブラリ名によって決定します。たとえば、ADO ライブラリは Visual Basic 6.0 では ADODB として参照されます。既定の名前空間を使用すれば、既定の名前空間はオリジナルのタイプ ライブラリ名 (ADODB) と同じなので、Visual Basic 6.0 アプリケーションとのソース レベルでの互換性が確保されます。
  • 「真の」名前空間は、将来作成されるマネージ バージョンのライブラリのために残しておくといいでしょう。たとえば、Microsoft Excel チームは "Office.Excel.Interop" という名前空間を使用し、これよりもわかりやすい "Office.Excel" という名前空間は、将来作成されるマネージ抽象レイヤのために予約しておくことができます。
  • PIA のユーザーはソース コードの中で名前空間を参照しなくてはならないため、名前空間はわかりやすく、かつ簡潔なものにするべきです。
  • 短縮形を使用するのは避けます。

PIA に使用すべきファイル名は?

アセンブリに関連する重要な名前は、アセンブリ名、名前空間名、そしてアセンブリのファイル名の 3 つです。既定の設定では、Tlbimp はアセンブリのインポート元のタイプ ライブラリの名前 (つまりライブラリを含んでいるファイルの名前ではなく、ライブラリ名) を 3 つのすべての名前に使用するアセンブリを作成します。たとえば、foo.dll に含まれている FooLib タイプ ライブラリが Tlbimp でインポートされた場合には、FooLib.dll という名前のファイルの中に、FooLib という名前の名前空間を持つ、FooLib という名前のアセンブリが作成されます。

Tlbimp が作成するアセンブリ名とファイル名は、/out オプションを使って変更することができます。名前空間は /namespace オプションで変更できます。

インポートされたタイプ ライブラリが、ライブラリを含んでいるファイルと同じ名前を持っている場合、Tlbimp は入力ファイルを出力ファイルで上書きすることはしません。この場合には、ユーザーは /out オプションを使って別の出力ファイル名を指定する必要があります。このときに使われる一般的な名前付け規約は、ライブラリの名前に ".Interop" を追加するというものです。たとえば、foo.dll という名前のファイルの中のタイプ ライブラリ名 Foo は、Foo.Interop.dll にインポートされます。

PIA に署名するためのキーの入手方法は?

PIA は、他のマネージ アセンブリの署名に使用されるのと同じパブリック/プライベート キーのペアで署名することができます。キーは、Microsoft® .NET Framework SDK に付属している SN ユーティリティで生成できます。

PIA を開発者に配布する方法は?

PIA は、ベンダが作成するすべてのアンマネージ コード ライブラリの一部として配布するべきです。PIA の配布は、タイプ ライブラリと同じように、DLL または EXE の形で行います。

出荷後に PIA を変更または改訂することはできるか?

はい、できます。ただし、新しいバージョンを作成するたびに、アセンブリのバージョン番号を変更する必要があります。

PIA のための発行者ポリシーを作成することはできるか?

はい。発行者ポリシー、アプリケーション ポリシー、およびマシン ポリシーを使って、アプリケーションが PIA にどのようにバインドするかを管理できます。

PIA を使わなくてもかまわない状況は?

PIA が入手不可能な場合には、PIA でない相互運用アセンブリを使用しなくてはならないことがあります。これは代替相互運用アセンブリと呼ばれます。PIA アセンブリを使用できない場合には、代替相互運用アセンブリに定義されている型をアセンブリで公開するのは避けるようにしてください。代替相互運用アセンブリの使用は、アセンブリ内に定義されている型が内部の使用に限定されている場合にのみ許容されます。アセンブリは代替相互運用アセンブリの型をパブリックに公開することはできません。言い換えると、アセンブリは、代替相互運用アセンブリに定義されている型を使用するパブリック メソッド、フィールド、またはプロパティを含むことはできません。また、アセンブリは代替相互運用アセンブリに定義されているインターフェイスを実装することはできません。

Microsoft プロダクトと Microsoft 以外のプロダクトの PIA を入手する方法は?

一部の PIA は Microsoft Visual Studio .NET に添付され、その他のものは将来設置される PIA ダウンロード サイトで入手可能となる予定です。