delete from hateblo.jp where 1=1;

タイトルに意味はありません。

C++とC#

対象

  • 衝動的にC++(native)を動かしたい人
  • dryな関係で居たい人
  • 再配布パッケージをインストールしたくない人

結論

以下のような構成をとることが多い。

構成
  • C#プロジェクト
    • ラッパープロジェクトを参照する
  • C# C++ラッパープロジェクト
    • 出力先に注意すること(C++のDLLがないと実行時エラーとなる)
  • C++プロジェクト

※Cインターフェイスを記述することで、名前が固定され、ラッパーからの呼び出しが比較的安全で、わかりやすくなる
気が向いたらサンプルプロジェクトをGistにでも記載するのと、文字列(配列)の扱いについていくつか記載する。

説明

C++プロジェクトについて

.NET 互換CLIライブラリをC++側で書くのが一番の近道。
しかし、CLIライブラリは/MD(動的リンク:マルチスレッド)のみ、/MT(静的リンク:マルチスレッド)には対応していない。[要出典]
動的リンクとしたとき、再配布パッケージは必須となってしまう。[要出典]
再配布パッケージを使用しないようにするためには、/MDを指定しなくてはならない。

Visual Studio 2015 (v140)からは再配布パッケージに使用されるvcruntime.dllの依存関係が多くなってしまったこと(マージモジュールになったから?)により、再配布をするにはパッケージが必要になってしまったように見受けられる。
以前はmsvcr120.dll単体+αで事足りていた。(Windows 7をターゲットとする場合)

Visual Studio Platform Toolset DLL .NET
2015 v140 vcruntime.dll 4.5.2/4.6
2013 v120 msvcr120.dll 4.5.1
2012 v110 msvcr110.dll 4.5
コールバックをC++側に渡すときの注意点

以下のようなコードがあったとする。

var cls = CPlusPlusMethod_Factory();
CPlusPlusMethod(cls, new Action(()=>DoSomething()));

Actionがメソッドを抜ける前に実行され、参照されなくなるなら、問題はないが、
たいていはコールバックとして関数を登録しているケースが多い。
マネージドコードからアンマネージドコードへコールバックを渡すだけでは、
参照が増えず、即座にGCされてしまい、不正アクセスの例外が発生する。
そのため、以下のようにC++側のコードが生きている間は、コールバックを参照として保持すべき。

var avoidgc = new List<Delegate>();
var cls = CPlusPlusMethod_Factory();
var action = new Action(()=>DoSomething());
avoidgc.Add(action);
CPlusPlusMethod(cls, action);

※上記記述はrubyの何かの記事のパクリです。出典を探し出せなくて困っているので、後日見つけたらリンクします