1

VSで新しいWin32プロジェクトを作成し、この目的でダイナミックライブラリ(* .dll)を選択しました。

メインファイルにいくつかのエクスポート機能を定義しました:

__declspec(dllexport)
int TestCall(void)
{
    int value = 4 / 2;
    std::cout << typeid(value).name() << std::endl;
    return value;
}

__declspec(dllexport)
void SwapMe(int *first, int *second)
{
    int tmp = *first;
    *first = *second;
    *second = tmp;
}

ダンピン/exportsを見ると、次のようになっています。

ordinal hint RVA      name

      1    0 00001010 ?SwapMe@@YAXPEAH0@Z
      2    1 00001270 ?TestCall@@YAHXZ

私は次のようにC#バージョンで呼び出しています:

[DllImport(@"lib1.dll", EntryPoint = "?TestCall@@YAHXZ",
CallingConvention = CallingConvention.Cdecl)]
static extern int TestCall();

エクスポートされたメソッドを使用する正しい形式ではありません。C ++ dllプロジェクトでエクスポートメソッドのそのような名前を生成できなかったのはどこですか?

4

2 に答える 2

6

これは正常であり、C++コンパイラは関数に名前の装飾を適用します。C ++言語は、C#と同様に、関数のオーバーロードをサポートしています。Foo(int)したがって、とFoo(double)関数を書くことができます。明らかに、両方を「Foo」という名前の関数としてエクスポートすることはできません。クライアントコードは、どちらを呼び出すかを認識していません。したがって、余分な文字は名前をエンコードして、オーバーロードに対して一意になるようにします。

関数を宣言することでこれをオフにすることができますextern "C"。C言語はオーバーロードをサポートしていないため、同じ種類の装飾は必要ありません。

しかし、そうでない方が実際には良いです。間違いを見つけるための優れた方法でもあるからです。C ++コードの関数宣言を変更するのと同じですが、C#コードのpinvoke宣言を変更するのを忘れています。これで、説明的ではなく、AccessViolationExceptionを診断するのが非常に難しい代わりに、「エントリポイントが見つかりません」という例外を簡単に診断できるようになります。これは必ずしもC++コードで発生させる必要はありませんが、スタックの不均衡によってC#コードがクラッシュする可能性もあります。装飾された名前を検索するのは少し面倒ですが、リンカーにマップファイル(/ MAPオプション)を作成するように依頼することで、それを改善します。

于 2012-12-29T20:14:57.337 に答える
2

extern "C"を使用して、名前のマングリングを回避するためのリンケージを指定します。

extern "C" __declspec(dllexport) int TestCall(void);
extern "C" __declspec(dllexport) void SwapMe(int *first, int *second); 
于 2012-12-29T20:05:30.267 に答える