.NET からのネイティブな COM サーバーの使用
更新 : 2007 年 11 月
このセクションでは、.NET アプリケーションから既存の COM コンポーネントを使用する際に使用できるオプションについて説明します。また、各アプローチの利点と欠点についても簡単に説明します。一般的には、C++ Interop を使用することをお勧めします。
TLBIMP の使用
Windows Software Development Kit (SDK) のタイプ ライブラリ インポータ (Tlbimp.exe)は、COM タイプ ライブラリを相互運用機能アセンブリと呼ばれるアセンブリとして公開するツールです。このアセンブリは、特定のタイプ ライブラリの各 COM インターフェイスに対して、マネージされた等価アセンブリ、つまりラッパーを定義します。
相互運用機能アセンブリのメソッドが呼び出されると、マネージからアンマネージへの遷移が実行され、制御が COM コンポーネントに渡されます。同様に、アンマネージ COM 関数から制御が戻ると、アンマネージからマネージへの遷移が実行されます。既定では、エラーを確認するために COM HRESULT が検証され、HRESULT が成功を示していない場合は例外がスローされます。同様に、COM コンポーネントの初期化およびインターフェイス クエリは相互運用機能アセンブリによって実行されるため、これらは呼び出し元のコードから隠ぺいされます。
相互運用機能アセンブリは、そのアセンブリが表している COM コンポーネントを置き換えません。つまり、アンマネージ COM 関数は COM コンポーネント内に残ります。したがって、COM コンポーネントをターゲット コンピュータにインストールして登録しないと、相互運用機能アセンブリの呼び出しは失敗します。
マネージ コードから COM コンポーネントを最も簡単に使用するには、Tlbimp を使用します。ただし、この方法には、特に大規模または複雑な COM インターフェイスで使用する場合に、いくつかの大きな欠点があります。これらの欠点を次に示します。
Tlbimp は、マネージ インターフェイスをタイプ ライブラリ内の各 COM インターフェイスに対して生成します。この動作を回避する方法はなく、結果として生成されるアセンブリはサイズが非常に大きくなる場合があります。たとえば、Tlbimp が Mshtml.dll に対して生成する相互運用機能アセンブリはサイズが 8 MB 以上になります。また、COM コンポーネント内でのみ使用するインターフェイスを隠ぺいする方法もありません。
Tlbimp がサポートするデータ型の数には制限があります。通常、サポートされていない型は、汎用的な非タイプ セーフ IntPtr 型としてマネージ環境にインポートされ、アセンブリを使用するには、エラーが発生しやすく冗長なマーシャリング コードが必要となりますが、場合によっては、Tlbimp.exe はインターフェイスのメンバをまったく公開できないこともあります。
Tlbimp は、最終的なアプリケーションと共に配置する必要がある独立した相互運用機能アセンブリを生成します。
これらの欠点を許容できる場合は、例について、「方法 : TLBIMP でネイティブ COM サーバーを使用する」を参照してください。
MSIL の変更
Tlbimp の欠点は若干緩和できます。そのためには、MSIL 逆アセンブラ (Ildasm.exe) を使用して相互運用機能アセンブリを逆アセンブリし、MSIL を編集することで不要なインターフェイス定義を削除して引数型を置き換え、編集後の MSIL を MSIL アセンブラ (Ilasm.exe) で再アセンブリします。このプロセスではエラーが発生しやすく、MSIL、アンマネージ型、および .NET 型についての知識が必要です。また、このプロセスは、COM インターフェイスが更新された場合も実行する必要があります。
C++ Interop
Visual Basic および C# とは異なり、Visual C++ では通常の COM 機構 (CoCreateInstance、QueryInterface など) を使用して COM オブジェクトを直接使用できるため、Visual C++ では Tlbimp の欠点、また MSIL の編集が必要であるという欠点を全面的に回避できます。これは C++ Interop の機能によって可能になります。これらの機能により、マネージ関数からアンマネージ関数への移行およびアンマネージ関数からマネージ関数への移行を実行する遷移コードをコンパイラが自動的に挿入します。
C++ Interop を使用すると、COM コンポーネントを通常どおりに使用することも、COM コンポーネントを C++ クラスにラップすることもできます。これらのラッパー クラスは、カスタム ランタイム呼び出し可能ラッパー (CRCW) と呼ばれ、アプリケーション コード内で COM を直接使用する場合よりも次の 2 つの点で有利です。
このラッパー クラスは、Visual C++ 以外の言語からも使用できます。
COM インターフェイスの詳細をマネージ クライアント コードから隠ぺいできます。ネイティブな型の代わりに .NET データ型を使用でき、データ マーシャリングの詳細を CRCW 内で透過的に実行できます。
Visual C++ を使用して COM インターフェイスをラップする方法については、「方法 : CRCW でネイティブ COM サーバーを使用する」を参照してください。
COM を直接使用するか、CRCW を利用するかどうかにかかわらず、単純な blittable 型以外の引数型はマーシャリングする必要があります。データのマーシャリングの詳細については、「C++ Interop (暗黙の PInvoke) の使用」を参照してください。
メモ : |
---|
MFC アプリケーションは、シングル スレッド アパートメント (STA: Single-Threaded Apartment) として初期化する必要があります。InitInstance のオーバーライドで CoInitializeEx を呼び出す場合、COINIT_MULTITHREADED ではなく COINIT_APARTMENTTHREADED を指定してください。詳細については、https://support.microsoft.com/default.aspx?scid=kb;ja-jp;828643 の「PRB: MFC アプリケーションは、マルチスレッド区画としてアプリケーションを初期化するとき、応答を停止します。」 (828643) を参照してください。 |