P/Invoke(Platform Invoke、プラットフォーム呼び出し)は、
.NET Frameworkの
共通言語基盤 (CLI) が提供する重要な機能の一つです。この技術を利用することで、
.NET環境で実行されるマネージコードから、オペレーティングシステムやその他のプログラムが提供する動的ライブラリ内のネイティブコードを直接呼び出すことが可能になります。これにより、C#やVB
.NETなどの
.NET言語で開発されたアプリケーションから、
Windows APIのような既存のネイティブな機能を活用することができるようになります。
P/Invokeの仕組み
P/Invokeを使用する際、最も重要なのは、呼び出したいネイティブ関数の情報と、その関数が期待するデータ型を正確に定義することです。CLIは、マネージコードとネイティブコードの間でデータの受け渡しを行う際に、必要に応じて自動的にデータ型を変換します。この変換処理は「マーシャリング」と呼ばれます。
具体的には、P/Invokeの宣言は、`System.Runtime.InteropServices.DllImportAttribute`属性をメソッドの宣言に付与することで行います。この属性には、呼び出したいネイティブ関数が含まれるDLLの名前や、関数のエントリポイント(名前)、呼び出し規約などの情報が指定されます。例えば、Windowsの`user32.dll`内にある`FindWindow`関数を呼び出すC#のコードは以下のようになります。
csharp
using System.Runtime.InteropServices;
public class Example
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static void Main(string[] args)
{
IntPtr hWnd = FindWindow(null, "電卓");
if (hWnd != IntPtr.Zero)
{
Console.WriteLine("電卓が見つかりました。ハンドル: " + hWnd);
} else {
Console.WriteLine("電卓が見つかりませんでした。");
}
}
}
この例では、`DllImport`属性によって`user32.dll`の`FindWindow`関数が、`Example`クラスの`FindWindow`メソッドに紐付けられています。`FindWindow`メソッドを呼び出すことで、ネイティブの`FindWindow`関数が実行されます。
型の変換(マーシャリング)
P/Invokeで最も重要な要素の一つが、データ型の変換、すなわちマーシャリングです。`int`や`double`のような型は、マネージコードとアンマネージコードの両方で直接解釈できるため、コピーされずにメモリに固定されたまま直接渡されます。このような型は「blittable型」と呼ばれます。一方、`string`や`bool`のような型は、マネージコードとアンマネージコードの間で表現方法が異なるため、CLIによって変換処理(マーシャリング)が行われます。このような型は「非blittable型」と呼ばれます。
マーシャリングは、データの整合性を保つために不可欠ですが、同時にパフォーマンスに影響を与える可能性があります。特に文字列や複雑な構造体のマーシャリングは、メモリの割り当てやコピーなど、追加の処理を必要とするため、注意が必要です。
DllImport属性の詳細設定
`DllImport`属性には、様々なフィールドを指定することで、P/Invokeの動作をカスタマイズできます。例えば、文字列のキャラクタセット(ASCII, Unicodeなど)、呼び出し規約(__stdcall, __cdeclなど)、エラー処理の方法などを指定することができます。
次の例では、メソッド名とは異なるエントリポイント名を持つ関数を呼び出す設定を示しています。`EntryPoint`フィールドに、実際の関数名を指定することで、メソッド名と関数名を一致させないことが可能です。
csharp
[DllImport("user32.dll", EntryPoint = "FindWindowA")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
また、`CharSet`フィールドを使うことで、文字列のマーシャリング方法を指定することができます。
Windows APIと
.NET Frameworkの間でデータ型を変換する際には、対応表を参考にすると便利です。以下に、一般的な対応を示します。
Windows API (Win32/Win64) | .NET Framework | C# / VB.NET | 説明 |
---|
- | - | - | - |
`BOOL` | `System.Boolean` | `bool` | ブール値 |
`BYTE` | `System.Byte` | `byte` | 8ビット符号なし整数 |
`SHORT` | `System.Int16` | `short` | 16ビット符号付き整数 |
`WORD` | `System.UInt16` | `ushort` | 16ビット符号なし整数 |
`INT` | `System.Int32` | `int` | 32ビット符号付き整数 |
`UINT` | `System.UInt32` | `uint` | 32ビット符号なし整数 |
`LONG` | `System.Int32` | `int` | 32ビット符号付き整数 (Win32)/64ビット符号付き整数 (Win64) |
`ULONG` | `System.UInt32` | `uint` | 32ビット符号なし整数 (Win32)/64ビット符号なし整数 (Win64) |
`HANDLE` | `System.IntPtr` | `IntPtr` | ポインタ型 |
`HWND` | `System.IntPtr` | `IntPtr` | ウィンドウハンドル |
`LPCSTR` | `System.String` | `string` | ANSI文字列へのポインタ |
`LPCWSTR` | `System.String` | `string` | Unicode文字列へのポインタ |
`LPSTR` | `System.Text.StringBuilder` | `StringBuilder` | ANSI文字列へのポインタ(変更可能) |
`LPWSTR` | `System.Text.StringBuilder` | `StringBuilder` | Unicode文字列へのポインタ(変更可能) |
まとめ
P/Invokeは、
.NET Frameworkでネイティブコードを活用するための強力なツールです。正確な型定義と`DllImport`属性の設定を行うことで、マネージコードからネイティブの関数を安全に呼び出すことが可能です。ただし、マーシャリングはパフォーマンスに影響を与える可能性があるため、注意が必要です。P/Invokeを効果的に活用することで、既存のネイティブライブラリの機能を
.NETアプリケーションに取り込み、より多様な処理を実現できます。
参考情報
PInvoke.net - Win32 APIをはじめとしたアンマネージAPIのP/Invoke宣言を集めたデータベースサイト。主にC#/VB対応。
アンマネージ コードとの相互運用 - .NET Framework | Microsoft Learn