C# から DLL 関数を呼び出す方法について示します。
動作環境
- Windows 7 Professional
- VisualStudio express 2013 for Desptop
DLL関数を呼び出すのためのDLLImportの使用
C# から DLL 関数を呼び出すには、DLLImportを行います。関数を呼び出すには、コンパイラに API の位置を知らせる必要があります。これには、System.Runtime.InteropServices.DllImport 属性を用います。この属性が指定されたメソッドは、指定した DLL に存在すると解釈されます。DllImportで使用できるCallingConventionは、呼び出し方法の種類が選択でき、次のようなものがあります。
パラメータ | 説明 | 既定値 |
---|---|---|
EntryPoint | DLL内の関数の名前 | |
CharSet | 文字列のマーシャリング方法を示すCharSet列挙 | CharSet.Auto |
SetLastError | Win32エラー情報を維持するか? | FALSE |
ExactSpelling | EntryPointの関数名を厳密に一致させるか? | FALSE |
PreserveSig | T定義通りのメソッドのシグネチャを維持するか? | |
CallingConvention | EntryPointで使用するモードを指定するCallingConvention列挙 | StdCall |
また、C# 言語では外部メソッドを呼び出す場合、必ず、メソッドに extern 修飾子を指定しなければなりません。この extern キーワードは、一般的に DllImport 属性とセットで用いられます
using System.Runtime.InteropServices; // DLL Import class Win32Api { [DllImport("User32.Dll", EntryPoint="SetWindowText")] public static extern void SetWindowText(int hwnd, String text); }
データ型の変換
C++で作成した関数をC#の使用する場合、データ型をC#に合わせる必要があります。C++のデータ型をC#のデータ型に変換する場合の一覧表を次に示します。
内容とサイズ | C++ | C# |
---|---|---|
1 バイト | signed char | sbyte |
2バイト | signed short int | short |
4 バイト | long (long int、signed long int) | int型 |
8 バイト | __int64 | long |
符号なし1バイト | BYTE bool | byte |
符号なし2バイト | unsigned short | ushort |
符号なし4バイト | unsigned int unsigned long |
uint |
符号なし8バイト | unsigned __int64 | ulong |
構造体の関数パラメータ
構造体を持つ関数のパラメータを、C#の関数として取り扱うためには、そのメンバの配置方法を変更する必要があります。これを実現するには、構造体に対してStructLayout属性(System.Runtime.InteropServices名前空間)を設定します。このとき、配置方法としてLayoutKind列挙体(System.Runtime.InteropServices名前空間)のメンバのいずれかを指定します。例えば、C言語などの構造体と同様に、メンバが宣言された順に配置されるようにするには、LayoutKind.Sequentialという値を指定します。
メンバ | 説明 |
---|---|
Sequential | 宣言される順番に従って並べる |
Explicit | FieldOffsetAttributeで独自のオフセットを指定して並べる |
Auto | 適切なレイアウトで並べる。(マネージコードの外からアクセスできない) |
パラメータ | 説明 | 既定値 |
---|---|---|
Pack | パックサイズを指定するint値。指定可能な値は[ 1, 2, 4, 8, 16]のいずれか。 | 8 |
CharSet | 文字列のマーシャリング方法を示すCharSet列挙 | CharSet.Auto |
Size | 構造体またはクラスのサイズを指定 |
[StructLayout(LayoutKind.Sequential,Pack=4)] public struct RECT { public int left; public int top; public int right; public int bottom; } class Win32Api { [DllImport("User32.Dll", EntryPoint="GetWindowRect")] public static extern int GetWindowRect(int hwnd, ref RECT rc); }
呼び出し側
private void button4_Click(object sender, EventArgs e) { RECT rc = new RECT(); int hwnd = (int)this.Handle; Win32Api.GetWindowRect(hwnd, ref rc); string msg = String.Format("top={0}, left={1}, right={2}, bottom={3}." , rc.top, rc.left, rc.right, rc.bottom); MessageBox.Show(msg); }
ポインタ型の関数パラメータ
Netでは、IntPtrを使ってラップします。ただし、受け取ったポインタから構造体へ変換するには、Marshal.PtrToStructureなどを使用して、データをC#側のプログラムに転送する必要があります。
using System.Runtime.InteropServices; public delegate bool EnumWindowCB2(int hwnd, IntPtr lparm); [DllImport("User32.Dll", EntryPoint = "EnumWindows")] public static extern int EnumWindows2(EnumWindowCB2 cb, IntPtr lparm);