6

マネージ C++ を使用して、いくつかのレガシー C++ ライブラリ用の .Net 呼び出し可能なラッパーを作成することを検討しています。

それはすべて非常に簡単に見えます。何か気をつけることはありますか?

4

5 に答える 5

6

C++/CLI でいくつかの既存の C++ ライブラリをラップするのは一般的に非常に簡単であり、落とし穴も比較的少ないことがわかりました。私が覚えているのは次のとおりです。

  • アンマネージ C++ コードと C++/CLI コードを同じ実行可能ファイル/DLL に混在させることは、非常に悪い考えです。そのように、シャットダウン時に競合するメモリマネージャーで問題に遭遇しました(基本的に、.NETランタイムと通常のC++ランタイムは、シャットダウン時にメモリをクリーンアップする際にお互いのつま先を踏んでおり、結果として非決定論的な動作をもたらしますどちらが何を解放したか)。静的なレガシー C++ ライブラリを C++/CLI ライブラリにリンクする代わりに、レガシー C++ を含む DLL を作成し、それを C++/CLI DLL に対してリンクしました。これにより、問題は完全に解決されました。
  • コードで列挙型を使用している場合は、それらを適切な C++/CLI 列挙型クラスでラップする必要があります。そうしないと、他の .NET 言語がそれらを表示および使用できなくなります。
  • C++/CLI オブジェクトは、アンマネージ C++ オブジェクトへのポインターのみを保持できます。残念ながら、場合によっては、これは、特定のオブジェクトを処理するために薄いラッパー レイヤーを作成する必要があることを意味します。私の「お気に入り」は、boost::shared_ptrs をそのようにラップする (したがって、別の間接レイヤーを追加する) か、.NET/ネイティブの境界を越えた後に null 削除子を使用してそれらを shared_ptrs に配置する必要があることでした。この種のコンストラクトを頻繁に使用する API を処理する必要がある場合は、どちらもあまり良くありません。RAII はこの境界を超えないため、注意してください。.NET の方法に合わせて微調整するには、ある程度の時間を費やす必要があります。
  • C++/CLI は多重継承を行わないため、レガシー ライブラリがそれを利用している場合は、インターフェイスなどを使用してこれをモデル化する必要がある場合があります。
  • 内部マーシャリング コードはほとんどの POD 変換を処理できるようですが、std::strings などを変換する検索/借用コードがあります。現時点で便利なリンクはありません)。
于 2009-01-08T21:00:05.357 に答える
2

それはかなり簡単で、うまく機能します。PInvoke よりもはるかに簡単です。

注意する必要がある大きなことは、プライベート メンバー、メソッド シグネチャなどを含む、マネージド ヘッダーにアンマネージド メンバーがないことです。ただし、マネージド型へのポインターであるプライベート メンバーを使用しても問題ありません。クラス。

また、オブジェクトの有効期間にも注意してください。多くの .NET プログラマは自分でクリーンアップすることに慣れていないため、メモリ リークが発生しやすくなります。作成するラッパー クラスにポインターが含まれている場合は破棄可能であることを確認し、マネージ コードで破棄するようにしてください。マネージ C++ での IDisposable の構文も奇妙ですが、ドキュメントに記載されています。

また、管理対象/非管理対象の境界を越えるたびにわずかなヒットが発生することを忘れないでください。したがって、それに応じてインターフェイスを計画してください。ループ内で何かが繰り返し呼び出される場合は、そのループを境界を越えて移動して、境界を 1 回だけ越えた方がよいでしょう。ただし、何百万もの通話を話している場合を除き、これについてあまり心配する必要はありません。

この記事は逆になりますが、役立つ点がいくつかあります。

ManWrap ライブラリを使用して、ネイティブ C++ コードで .NET を最大限に活用する

こちらもご覧ください

Visual Studio 2005 のマネージ コード
マネージ オブジェクトの削除、ライブラリのラップなど

于 2009-01-08T20:51:15.280 に答える
1

私たちが遭遇したいくつかの問題:

  • メモリ/リソースの有効期間管理 (GC/IDisposable とデストラクタ)。これはよく知られていることだと思いますし、Rob の投稿にはいくつかのことが書かれているので、ここでは詳しく説明しません...
  • 文字列のエンコード/デコード。ネイティブ コードが UNICODE ビルドである場合、これについてあまり心配する必要はありませんが、そうでない場合は、ネイティブ文字列と .Net 文字列の間で変換するときのエンコーディングに注意してください。
  • C++ は [Conditional("Debug")] を尊重しません。つまり、Debug.Assert、Debug.Trace などもリリース ビルドで呼び出されます。代わりに従来の C++ マクロを使用してください。
  • 64 ビットのサポート: .Net はデフォルトで、プラットフォームに応じて 32 ビットまたは 64 ビットのコードを生成しますが、ネイティブ コードはおそらく 32 ビットのみです...
于 2009-01-08T21:00:21.487 に答える
1

みんなが言ったことに付け加えるけど、

pin_ptr wch = PtrToStringChars(文字列); (string は System::String です)

あなたの友達になります。

非マネージド クラスをマネージド クラスに直接含めることはできませんが、アンマネージド クラスへのポインターを配置し、コンストラクターでそれを新規作成し、デストラクターで削除することはできます。

私は、C++ と C++/CLI コードを 1 つの DLL に混在させることに関して、Timo Geusch が言及した問題を経験していません。私の DLL は問題なく両方を広範囲に使用しています。

C++/CLI は (C++ と .NET の知識があれば) 難しくなく、うまく機能します。

于 2009-01-08T22:41:52.063 に答える
1

他の人が言ったように: 98% の確率で動作し、デバッグ可能で、高速です。

これまでに言及した以上に遭遇したこと:

  • すべてのレガシ C++ コードをマネージとしてコンパイルしないでください。それが役立つことを示唆する記事がいくつかありましたが、通常はただ遅いだけです。
  • アンマネージド例外をキャッチし、マネージド例外として再スローすることを忘れないでください。
  • MFC を使用する場合は、.lib ランタイムを使用できないことに注意してください。したがって、MFC ランタイムもデプロイすることになります。
  • OpenMP (スレッド ライブラリ) は C++/CLI では実行されません。
  • C++/CLI dll を独自のコードから C# dll に依存させたとき、VS2005 でいくつかのビルドの問題が発生しました。

C++ コードで単体テストを実行するための C++/CLI コードを書き始めたほど、うまく機能することさえありました。NUnit/Resharper は、C++/CLI DLL でユニット テストを喜んで見つけて実行します。これにより、任意のレベルでネイティブ コードを直接呼び出すことができ、テンプレート コンテナー クラスをテストすることさえできます。

于 2010-02-09T22:06:13.473 に答える