59

背景:大規模な課題の一環として、C# ライブラリをアンマネージ C++ および C コードにアクセスできるようにする必要があります。この質問に自分で答えるために、私はここ数日/数週間 C++/CLI を学んでいます。

アンマネージ C++ および C から C# dll を使用して実現するには、さまざまな方法があるようです。簡単に言えば、Interlope サービスを使用する、.com を使用するなどの答えがいくつかあります。regasm、PInvoke の使用 (C# から C++ のみに移行するように見える)、および C++/CLR での IJW の使用 (Interlope サービスのように見える)。ネイティブ C++ および C コードの代わりに IJW を使用して C# dll を呼び出す CLR ラッパーであるライブラリをセットアップするのが最善だと考えています。

詳細:文字列と int の値を C++ コードから C# dll に渡し、void を返す必要があります。

関連性:多くの企業には、C++、C、および C# を組み合わせて使用​​する言い訳がたくさんあります。パフォーマンス: 通常、アンマネージ コードの方が高速です。インターフェイス: 管理されたインターフェイスは、一般的に保守、展開が容易で、多くの場合、見た目も簡単です。レガシー コードも私たちを強制します。そこにあった(登った山のように)。C# から C++ ライブラリを呼び出す方法の例は豊富にあります。C++ コードから C# ライブラリを呼び出す方法の例は、特に更新された 4.0 以降のコードを見たい場合、Google で見つけるのは困難です。

ソフトウェア: C#、C++/CLR、C++、C、Visual Studio 2010、.NET 4.0

質問の詳細: OK マルチパート質問:

  1. com オブジェクトを使用する利点はありますか? それともPInvoke?それとも他の方法ですか?(Google Land でこのトピックに関する詳細情報を見つけたとしても、ここでの学習曲線は同じように急勾配になると思います。IJW は、私がやりたいことを約束しているようです。IJW ソリューションを探すことをあきらめて、代わりにこれに焦点を当てますか?) (長所/短所?)

  2. C++/CLR で IJW を利用するラッパーを作成するソリューションがあると想像するのは正しいですか? このトピックに関する詳細情報はどこで見つけることができますか。また、Google で十分に検索できなかったとは言わないでください。または、どこで見たかを言わずに MSDN を調べてください。(明確でシンプルなコードを書くために、私はこのオプションを好むと思います。)

  3. 質問の範囲を狭める: 私の本当の問題と必要性は、次の小さな質問に答えることだと思います: アンマネージ C++ ファイルがビジュアル スタジオ内で使用できる C++/CLR ライブラリを設定するにはどうすればよいですか。マネージ C++ クラスをアンマネージ C++ コードで簡単にインスタンス化できれば、残りの作業 (インターフェースやラッピングなど) を解決できると思います。私の主な愚かさは、Visual Studio 内で参照/#includes などを設定しようとすることにあると思いますが、他の誤解がある可能性があることは明らかです。おそらく、この全体に対する答えは、これを支援するチュートリアルまたは指示へのリンクにすぎない可能性があります.

調査:私はグーグルとビンジングを何度も繰り返し、ある程度の成功を収めました。C# コードからアンマネージ ライブラリを使用する方法を示す多くのリンクを見つけました。また、com オブジェクトを使用してそれを行う方法を示すリンクがいくつかあることを認めます。VS 2010 を対象とした結果はあまりありません。

参考文献: 私は多くの投稿を何度も読みました。私は最も関連性の高いものを試してみました。興味をそそられるほど答えに近いものもありますが、私はそれらを機能させることができないようです。キーワード ref の誤用、#include または using ステートメントの欠落、名前空間の誤用、実際に IJW 機能を適切に使用していない、または VSコンパイルを正しく処理する必要があります。私は、自分が動作しなければならないコードを理解して期待している場所にいないような気がします。私はそれを理解できる場所に行きたいと思っています。ランダムに 2 つのリンクを含めますが、現在のヒットポイント レベルではすべてを表示することはできません。

http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod

これは、C++ から Visual Basic へ、そして C++CLR 経由で戻る双方向で、マネージ コードとアンマネージ コードからコードを呼び出します。もちろん、私は C# に興味があります。 -管理されたコードから管理されていないコードと副

4

6 に答える 6

43

これはかなり簡単に行うことができます。

  1. .h/.cpp コンボを作成する
  2. 新しく作成した .cpp ファイルで /clr を有効にします。(CPP -> 右クリック -> プロパティ)
  3. C# dll を指すように「追加の #using ディレクトリ」の検索パスを設定します。

Native.h

void NativeWrapMethod();

ネイティブ.cpp

#using <mscorlib.dll>
#using <MyNet.dll>

using namespace MyNetNameSpace;

void NativeWrapMethod()
{
    MyNetNameSpace::MyManagedClass::Method(); // static method
}

これは、ネイティブ コードで C++\CLI から C# ライブラリを使用する基本です。(必要に応じて Native.h を参照し、関数を呼び出します。)

マネージ C++\CLI コードで C# コードを使用することは、ほぼ同じです。

この件に関しては多くの誤った情報があります。:)


VS2010 - VS2012 (おそらく VS2008 でも動作します。)

于 2012-11-16T00:16:43.930 に答える
26

2018年更新

ソリューションが Visual Studio 2017 以降では機能しないようです。残念ながら、私は現在 Visual Studio を使用していないため、この回答を自分で更新することはできません。しかし、ケイリーは私の答えの更新版を投稿しました、ありがとう!

更新終了

COM を使用する場合、この問題に対する私の解決策は次のとおりです。

C# ライブラリ

まず、COM 互換ライブラリが必要です。

  • あなたはすでにそれを手に入れましたか?完璧です。この部分はスキップできます。

  • ライブラリにアクセスできますか?手順に従って、COM 互換であることを確認します。

    1. プロジェクトのプロパティで [COM 相互運用機能に登録する] オプションがオンになっていることを確認してください。プロパティ -> ビルド -> 下にスクロール -> COM 相互運用に登録

次のスクリーンショットは、このオプションがある場所を示しています。

スクリーンショット プロジェクト プロパティ ビルド

  1. 使用可能にする必要があるすべてのインターフェイスとクラスには、 GUIDが必要です

    namespace NamespaceOfYourProject
    {
        [Guid("add a GUID here")]
        public interface IInterface
        {
            void Connect();
    
            void Disconnect();
        }
    }
    
    namespace NamespaceOfYourProject
    {
         [Guid("add a GUID here")]
         public class ClassYouWantToUse: IInterface
         {
             private bool connected;
    
             public void Connect()
             {
                 //add code here
             }
    
             public void Disconnect()
             {
                 //add code here
             }
         }
    }
    

以上が、C# コードで行う必要があることのほとんどです。C++ コードを続けましょう。

C++

  1. まず、C# ライブラリをインポートする必要があります。

C# ライブラリをコンパイルすると、.tlb ファイルが作成されます。

#import "path\to\the\file.tlb"

この新しく作成されたファイルを file.cpp にインポートすると、オブジェクトをローカル変数として使用できます。

#import "path\to\the\file.tlb"

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);

    NamespaceOfYourProject::IInterfacePtr yourClass(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));

    yourClass->Connect();

    CoUninitialize();
}
  1. クラスを属性として使用します。

最初のステップはローカル変数でのみ機能することに気付くでしょう。次のコードは、それを属性として使用する方法を示しています。この質問に関連しています。

atlcomcli.h にある CComPtr が必要になります。このファイルをヘッダー ファイルに含めます。

CPlusPlusClass.h

#include <atlcomcli.h> 
#import "path\to\the\file.tlb"

class CPlusPlusClass
{
public:
    CPlusPlusClass(void);
    ~CPlusPlusClass(void);
    void Connect(void);

private:
    CComPtr<NamespaceOfYourProject::IInterface> yourClass;
}

CPlusPlusClass.cpp

CPlusPlusClass::CPlusPlusClass(void)
{
    CoInitialize(NULL);

    yourClass.CoCreateInstance(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));

}

CPlusPlusClass::~CPlusPlusClass(void)
{
    CoUninitialize();
}

void CPlusPlusClass::Connect(void)
{
    yourClass->Connect();
}

それでおしまい!COM を使用して C++ で C# クラスを楽しんでください。

于 2015-05-01T14:26:16.587 に答える
16

これを行うための絶対的な最善の方法は、c# コードをネイティブ C++ に接続する c++/cli ブリッジを作成することです。これは、3 つの異なるプロジェクトで実行できます。

  • 最初のプロジェクト: C# ライブラリ
  • 2 番目のプロジェクト: C++/CLI ブリッジ (これは C# ライブラリをラップします)
  • 3 番目のプロジェクト: 2 番目のプロジェクトを使用するネイティブ C++ アプリケーション

私は最近、これを行う方法について簡単な GitHub チュートリアルを作成しまし。そのコードを少し理解すれば、ネイティブ C++ で C# コードを使用できるようにする C++/CLI ブリッジを作成することができるはずです。

おまけとして、サブスクライブできる C++ の関数ポインターに C# イベントをラップする方法を追加しました。

于 2014-08-20T16:44:59.117 に答える
4

少なくとも私自身の質問に答え始める何かを見つけました。次の 2 つのリンクには、アンマネージ C++ で C# クラスを使用する方法を示す Microsoft の wmv ファイルがあります。

この最初のものは、COM オブジェクトと regasm を使用します: http://msdn.microsoft.com/en-us/vstudio/bb892741

この 2 つ目は、C++/CLI の機能を使用して C# クラスをラップします: http://msdn.microsoft.com/en-us/vstudio/bb892742。ビデオのように、マネージ コードから ac# クラスをインスタンス化し、文字列を取得することができました。非常に役に立ちましたが、文字列境界を持つクラスを ac# クラスにインスタンス化したいので、私の質問の 2/3 しか答えません。概念実証として、次のメソッドの例に示されているコードを変更し、この目標を達成しました。もちろん、{public string PickDate(string Name)} メソッドを変更して名前文字列を処理し、それが機能することを自分自身に証明することも追加しました。

wchar_t * DatePickerClient::pick(std::wstring nme)
{
    IntPtr temp(ref);// system int pointer from a native int
    String ^date;// tracking handle to a string (managed)
    String ^name;// tracking handle to a string (managed)
    name = gcnew String(nme.c_str());
    wchar_t *ret;// pointer to a c++ string
    GCHandle gch;// garbage collector handle
    DatePicker::DatePicker ^obj;// reference the c# object with tracking handle(^)
    gch = static_cast<GCHandle>(temp);// converted from the int pointer 
    obj = static_cast<DatePicker::DatePicker ^>(gch.Target);
    date = obj->PickDate(name);
    ret = new wchar_t[date->Length +1];
    interior_ptr<const wchar_t> p1 = PtrToStringChars(date);// clr pointer that acts like pointer
    pin_ptr<const wchar_t> p2 = p1;// pin the pointer to a location as clr pointers move around in memory but c++ does not know about that.
    wcscpy_s(ret, date->Length +1, p2);
    return ret;
}

私の質問の一部は次のとおりでした。私が調査に多くの努力を払って読んだことから、その答えは、COM オブジェクトの方が使いやすいと考えられており、代わりにラッパーを使用すると、より優れた制御が可能になるということです。COM オブジェクトは自動的に標準サイズのフットプリントを持ち、ラッパーは必要なだけ大きくなるため、場合によっては、ラッパーを使用するとサンクのサイズを縮小できます (常にではありません)。

サンク (上で使用したように) は、COM オブジェクトの場合は C# と C++ の間、C++/CLI を使用したコーディングの場合は C++/CLI とネイティブ C++ の間で使用される空間時間とリソースを指します。ラッパー。したがって、私の回答の別の部分には、絶対に必要以上にサンク境界を越えることは悪い習慣であり、ループ内でサンク境界にアクセスすることはお勧めできません。 (サンクが 1 つだけ必要な境界を 2 回越えます) 私のような初心者にはコードが間違っているようには見えません。

wmv についての 2 つのメモ。まず、一部の映像は両方で再利用されています。だまされないでください。最初は同じように見えますが、カバーするトピックは異なります。第 2 に、wmv ではカバーされていない、現在 CLI の一部であるマーシャリングなどのいくつかのボーナス機能があります。

編集:

インストールには結果があることに注意してください。CLR は C++ ラッパーを見つけられません。C++ アプリケーションが、それを使用するすべてのディレクトリにインストールされることを確認するか、インストール時にライブラリ (厳密な名前を付ける必要があります) を GAC に追加する必要があります。これはまた、開発環境ではどちらの場合でも、アプリケーションがライブラリを呼び出す各ディレクトリにライブラリをコピーする必要がある可能性が高いことを意味します。

于 2012-12-11T15:59:12.627 に答える
0

私は周りを見回して、それがどのように行われるかを詳述しているマイクロソフトの比較的最近の記事を見つけました(多くの古い情報が浮かんでいます)。記事自体から:

コード サンプルでは、​​CLR 4 ホスティング API を使用してネイティブ C++ プロジェクトで CLR をホストし、.NET アセンブリを読み込んで呼び出します。

https://code.msdn.microsoft.com/CppHostCLR-e6581ee0

基本的には、次の 2 つのステップで説明します。

  1. CLR をプロセスにロードする
  2. アセンブリをロードします。
于 2016-10-16T23:02:43.343 に答える