C# で実装する必要がある C++ で定義したインターフェイスがあります。これについて最善の方法は何ですか?インターフェイス定義で COM をまったく使用したくありません。私が今これを解決した方法は、C++ と C# の 2 つのインターフェイス定義を持つことです。次に、C# インターフェイスを COM サーバーとして公開します。これは、C++ で記述され、C# を呼び出すことができる私のアプリケーションでした。C# だけでなく C++ で実装を定義する必要を回避できる方法はありますか?
6 に答える
マネージ コードに C# の代わりに C++/CLI を使用する場合は、ヘッダー ファイルを介して直接ネイティブ C++ インターフェイス定義を使用できます。これがどれほど簡単かは、インターフェイスの内容によって異なります。最も単純なケースは、C から使用できるものです。
Marcus Heege のExpert C++/CLI: .NET for Visual C++ Programmersを参照してください。.NET でのネイティブ C++ とマネージ C++ の混在に関する多くの役立つ情報があります。
Swigは、C# などの他の言語で C++ クラスをラップするための優れたツールです。
COMを使いたくないのはなぜですか?
これが私の提案だったでしょう。COM相互運用機能は私にとって非常にうまく機能し、C#でCOMオブジェクトとインターフェイスを使用しました(COMオブジェクトを参照するだけで、ランタイム呼び出し可能ラッパーが自動的に作成されます)。同様に、C#クラスを「COM相互運用機能の登録」としてマークすると、逆の方法で機能します。
もう 1 つのアプローチは、「フラットな」C スタイルの API を使用することです。extern "C"
偶発的な過負荷を防ぐために使用することもできます。DEF ファイルを使用して、エクスポートされた関数に明示的に名前を付けます。これにより、関数は決して装飾されません (C++ 関数は、エクスポート テーブルのパラメーター タイプのエンコーディングで「装飾」されます)。
x86 では、呼び出し規約に注意してください。おそらく__stdcall
orの使用を明示的に宣言することです__cdecl
。P/Invoke は主に Windows API を呼び出すために使用されるため、既定値は StdCall ですが、C および C++ の既定値は cdecl です。これは、varargs がサポートされているためです。
最近IRapiStream
、.NET が IStream をストレージに変換しようとしているように見えたため、COM インターフェイスをフラット C インターフェイスにラップしましたが、エラーで失敗しましたSTG_E_UNIMPLEMENTEDFUNCTION
。
C++ でインターフェイスを記述し、マクロを使用して、UNIX では標準の cpp ヘッダー ファイルのように、Windows では IDL ファイルのように見えるようにします (これがうまくいかない場合は、いつでも python/ruby スクリプトを記述して、 C++ ヘッダー ファイル)。
IDL をコンパイルして typelib を生成します。TypeLib Importer を使用して、C# のインターフェイス定義を生成し、そこにインターフェイスを実装します。
使用している .NET のバージョンについては言及されていませんが、Visual Studio .NET 2003 を使用してうまくいったことは、実際の C++ クラスの単純な実装の周りに薄い C# ラッパーを提供することです。
public __gc class MyClass_Net {
public:
MyClass_Net()
:native_ptr_(new MyClass())
{
}
~MyClass_Net()
{
delete native_ptr_;
}
private:
MyClass __nogc *native_ptr_;
};
明らかに、Boost shared_ptr を使用したいのですが、V.NET 2003 でうまく動作させることはできませんでした...
メソッドは、ポインターを介して基になる C++ メソッドに単純に転送されます。メソッドの引数を変換する必要がある場合があります。たとえば、文字列を受け取る C++ メソッドを呼び出すには、C# メソッドはおそらく System.String (Managed C++ では System::String) を受け取る必要があります。これを行うには、System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi() を使用する必要があります。
このアプローチの利点の 1 つは、Managed C++ が .NET 言語であるため、アクセサーをプロパティ (__property) として公開できることです。C# のように、属性を公開することもできます。