web-dev-qa-db-ja.com

C#からC ++ / CLIを呼び出すにはどうすればよいですか?

プログラムの算術計算を担当するC++で実装されたクラスと、WPFを使用するインターフェイスがあります。 C#で入力を処理しますが、C++クラスを使用するにはどうすればよいですか?

マネージC++ラッパークラスを作成してそれとやり取りすることについていくつかのコメントを見てきましたが、どこから始めればいいのかわかりません。他のすべてのコードと一緒にコンパイルする方法もわかりません。私はこれに関するチュートリアルを本当に見つけることができず、マネージドC++でGoogleが表示するものは実際には役に立たないようです。

私を助けるためにそこに何かありますか?これは私には不合理ではないようです。

[〜#〜] edit [〜#〜] m3rLinEzソリューションを試しましたが、BadImageFormatExceptionが発生しています。DLLが生成されていないためだと思います。言われた通り、何が起こったのか分からない。

64
master chief

C++/CLIをご覧になりましたか?

非常に短い例を挙げましょう。 Visual C++-> CLR-> Class Libraryプロジェクトのソースファイルを次に示します。基本的にWindowsユーザー名を取得して返します。

これをコンパイルするには、プロジェクト設定に移動し、「Additional Dependencies」を「Inherit from parent」としてマークする必要があります。これらのWindowsライブラリ(kernel32.lib、user32.lib、..)を使用しているためです。

// CSCPP.h

#pragma once

#include "windows.h"

using namespace System;

namespace CSCPP {

    public ref class Class1
    {
        // TODO: Add your methods for this class here.
    public:
        String^ GetText(){
            WCHAR acUserName[100];
            DWORD nUserName = sizeof(acUserName);
            if (GetUserName(acUserName, &nUserName)) {
                String^ name = gcnew String(acUserName);
                return String::Format("Hello {0} !", name);
            }else{
                return gcnew String("Error!");
            }
        }
    };
}

新しいC#プロジェクトを作成し、最初のC++/CLIクラスライブラリプロジェクトへの参照を追加します。次に、インスタンスメソッドを呼び出します。

namespace CSTester
{
    class Program
    {
        static void Main(string[] args)
        {
            CSCPP.Class1 instance = new CSCPP.Class1();
            Console.WriteLine(instance.GetText());
        }
    }
}

これにより、私のマシンで次の結果が得られました。

こんにちはm3rlinez!

C++/CLIは、基本的にC++標準に対するマネージ拡張です。 C++/CLIプロジェクトでCLRクラスとデータ型を利用し、これをマネージ言語に公開することもできます。これを使用して、古いC++ライブラリのマネージラッパーを作成できます。 CLR文字列への参照型を定義するString^などの奇妙な構文がいくつかあります。 「クイックC++/CLI-10分未満でC++/CLIを学ぶ」 がここで役立つことがわかりました。

56
Gant

同じプロセスでマネージからアンマネージコードを呼び出すには、少なくとも3つの方法があります。

  1. C++/CLI
  2. プラットフォーム呼び出し
  3. C++をCOMオブジェクトでラップする

職場ではこのためにC++/CLIを使用していますが、動作しているようです。

9
Arve

標準の(非COM /マネージド)ダイナミックリンクライブラリを ここで説明 として作成し、C#コードで DllImport属性 (プラットフォーム呼び出し)を使用して、エクスポートされた関数にアクセスします。

その記事からのキーポイント:

このコードのメソッド宣言の__declspec(dllexport)修飾子に注意してください。これらの修飾子により、メソッドをDLLによってエクスポートできるため、他のアプリケーションで使用できます。詳細については、dllexport、dllimportを参照してください。

これは、実際のCOM相互運用ラッパーに代わる軽量の代替手段であり、登録などの問題を回避します(DLLはアプリケーションディレクトリに簡単に配置できます)。

別の選択肢は It Just Works (IJW)です。 C++コードを管理していて、他の.NET言語からこれにアクセスする必要がある場合、これはおそらくより良い選択です。ただし、これは、アンマネージC++をマネージC++に変換することができる場合は、オプションにすぎません。

4
Ash

I/JW(It Just Works)と比べるとかなり遅いので、P/Invokeには近づかないでしょう。後者では、マネージドC++とアンマネージドC++をシームレスに織り交ぜることができます。必要なことは、マネージc ++アセンブリを作成し、c#から表示できるマネージクラスを作成し、そこからアンマネージコードを呼び出すことだけです。

ええと...はい。私は、P/Invoke呼び出しが本来より遅くなるという印象を受けました。ただし、マーシャリングを明示的に制御することにより、多くの場合でC++/CLIバージョンのパフォーマンスを向上させることができます。

両方のメカニズムに関するMicrosoftの記事は次のとおりです。

http://msdn.Microsoft.com/en-us/library/ms235282.aspx

IJWの利点

  • プログラムが使用するアンマネージAPIのDLLImport属性宣言を記述する必要はありません。ヘッダーファイルを含めて、インポートライブラリとリンクするだけです。
  • IJWメカニズムはわずかに高速です(たとえば、IJWスタブは、開発者によって明示的に行われるため、データ項目を固定またはコピーする必要があるかどうかを確認する必要はありません)。
  • パフォーマンスの問題を明確に示しています。この場合、Unicode文字列からANSI文字列に変換していること、および付随するメモリの割り当てと割り当て解除があること。この場合、IJWを使用してコードを記述する開発者は、_putwsを呼び出してPtrToStringCharsを使用するとパフォーマンスが向上することを認識します。
  • 同じデータを使用して多くのアンマネージAPIを呼び出す場合、一度マーシャリングしてマーシャリングされたコピーを渡すことは、毎回再マーシャリングするよりもはるかに効率的です。

審美的な利点もあります:

  • C#コードは、相互運用性を備えたC#コードのように見えます。
  • DLLImport属性を定義する必要はありません。次のようなデータ構造(p/invoke特定の属性も含む)を定義する必要はありません。

    [StructLayout(LayoutKind.Sequential、CharSet = CharSet.Ansi)] public struct DevMode {[MarshalAs(UnmanagedType.ByValTStr、SizeConst = 32)] public string dmDeviceName; }

  • すべてのパラメータープリミティブ型を対応する.NETの対応する型に変換する必要はありません(マネージ型がアンマネージ型にマップされる方法をリストする このページ に表があります)。
  • C++/CLIを使用して作業することができます。これは、学ぶのが本当に楽しく、洗練されています。 VS 2003から長い道のりを経て、完全な機能を備えた.NET言語になりました。すべてのIJW情報と同様に、Microsoftのドキュメントは非常に優れています。
  • C++/CLIでC++相互運用を行うことは、C#とは対照的に非常に自然に感じられます。これは完全に主観的なものですが、C++でMarshal.PtrToString(ptr)を実行する文字列マーシャリングを実行したいです。
  • APIを公開する場合は、おそらくすべてのP/Invokeを別のレイヤーにまとめる必要があるため、P/Invokeのlinesさを扱う必要はありません。この方法では、すべてのマーシャリングとその周囲のC#レイヤーのオーバーヘッドがあります。 C++/CLIを使用すると、マーシャリングと相互運用の抽象化が1か所にまとめられ、必要なマーシャリングの量を選択できます。

私見Windows SDKで奇妙な関数を呼び出す場合は、P/Invokeを使用します。やや複雑なC++ APIをマネージドワールドに公開している場合は、間違いなくC++/CLIを使用してください。

3
Igor Zevaka