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

时间:2010-03-05 22:33:34

标签: c# c++ visual-studio-2010 pinvoke dllimport

切换到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签名与目标匹配   非托管签名。

5 个答案:

答案 0 :(得分:59)

正如Dane Rose's comment中所述,您可以在C ++函数上使用__stdcall,也可以在CallingConvention = CallingConvention.Cdecl上声明DllImport

这是解决我问题的答案。

答案 1 :(得分:9)

你在C#中指定stdcall而不是在C ++中指定stdcall,这里的不匹配将导致函数和调用者从堆栈中弹出参数。

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

或者在C ++中试试这个

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);

答案 2 :(得分:3)

在结构的C#声明中没有指定填充,但在C ++版本中没有。由于您混合的char数组不是四的倍数和奇数的2字节短路,编译器可能在结构中插入填充并添加结尾。

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

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

// The struct

#pragma pack(pop)

答案 3 :(得分:2)

有与上述相同的问题 - 多年来一直运行良好的非托管C ++应用程序。当我们升级到VS2010时,我们开始收到PInvokeStackUnbalanced消息。

如上所述将“__stdcall”添加到C ++签名中会使问题消失。

答案 4 :(得分:1)

很好。我的更新功能定义如下:

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

效果很好。