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

问题描述 投票:39回答:5

切换到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'检测到一个管理的应用程序路径中的问题。

附加信息:P调用功能'SuperSpecialOpenFileFunc'具有使堆栈不平衡。这可能因为托管的PInvoke签名与不受管理的目标不符签名。检查来电的约定和参数PInvoke签名匹配目标非托管签名。

c# c++ visual-studio-2010 pinvoke dllimport
5个回答
61
投票

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


9
投票

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

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

或在C ++中尝试此操作

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);

3
投票

您在结构的C#声明中未指定填充,但在C ++版本中未指定。由于您混合的字符数组不是4的整数倍,也不是2字节短裤的奇数,因此编译器可能会在结构中插入填充并添加结尾。

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

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

// The struct

#pragma pack(pop)

2
投票

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

如上所述,向C ++签名添加“ __stdcall”使问题消失了。


1
投票

很好。我将函数定义如下:

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

效果很好。

© www.soinside.com 2019 - 2024. All rights reserved.