web-dev-qa-db-ja.com

アンマネージC ++関数のPInvokeStackImbalance C#呼び出し

VS2010に切り替えた後、マネージデバッグアシスタントは、C#アプリケーションからアンマネージC++関数を呼び出すと、アンバランススタックに関するエラーを表示します。

通常の容疑者は問題を引き起こしていないようです。他に確認する必要があるものはありますか? VS2008でビルドされたC++ dllおよびC#アプリケーションには問題がなく、奇妙なバグや神秘的なバグもありませんでした。

チェックされたものは次のとおりです。

  • Dll名は正しいです。
  • エントリポイント名は正しく、depends.exeで検証済みです。コードではマングルされた名前を使用する必要があります。
  • 呼び出し規約は正しいです。
  • サイズとタイプはすべて正しいようです。
  • 文字セットは正しいです。
  • エラーを無視しても問題はないようで、デバッガの外部で実行している場合は問題はありません。

C#:

[DllImport("Correct.dll", EntryPoint = "SuperSpecialOpenFileFunc", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern short SuperSpecialOpenFileFunc(ref SuperSpecialStruct stuff);

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct SuperSpecialStruct
{
   public int field1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
   public string field2;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
   public string field3;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
   public string field4;
   public ushort field5;
   public ushort field6;
   public ushort field7;
   public short field8;
   public short field9;
   public uint field10;
   public short field11;
};

C++:

short SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);

struct SuperSpecialStruct
{
   int               field1;
   char              field2[256];
   char              field3[20];
   char              field4[10];
   unsigned short    field5;
   unsigned short    field6;
   unsigned short    field7;
   short             field8;
   short             field9;
   unsigned int      field10;
   short             field11;
};

エラーは次のとおりです。

マネージデバッグアシスタント「PInvokeStackImbalance」は「マネージアプリケーションパス」で問題を検出しました。

追加情報:PInvoke関数「SuperSpecialOpenFileFunc」の呼び出しにより、スタックのバランスが崩れました。これは、管理されたPInvoke署名が管理されていないターゲット署名と一致しないためです。 PInvoke署名の呼び出し規則とパラメーターが、ターゲットのアンマネージ署名と一致することを確認します。

39
user287498

デーンローズのコメント で述べたように、__stdcall C++関数で、またはCallingConvention = CallingConvention.CdeclDllImportで。

これが私の問題を解決する答えです。

60
Graviton

C#ではなくstdcallを指定しますが、C++では指定しません。ここで不一致があると、関数と呼び出し側の両方がスタックから引数をポップします。

一方、デフォルトの呼び出し規則としてstdcallを有効にするコンパイラスイッチがあります(-Gz)それを使用していますか?

または、C++でこれを試してください

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);
9
John Knoeller

構造体のC#宣言ではパディングを指定しませんが、C++バージョンでは指定しません。すべてが4の倍数ではなく、奇数の2バイトのshortではないchar配列を混合しているため、コンパイラはおそらく構造体内にパディングを挿入し、末尾を追加します。

#pragma packで構造体をラップして、パディングがないことを確認してください。

#pragma pack(Push)
#pragma pack(1)

// The struct

#pragma pack(pop)
3
Michael

説明と同じ問題がありました-何年も完璧に機能していたアンマネージC++アプリ。 VS2010にアップグレードすると、PInvokeStackUnbalancedメッセージの取得を開始しました。

上記のようにC++シグネチャに「__stdcall」を追加すると、問題はなくなりました。

2
user351059

次のように関数定義を更新します:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]

うまくいきます。

1
Vicky