読者です 読者をやめる 読者になる 読者になる

C# へのネイティブ DLL の取り込み - 値渡し,参照渡し引数編

仕事で C# を使うようになったため C# 関連の勉強を開始.既存の資産が C である場合が多いので,C の DLL を取り込む方法を調べた.

C# 側での記述

簡単な例 (参照渡しパラメータなしの Win32API)

 DllImport 属性 (System.Runtime.InteropServices) を利用し,その関数が外部にあることを宣言する.例えば,下記の Win32API を用いる場合,,,

BOOL MessageBeep(
    UINT uType   // サウンドの形式
);

C# 側では下記のように宣言する.
DllImport 属性をつけた Win32 API や DLL 関数の宣言では,関数の実体が外部にあることを表す extern 修飾子と静的なメンバであることを表す static を必ず指定する.
(Windows の DLL と .NET Framework とでは型の管理方法が異なるため,実際には型の相互変換(マーシャリング)が行われる.)

class BeepTest
{

  // DLL "user32.dll" から持ってくる関数であることを宣言.
  [DllImport("user32.dll")]
  extern static bool MessageBeep(uint uType)

  public void test() {
    // 値渡しのパラメータを渡して呼んであげる.
    MessageBeep(0xFFFFFFFF);
  }

  static void Main() {
    BeepTest test = new BeepTest();
    test.test();
  }

}

参照渡しのパラメータを含む DLL の場合

 参照渡しのパラメータを含む関数を宣言するには,参照渡しになっているパラメータを ref パラメータとして宣言する.たとえば,例として下記のような関数を考えてみる.ここで,下記の関数は数字を受け取り,受け取った値に対して10追加して返す関数とする.

BOOL Add10(
    int* num // 参照渡しのパラメータ.関数呼び出し時に初期値の指定が必要で,関数が戻ってきたときの値も必要.
);

上記のような参照渡しのパラメータを含む DLL 関数の場合,C# 側では下記のように宣言する.

// 呼び出し側から初期値を与える必要がない場合は,"ref" を "out" として宣言することもできる.

class AddTest 
{

  [DllImport("MyDll.dll")]
  extern static bool Add10(ref uint num);

  public void test() {
    int num = 3;
    Console.WriteLine("Original Number : " + num);
    Add10(ref num); // 関数呼び出し側でも参照変数であることを明示.
    Console.WriteLine("Modified Number : " + num);
    Console.ReadLine();
  }

  static void Main() {
    test();
  }

}


一方で,関数の提供側である C のコードは下記のように記述する.

// MyDll.h

extern "C" {
  __declspec(dllexport) void Add10(int* num);
}

// MyDll.cpp

void Add10(int* num) {

  *num = *num + 10;
  return;

}