今回のプロジェクトでは、まずC#で実装したフォームを利用して、過去の資産のDLLを使用することにした。
復習:DLLの作り方
- Visual StudioでMFC 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を宣言し、インスタントを固定してそのポインタを取得する必要がある。
こんな感じだ。
よく見て頂くと分かるが、上記のDLLラッパー関数宣言の頭にもunsafeが付いている。
unsafe
{
fixed(byte* pDllByteArray = &byteArray[0])
{
DLL_Foo(intVar1, intVar2, pDllByteArray);
}
}
さらに、そのプロジェクトのbuildオプション(プロジェクトのプロパティからbuildタブを選ぶ)で、allow unsafe codeをチェックする必要がある。
但し・・・主要なMFCの型にはC#の対応型が存在する、詳細はこちら。
そして、なんとMFCのBYTE*はC#のbyte[]でそのまま受け渡しができるのだ。
なので、今回の場合には全くunsafeをする必要がなく、DLLラッパー関数宣言は
そのDLLを使用する部分は、
[DllImport("(DLLプロジェクト名).dll", CallingConvention = CallingConvention.Cdecl)]
static extern void DLL_Foo(int DllIntVar1, int DllIntVar2, byte[] DllByteArray);
でイケてしまうのだ。
DLL_Foo(intVar1, intVar2, byteArray);
ああ、ラクちん、ラクちん、楽をするのには丸一日ぐらいハマる必要があるのだ、orz