P/Invoke
P/Invoke(Platform Invoke、プラットフォーム呼び出し)とは、.NET Frameworkにおける共通言語基盤 (CLI) の機能の一つであり、マネージコードから動的ライブラリ内のネイティブコードを呼び出すことを可能にするものである。受け渡しされるデータ型は、必要であればCLIによって適切に変換されるが、メタデータによってプログラマーが変換方法を指定することもできる。こうしたデータの変換をマーシャリングという。
例
P/Invokeの宣言は、System.Runtime.InteropServices.DllImportAttribute属性をメソッドの宣言につけることで行う。
次のC#コード例では、user32.dll内に定義されているFindWindow関数を呼び出している。
using System.Runtime.InteropServices;
namespace Example
{
class ExampleClass
{
// FindWindowのアンマネージシグネチャは HWND FindWindow(LPCTSTR, LPCTSTR)
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public void Test(string windowName)
{
IntPtr hWnd = FindWindow(null, windowName);
if (hWnd == IntPtr.Zero)
{
Console.WriteLine("Window not found.");
}
else
{
Console.WriteLine("There is a window named " + windowName + ".");
}
}
}
}
このように、P/Invokeで宣言したメソッドは通常のメソッドのように呼び出すことができる。
intやdoubleのような型はアンマネージコードが直接解釈することができるため、コピーされずにメモリに固定されたまま直接渡される(blittable型)。一方、stringやboolのような型はマネージコードとアンマネージコードとの間で表現方法が異なるため、CLIによって変換処理(マーシャリング)が行われる(非blittable型)[1]。
また、DllImportのフィールドを指定することで、文字列のキャラクタセット、呼び出し規約、エラー処理などといった既定の動作を変更することができる。例えば、次の宣言ではメソッド名とは異なる名前の関数を呼び出し対象とするよう指定している。
// ShellExecuteのアンマネージシグネチャは HINSTANCE ShellExecute(HWND, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, INT)
[DllImport("shell32.dll", EntryPoint="ShellExecute")]
static extern IntPtr UnmanagedFunctionWithNewName(
IntPtr hWnd,
string lpVerb,
string lpFile,
string lpParameters,
string lpDirectory,
int nShowCmd
);
Windows APIと.NET Frameworkの対応表
以下の表にWindows API (Win32/Win64) での型名[2]、.NET Frameworkでの型名、C#/VBでの型名の対応を示す。
Windows APIでの型名 | .NET Frameworkでの型名 | C#での型名 | Visual Basicでの型名 |
---|---|---|---|
HANDLE (void* ) あるいはHBITMAP [3]などハンドルを表す型名 | System.IntPtr | System.IntPtr | System.IntPtr |
INT_PTR , LONG_PTR など(ポインタと同サイズの整数型) | System.IntPtr | System.IntPtr | System.IntPtr |
INT8 /SCHAR (signed char ) | System.SByte | sbyte | SByte |
UINT8 /UCHAR /BYTE /BOOLEAN (unsigned char ) | System.Byte | byte | Byte |
INT16 /SHORT (short ) | System.Int16 | short | Short |
UINT16 /USHORT /WORD (unsigned short ) | System.UInt16 | ushort | UShort |
INT32 /INT (int )LONG32 /LONG (long ) | System.Int32 | int | Integer |
UINT32 /UINT (unsigned int )ULONG32 /ULONG /DWORD (unsigned long ) | System.UInt32 | uint | UInteger |
INT64 /LONG64 /LONGLONG (long long ) | System.Int64 | long | Long |
UINT64 /ULONG64 /ULONGLONG (unsigned long long ) | System.UInt64 | ulong | ULong |
BOOL (int ) | System.Boolean | bool [4] | Boolean [5] |
CHAR (char ) | System.Byte /System.SByte | byte /sbyte | Byte /SByte |
WCHAR (wchar_t ) | System.Char | char | Char |
LPSTR (char* )LPWSTR (wchar_t* ) | System.Text.StringBuilder | System.Text.StringBuilder | System.Text.StringBuilder |
LPCSTR (const char* )LPCWSTR (const wchar_t* ) | System.String | string | String |
FLOAT (float ) | System.Single | float | Single |
DOUBLE (double ) | System.Double | double | Double |
外部リンク
- PInvoke.net - Win32APIをはじめとしたアンマネージAPIのP/Invoke宣言を集めたデータベースサイト。主にC#/VB対応。
- アンマネージ コードとの相互運用 - MSDN
脚注
- Blittable 型と非 Blittable 型
- Windows Data Types - Windows applications | Microsoft Docs
- STRICTシンボル定義の有無によって変化するが、ポインタ型であることに変わりはない。
- sizeof(bool)の結果は1だが、System.Runtime.InteropServices.Marshal.SizeOf(typeof(bool))の結果は4となる。
- Len(New Boolean)の結果は2だが、System.Runtime.InteropServices.Marshal.SizeOf(GetType(Boolean))の結果は4となる。