65

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

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

私を助けるためにそこに何かありますか?これは私には不合理に思えません。

編集m3rLinEz ソリューションを試しましたが、BadImageFormatException が発生しました。DLL が生成されていないためだと思います。私は言われたとおりにすべてをしました、私は何が起こったのか分かりません。何か案は?

4

4 に答える 4

57

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

非常に短い例を挙げましょう。これは、Visual C++->CLR->クラスライブラリプロジェクトのソースファイルです。基本的にWindowsのユーザー名を取得して返します。

これをコンパイルするには、プロジェクト設定に移動し、「追加の依存関係」を「親から継承」としてマークする必要があることに注意してください。これらの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++ライブラリのマネージラッパーを作成できます。String^CLR文字列への参照型を定義するなど、いくつかの奇妙な構文があります。ここでは、 「クイックC ++/CLI-10分未満でC++/CLIを学ぶ」が役立つと思います。

于 2010-02-06T03:55:22.917 に答える
9

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

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

職場では、これに C++/CLI を使用していますが、うまくいくようです。

于 2010-02-06T09:16:18.337 に答える
4

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

その記事の重要なポイント:

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

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

もう 1 つの選択肢は、It Just Works (IJW) です。C++ コードを管理しており、他の .NET 言語からこれにアクセスする必要がある場合は、おそらくこれが適切な選択です。ただし、これは、アンマネージド C++ をマネージド C++ に変換できる/喜んで変換できる場合にのみ選択できます。

于 2010-02-06T03:24:29.287 に答える
4

P/Invoke は IJW (It Just Works) に比べてかなり遅いので、私は遠ざけます。後者を使用すると、マネージドとアンマネージドの 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 を使って作業することができます。C++/CLI は学ぶのがとても楽しく、洗練されたものです。VS 2003 から長い道のりを歩み、今では完全な機能を備えた .NET 言語です。すべての IJW 情報と同様に、Microsoft のドキュメントは非常に優れています。
  • C++/CLI で C++ 相互運用を行うことは、C# とは対照的に非常に自然に感じられます。これは完全に主観的なものですが、私は C++ で文字列のマーシャリングを行いたいと思っていますMarshal.PtrToString(ptr)
  • API を公開する場合は、おそらくすべての P/Invoke を別のレイヤーにラップする必要があるため、P/Invoke の醜さに対処する必要はありません。このようにして、すべてのマーシャリングとその周りの C# レイヤーのオーバーヘッドが発生します。C++/CLI では、マーシャリングと相互運用の抽象化が 1 か所にあり、必要なマーシャリングの量を選択できます。

Windows SDK で奇妙な関数を呼び出している場合は、P/Invoke を使用してください。適度に複雑な C++ API を管理対象の世界に公開する場合は、間違いなく C++/CLI です。

于 2010-02-06T03:30:05.420 に答える