前回はC#で書かれたライブラリの作成方法でしたが、今回は、C#から使えるC++で書かれたライブラリの作成方法です。
実際のところ画像処理プログラムでは、C#で処理を書くことはほとんどなく、処理部分はC++で書かれる事の方が多いのではないでしょうか?(少なくとも自分はそうです。)
正直、C++のライブラリの作成方法はあまり深く理解していないのですが、メモ程度に。。
事前にVisual Studio をデフォルトのままでインストールするとC++はインストールされないので、C++をインストールしておいてください。
まず、関数を呼び出すC#のプロジェクトを作成しておき、ソリューションの右ボタンで、
追加→新しいプロジェクト
を選択します。
次に
Visual C++ → Win32 → Win32プロジェクト
と選択し適当な名前(今回は CppDLL とします。)を付けOKボタンをクリックします。
表示されたウィザードで次へをクリックします。
アプリケーションの種類で DLL を選択し、慣れている人は 空のプロジェクト でいいんでしょうけど、私は慣れていないので、 シンボルのエクスポート と プリコンパイル済みヘッダー にチェックを入れ、完了をクリックします。
今どきのOSはほとんど64bitなので、今回は64bitOS用のライブライを作成するのを前提とします。
Visual Studio の 構成マネージャー をクリックします。
プラットフォームに x64 を選択します。
ビルドの部分いチェックが入っていない場合はチェックを入れます。
これを アクティブソリューションの構成のDebugとReleaseの両方で行います。
これでけで、ソリューションのビルドを行うと、ソリューションフォルダの直下にx64フォルダが作成されます。
さらにその中のReleaseもしくはDebugフォルダの中に、このように↓dllファイルが作成されてますが、C#から、このdllファイルを使うにはさらに細工が必要になります。
以降は、C++プロジェクトの作成時にウィザードが吐き出した
CPPDLL_API int fnCppDll(void);
の関数がC#から使えるようにC++のヘッダファイルを変更します。
C++ライブライのヘッダファイル(ここでは CppDll.h)を開き、C#から使う関数を
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
// ここに使用する関数を定義する
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
のように extern “C” { } で関数の定義を挟み込みます。
こんな感じ↓
#ifdefの部分は、あんまり分かってない。。
次に作成したC++のライブラリファイル(*.dll)がC#から使用できるようにします。
ここは、いくつかやり方があり、好みが分かれるところだと思いますが、今回は、C++のプロジェクトが作成したDLLファイルの出力先をC#の出力先にに合わせるように変更します。
C++のプロジェクト名の部分を右クリックし、
構成のプロパティ→全般→出力ディレクトリ
を
$(SolutionDir)\WindowsFormsApplication1\bin\$(Configuration)\
とします。(※WindowsFormsApplication1はC#のプロジェクト名です。)
この出力ディレクトリの設定を 構成の Release と Debug の両方設定します。
これで、C#のプログラムから参照できる位置(C#のexeファイルと同じフォルダ)にdllファイルが出力されます。
この設定を間違うと、以下のようなエラーが表示されます。
今回は64bitOS用のDLLとして作成していますが、C#のプロジェクトはOSが64bitであってもプロジェクトが初期設定状態だと、32bitで動作するので、これを64bitで動作するように変更します。
C#のプロジェクト名を右クリックし、 プロパティ をクリックし、以下のウィンドウを表示させ、 左側メニューの ビルド を選択し 32ビットを優先のチェックを外します。
この設定を 構成 の Debugおよび Release の両方行います。
この設定を間違うと、 BadImageFormatExceptionはハンドルされませんでした。 というエラーメッセージが表示れます。
これで、とりあえずC#からC++の関数が動作します。
C#からは、以下のようなコードでC++の関数定義を行います。
using System.Runtime.InteropServices;
[DllImport("CppDll.dll")]
public static extern int fnCppDll();
“CppDll.dll”の部分は適宜、作成したdllファイル名に合わせて下さい。
実際に関数を呼び出す部分は、
private void button1_Click(object sender, EventArgs e)
{
int n = fnCppDll();
MessageBox.Show(n.ToString());
}
のように、ボタンクリックイベントで呼び出したとすると、以下のように表示されると動作はOKです。
さらに、これだけど少し足りなくて、C++のプロジェクトのプロパティで、
構成プロパティ→C/C++→コード生成→ランタイムライブラリ
の部分で、構成が
Releaseのとき:マルチスレッド(/MT)
Debugのとき:マルチスレッドデバッグ(/MTd)
に変更しておきます。
この設定をしないと、別のPCでプログラムを実行した際に、開発を行ったVisual Studioと同じバージョンのC++ランタイム(再頒布可能パッケージ)がインストールされていないと動作してくれないので、いざ、実行環境で動作させようとした時にハマったりもします。
以上、少し怪しい部分もあるかと思いますが、こんな感じで。。
コメント