C/C++ による汎用 DLL を作成する その4

前回では次のような関数を公開する DLL を C/C++ で作成しました。

今回はこの DLL を C# から使う方法をまとめます。

とりあえず C# のコンソールアプリケーションプロジェクトを作成し、
次のようにコマンドプロンプトウィンドウが保持されるようにしましょう。

ここで一度ビルドしてアセンブリを生成しておきます。

さて、C# で作成される DLL アセンブリを使う場合は、
ソリューションエクスプローラー上の「参照設定」に
使用する DLL を追加するようにしていましたが、
C/C++ で作成された DLL ファイルを使う場合は方法が異なります。

まず、作成するアプリケーションファイルと同じディレクトリか、
環境変数に設定されているパス上に使用する DLL ファイルを置きます。
通常はプロジェクトファイルのあるディレクトリの中の
bin\Debug ディレクトリ、Release モードの場合は bin\Release ディレクトリですね。
その上で、次のようなコードを追加します。

C/C++ による DLL を使用するときは、
使用する関数を static extern 修飾子を付けて宣言し、
System.Runtime.InteropServices.DllImport 属性を使って
使用する DLL ファイルを指定します。
このとき、DLL ファイルのパス指定が間違っていたり、
指定された場所に DLL ファイルが存在しないと
実行時に DllNotFoundException 例外が発生するので注意が必要です。

これで実行すると次のように出力されます。

クリップボード01

DLL 内部で実装された関数内で printf による標準出力をおこなっているので、
その出力もコマンドプロンプトに表示されています。

確かに入力引数で渡した 1 という値が表示されています。
また、C# 側に戻した double 型の値もきちんと受け渡されていることがわかります。
このように単純な数値型であれば
DLL が公開している関数を簡単に導入できます。

DllImport 属性には DLL ファイルのパスを指定する以外に
次のような引数を与えることもできます。

名称 説明
CallingConvention エントリ ポイントの呼び出し規約を示します。
CharSet 文字列パラメーターをメソッドにマーシャリングし、名前マングルを制御する方法を示します。
EntryPoint 呼び出す DLL エントリ ポイントの名前または序数を指定します。

CallingConvention で呼び出し規約を明示的に指定できます。
デフォルトでは __stdcall となっているので、特に使用する必要はないと思います。
CharSet は文字列型を扱うときに使用するかもしれません。
EntryPoint は使用する DLL の関数の名前と
C# 上で使用する関数の名前を異なるものにしたいときに使用します。

これ以外にも細かい設定をおこなうための引数が用意されていますので、
興味がある方は DllImportAttribute クラスを調べてみてください。

次回は文字列型や構造体などの受け渡しの方法について紹介します。