C#から使うC++ライブラリ(DLL)の作成方法

前回はC#で書かれたライブラリの作成方法でしたが、今回は、C#から使えるC++で書かれたライブラリの作成方法です。

C++と言っても、C++内部でクラスを使う事は可能ですが、C#から直接呼ぶ事が出来るのは、クラスではない関数のみとなります。
そのため、クラスオブジェクトをC++のライブラリとC#間でやり取りすることは出来ないので、注意してください。(構造体を引数で渡す事は可能です。)

 

正直、C++のライブラリの作成方法はあまり深く理解していないのですが、メモ程度に。。

 

事前にVisual Studio をデフォルトのままでインストールするとC++はインストールされないので、C++をインストールしておいてください。

 

まず、関数を呼び出すC#のプロジェクトを作成しておき、ソリューションの右ボタンで、

追加→新しいプロジェクト

を選択します。

 

次にプロジェクトを追加しますが、Visual Studio のバージョンにより画面が異なるため、各バージョンに合わせて確認ください。

Visual Studio 2017, 2019の場合

Visual Studio 2019には、上部に言語、OS別表示のフィルタをかけることが出来るので、C++、Windowsを選択します。

次にプロジェクトの一覧の中から Windowsデスクトップウィザードを選択します。

次にプロジェクト名とプロジェクトの場所を指定します。
プロジェクト名は、デフォルト設定ではライブラリ名になるので、ちゃんとした名前を付ける事をお勧めします。

次に アプリケーションの種類に ダイナミックリンクライブラリ(.dll) を選択し、追加オプションでは、
プリコンパイル済みヘッダー(P)シンボルのエクスポートにチェックを入れます。

→以降は、以下共通を参照ください。

Visual Studio 2015の場合

Visual C++ → Win32 → Win32プロジェクト

と選択し適当な名前(今回は CppDLL とします。)を付けOKボタンをクリックします。

 

表示されたウィザードで次へをクリックします。

 

アプリケーションの種類で DLL を選択し、慣れている人は 空のプロジェクト でいいんでしょうけど、私は慣れていないので、 シンボルのエクスポート と プリコンパイル済みヘッダー にチェックを入れ、完了をクリックします。

以下共通

ウィザードでDLLを作成すると、プログラムのたたき台となるサンプルコードを吐き出してくれるので、慣れないうちは、ウィザードを使った方がお勧めです。(私は、今でも使ってますが。。)

 

次にプロジェクトの設定を行います。

 

今どきのOSはほとんど64bitなので、今回は64bitOS用のライブライを作成するのを前提とします。

Visual Studio の 構成マネージャー をクリックします。

 

プラットフォームに x64 を選択します。

ビルドの部分いチェックが入っていない場合はチェックを入れます。

これを アクティブソリューションの構成のDebugReleaseの両方で行います。

 

これでけで、ソリューションのビルドを行うと、ソリューションフォルダの直下に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++ランタイム(再頒布可能パッケージ)がインストールされていないと動作してくれないので、いざ、実行環境で動作させようとした時にハマったりもします。

 

以上、少し怪しい部分もあるかと思いますが、こんな感じで。。

 

関連記事

【C#エラー】System.BadImageFormatException 間違ったフォーマットのプログラムを読み込もうとしました。

C#ライブラリ(DLL)の作成方法

C#から使う、C#で書かれたライブラリ(*.dll)の作成方法です。
C#から使う、C言語ライブラリの作成方法はこちらを参照ください。

 

まず、ライブラリを呼び出す側のプロジェクトを作成します。

 

ここでは、Windowsフォームアプリケーションを作成するのに、

テンプレート→Visual C#→Windows→Windowsフォームアプリケーション

と選択し、名前を適当に付けてOKボタンをクリックします。

 

これで、呼び出し側のプロジェクトが作成されました。

 

次に、C#ライブラリ用のプロジェクトを作成します。

今、作成したプロジェクトの1つ上の階層に作成されている ソリューション の文字を右クリックし、

追加→新しいプロジェクト

を選択します。

 

今度はライブラリを作成するので、

  Visual C#→Windows→クラスライブラリ

と選択し、名前を適当に付けてOKボタンをクリックします。

 

すると、最小限のコードが生成されます。

 

通常は、Class1とかいうクラス名ではなく、もっとわかりやすい名前に変えますが、とりあえず、このまま次に進みます。

 

次に、2つの値を足すだけの簡単なメソッドを追加してみます。

 

この状態で、ビルドすると、ライブラリのプロジェクトフォルダのbinフォルダのDebugもしくはReleaseフォルダの中にライブラリファイル(CSharpDll.dll)が作成されます。

 

しかし、それだけだと、ライブラリを呼び出す元のプロジェクト(ここではWindowsFormsApplication1)からは使う事ができないため、参照の設定を行います。

 

参照は呼び出す元の方のプロジェクトにある、参照の文字を右クリックし、参照の追加を選択します。

 

ここで、ライブラリファイルを選択する方法もあるのですが、プログラム作成中はライブラリのプロジェクトを参照した方がデバッグ等が便利なので、プロジェクトの参照を行います。

 

  プロジェクト→ソリューション

 

と選択すると、ライブラリのプロジェクト名が表示されているので、プロジェクト名の左側にあるチェックボックスにチェックを入れ、OKボタンをクリックします。

 

これで、参照元に参照先のライブラリ名(ここではCSharpDll)が追加され、ライブラリが使用できる状態になります。

 

 

試しにフォーム上にボタンを配置します。

 

 

ボタンをダブルクリックし、作成されたクリックイベント内に、今、作成したライブラリのメソッドを追加してみます。

 

これで、ボタンをクリックした時に、以下のように表示されれば、C#ライブラリの作成は成功です。

 

ここでは、ライブラリのプロジェクトの参照として行いましたが、こうすることで、ライブラリのメソッド内へのステップイン実行もできるようになるので、かなり便利です。

 

一つポイントとしては、デフォルトのまま、ライブラリを作成すれば特に問題は無いのですが、ライブラリのプロジェクトのプラットフォームはAnyCPUにしておくのをお勧めします。

 

こうしておく事で、呼び出し元のプロジェクトがx86だろうが、x64であっても、同一のライブラリファイル(ここではCSharpDll.dll)を使用することができるようになります。

これを間違うと、x86用のdllファイル、x64用のdllファイルのそれぞれを作成する必要が出てくるので、少々面等になります。