5

foo.dll に次の C++ クラスがあるとします。

class a{
  private:
    int _answer;

  public:
    a(int answer) { _answer = answer; }
    __declspec(dllexport) int GetAnswer() { return _answer; }
}

C# から pInvoke GetAnswer を使用したいと思います。そのために、次の方法を使用します。

[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint= "something")]
public static extern int GetAnswer(IntPtr thisA);

そして、a を指す IntPtr を渡します (別の場所から取得したもので、重要ではありません)。 CallingConvention = CallingConvention.ThisCall正しく処理されていることを確認します

この質問の素晴らしいところは、すでにうまく機能しているので、これまでのところ自分が正しいことを知っているということです! Depends.exe を使用すると、"GetAnswer" が ?GetAnswer@a@@UAEHXZ としてエクスポートされていることがわかります (またはそれに近いもの - ポイントは、名前がマングルされていることです)。マングルされた名前を EntryPoint の「何か」に差し込むと、すべてがうまく機能します! Depends.exe を使用できるようになるまでに約 1 日かかりました。そのため、同様の問題を抱えている人の助けとしてここに残しておきます。

私の本当の質問は次のとおり です。 GetAnswer で C++ の名前マングリングを無効にして、マングルされた名前をエントリ ポイントとして入力する必要がないようにする方法はありますか。名前のマングリングについての私の理解は、コンパイラが変更されると変更される可能性があるためです。また、pInvoke するすべてのインスタンス メソッドに Depends.exe を使用するのは面倒です。

編集:私が試したことを追加するのを忘れました:定義に貼り付けることができますが、関数宣言にextern "C"を置くことができないようです。ただし、これは役に立たないようです (考えてみれば明らかです)。

私が考えることができる他の唯一の解決策は、インスタンス メソッドをラップし、a のインスタンスをパラメーターとして受け取る c スタイルの関数です。次に、そのラッパーで名前マングリングを無効にし、それを pInvoke します。ただし、すでに持っているソリューションに固執したいと思います。私は同僚に pInvoke が素晴らしいことをすでに伝えました。pInvoke を機能させるためだけに C++ ライブラリに特別な関数を入れなければならないとしたら、私はばかみたいに見えるでしょう。

4

4 に答える 4

1

関数自体がどのように宣言されているかについて実際に多くの情報を含むマングルされた名前を無効にする必要はありません。基本的には、関数名がデマングルされた後の関数のシグネチャ全体を表します。すでに単語の回避策を見つけており、他の回答が正解としてマークされていることを理解しています。私が以下に書いているのは、あなたが望むようにそれを機能させる方法です.

[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "#OrdinalNumber")]
public static extern int GetAnswer(IntPtr thisA);

"#OrdinalNumber" を "#1" など、GetAnsweer の実際の序数に置き換えると、思いどおりに機能します。

EntryPoint プロパティは、関数名または関数の序数を渡すことができる GetProcAddress に渡す関数名と同じであると考えることができます。

C++ クラスの非静的関数メンバーを呼び出すアプローチは確かに正しく、thiscall は正しく使用されています。これはまさに thiscall 呼び出し規約が C# P/Invoke で機能します。このアプローチの問題点は、DLL の PE 情報を調べ、関数情報をエクスポートし、呼び出す各関数の序数を調べる必要があることです。呼び出す C++ 関数が多数ある場合は、そのようなプロセスを自動化したい。

于 2014-02-23T03:32:59.877 に答える
0

質問の著者から:私が実際に行った解決策

インスタンス メソッドをラップし、aのインスタンスをパラメーターとして受け取る c スタイルの関数を使用することになりました。そうすれば、クラスが継承された場合、適切な仮想メソッドが呼び出されます。

C++/CLI は、管理するプロジェクトが 1 つ増えるだけなので、意図的に C++/CLI を使用しないことにしました。クラスですべてのメソッドを使用する必要がある場合は検討しますが、実際に必要なのは、クラス データをシリアル化するこの 1 つのメソッドだけです。

于 2013-07-25T21:39:04.860 に答える