C++ Interop (暗黙の PInvoke) の使用
他の .NET 言語とは異なり、Visual C++ には相互運用性サポートが備えられています。相互運用性サポートを使用すると、managed、unmanaged プラグマにより、マネージド コードとアンマネージド コードは同じアプリケーション内、また同じファイルでも共存できるようになります。 これにより、Visual C++ 開発者は、他のアプリケーションの動作を妨げることなく、既存の Visual C++ アプリケーションに .NET 機能を統合できます。
また、dllexport、dllimport を使用して、マネージド コンパイル単位からアンマネージド 関数を呼び出すこともできます。
関数パラメーターのマーシャリング方法を指定したり、DllImportAttribute を明示的に呼び出す際に指定できるその他の詳細設定を行ったりする必要がない場合は、暗黙の PInvoke を使用すると便利です。
Visual C++ では、マネージド関数とアンマネージド 関数を相互運用するために 2 つの方法があります。
明示的な PInvoke は、.NET Framework でサポートされており、ほとんどの .NET 言語で使用できます。 ただし、その名前からわかるように、C++ Interop は Visual C++ 固有の機能です。
C++ Interop
C++ Interop では、より高度なタイプ セーフが提供されます。これは通常、より簡単に実装できます。 ただし、アンマネージ ソース コードが利用できない場合や、クロスプラットフォーム プロジェクト用である場合、C++ Interop は使用できません。
C++ COM Interop
Visual C++ がサポートしている相互運用機能は、COM コンポーネントとの相互運用性において、他の .NET 言語に比べ特に優れた効果を発揮します。 データ型のサポートに制限が存在したり、全 COM インターフェイスのすべてのメンバーの公開が義務付けられたりするなどの、.NET Framework Tlbimp.exe (タイプ ライブラリ インポーター) の制限にとらわれることなく、C++ Interop では、COM コンポーネントに自由にアクセスでき、独立した相互運用機能アセンブリは必要ありません。 Visual Basic や C# とは異なり、Visual C++ では通常の COM 機構 (CoCreateInstance や QueryInterface など) を使用して、COM オブジェクトを直接使用できます。 これは、マネージド関数からアンマネージド関数 (およびその逆方向) に移行するための遷移コードがコンパイラによって自動的に挿入される、C++ Interop 機能によって実現されています。
C++ Interop を使用すれば、COM コンポーネントを通常どおりに使用することも、C++ クラス内でラップすることもできます。 これらのラッパー クラスはカスタム ランタイム呼び出し可能ラッパー (CRCW) と呼ばれます。これらは、アプリケーション コード内で直接 COM を使用する場合と比べて、2 つの利点があります。
結果のクラスを、Visual C++ 以外の言語から使用できます。
COM インターフェイスの詳細を、マネージド クライアント コードからは見えないようにすることができます。 .NET データ型をネイティブ型の代わりに使用でき、データ マーシャリングの詳細は CRCW 内で透過的に実行できます。
COM が直接使用されるか、CRCW を介して使用されるかにかかわらず、単純な blittable 型以外の引数の型はマーシャリングする必要があります。
blittable 型
シンプルな組み込み型を使用するアンマネージ API については (「Blittable 型と非 Blittable 型」を参照)、メモリ内に同じデータ型表現があるため、特別なコーディングは必要ありません。ただし、複雑なデータ型については、明示的なデータ マーシャリングが必要です。 例については、「方法: PInvoke を使用してマネージド コードからネイティブ DLL を呼び出す」をご覧ください。
例
// vcmcppv2_impl_dllimp.cpp
// compile with: /clr:pure user32.lib
using namespace System::Runtime::InteropServices;
// Implicit DLLImport specifying calling convention
extern "C" int __stdcall MessageBeep(int);
// explicit DLLImport needed here to use P/Invoke marshalling because
// System::String ^ is not the type of the first parameter to printf
[DllImport("msvcrt.dll", EntryPoint = "printf", CallingConvention = CallingConvention::Cdecl, CharSet = CharSet::Ansi)]
// or just
// [DllImport("msvcrt.dll")]
int printf(System::String ^, ...);
int main() {
// (string literals are System::String by default)
printf("Begin beep\n");
MessageBeep(100000);
printf("Done\n");
}
Begin beep
Done
このセクションの内容
相互運用シナリオでのデリゲートの使用については、「delegate (C++ コンポーネント拡張)」をご覧ください。