C#からDLL関数の呼び出し

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という値を指定します。

LayoutKind列挙体
メンバ 説明
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);