PInvokeStackImbalance C#调用非托管C++函数

use*_*498 39 c# c++ pinvoke dllimport visual-studio-2010

切换到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;
};
Run Code Online (Sandbox Code Playgroud)

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;
};
Run Code Online (Sandbox Code Playgroud)

这是错误:

托管调试助手'PInvokeStackImbalance'在"托管应用程序路径"中检测到问题.

附加信息:对PInvoke函数'SuperSpecialOpenFileFunc'的调用使堆栈失衡.这很可能是因为托管PInvoke签名与非托管目标签名不匹配.检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配.

Gra*_*ton 60

正如提到的丹麦玫瑰的评论,你可以使用__stdcall你的C++函数或声明CallingConvention = CallingConvention.CdeclDllImport.

这是解决我的问题的答案.


Joh*_*ler 9

您在C#中指定了stdcall但在C++中没有指定,这里的不匹配将导致函数和调用者弹出参数从堆栈中移出.

另一方面,有一个编译器开关,它将打开stdcall作为默认调用约定,(-Gz)你使用它吗?

或者在C++中尝试这个

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);
Run Code Online (Sandbox Code Playgroud)


Mic*_*ael 3

您可以在结构体的 C# 声明中指定无填充,但在 C++ 版本中则不然。由于您混合的 char 数组不全是 4 的倍数和奇数个 2 字节 Short,编译器可能会在结构中插入填充并添加末尾。

尝试将结构体包装在 a 中#pragma pack以确保没有填充。

#pragma pack(push)
#pragma pack(1)

// The struct

#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)