MFCで作ったDLLをC#で使用する

今回のプロジェクトでは、まずC#で実装したフォームを利用して、過去の資産のDLLを使用することにした。

復習:DLLの作り方

  • Visual StudioMFC DLLプロジェクトを新しく作成する
  • 実装クラス(大概"プロジェクト名.cpp"になっているはず)に以下のようなエントリーポイントを作成する


extern "C" __declspec(dllexport) void DLL_Foo(int, int, BYTE*);
void DLL_Foo(int DllIntVar1, int DllIntVar2, BYTE* pDllByteArray)
{
(適切な実装をする)
}

  • ビルド

以上


次に使う側のC#のプロジェクトでDLLラッパー関数を作成する

DLLラッパー関数の作成

  • 実装クラスの宣言に"using System.Runtime.InteropServices;"を追加する、これでDLLImportプロパティが使用できるようになる
  • 実装クラスに以下を追加


[DllImport("(DLLプロジェクト名).dll", CallingConvention = CallingConvention.Cdecl)]
unsafe static extern void DLL_Foo(int DllIntVar1, int DllIntVar2, byte* pDllByteArray);

  • あとは呼び出して使うだけ

あまり難しくはない。


今回ハマったのは、ここで出てくるBYTE*の引渡しであった。
C#では通常ポインタを使用しない。
使用するのであれば、unsafeした上にfixedを宣言し、インスタントを固定してそのポインタを取得する必要がある。
こんな感じだ。


unsafe
{
fixed(byte* pDllByteArray = &byteArray[0])
{
DLL_Foo(intVar1, intVar2, pDllByteArray);
}
}
よく見て頂くと分かるが、上記のDLLラッパー関数宣言の頭にもunsafeが付いている。
さらに、そのプロジェクトのbuildオプション(プロジェクトのプロパティからbuildタブを選ぶ)で、allow unsafe codeをチェックする必要がある。


但し・・・主要なMFCの型にはC#の対応型が存在する、詳細はこちら
そして、なんとMFCのBYTE*はC#のbyte[]でそのまま受け渡しができるのだ。
なので、今回の場合には全くunsafeをする必要がなく、DLLラッパー関数宣言は


[DllImport("(DLLプロジェクト名).dll", CallingConvention = CallingConvention.Cdecl)]
static extern void DLL_Foo(int DllIntVar1, int DllIntVar2, byte[] DllByteArray);
そのDLLを使用する部分は、

DLL_Foo(intVar1, intVar2, byteArray);
でイケてしまうのだ。
ああ、ラクちん、ラクちん、楽をするのには丸一日ぐらいハマる必要があるのだ、orz