pinvokestackimbalance - 如何修复此问题或将其关闭?

时间:2010-08-17 20:45:30

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

我刚从vs2008切换到vs2010。完全相同的解决方案,除了现在每次调用C ++ dll都会产生'pinvokestackimbalance'异常。

此异常在2008年不会被触发。我可以完全访问C ++ dll和调用应用程序。 pinvoke似乎没有任何问题,但是这个问题使调试其他问题变得不可能; IDE经常停下来告诉我这些事情。

例如,这是C#签名:

    [DllImport("ImageOperations.dll")]
    static extern void FasterFunction(
        [MarshalAs(UnmanagedType.LPArray)]ushort[] inImage, //IntPtr inImage, 
        [MarshalAs(UnmanagedType.LPArray)]byte[] outImage, //IntPtr outImage, 
        int inTotalSize, int inWindow, int inLevel);

这就是C ++方面的样子:

#ifdef OPERATIONS_EXPORTS
#define OPERATIONS_API __declspec(dllexport)
#else
#define OPERATIONS_API __declspec(dllimport)
#endif
extern "C" {


OPERATIONS_API void __cdecl FasterFunction(unsigned short* inArray, 
                                       unsigned char* outRemappedImage,
                                       int inTotalSize, 
                                       int inWindow, int inLevel);

}

vs2010和vs2008之间有什么不同会导致这些异常被抛出?我应该在DllImport指令中添加一组不同的参数吗?

5 个答案:

答案 0 :(得分:130)

首先,要了解代码是错误的(并且始终存在)。 “pInvokeStackImbalance”本身不是一个例外,而是一个托管调试助手。它默认在VS2008中关闭,但是很多人没有打开它,所以默认情况下它在VS2010中启用。 MDA不在发布模式下运行,因此如果您为发布版本构建它将不会触发。

在您的情况下,调用约定不正确。 DllImport默认为CallingConvention.WinApi,与x86桌面代码的CallingConvention.StdCall相同。它应该是CallingConvention.Cdecl

这可以通过将行[DllImport("ImageOperations.dll")]编辑为:

来完成
[DllImport("ImageOperations.dll", CallingConvention = CallingConvention.Cdecl)]

有关详细信息,请参阅this MSDN reference

答案 1 :(得分:37)

将其关闭:

  
      
  1. CTRL + ALT + E
  2.   
  3. "托管调试助手"取消选中PInvokeStackImbalance。
  4.   

答案 2 :(得分:8)

更好地解决这个问题在这里并不困难我提到了一些方法,它可能与我上面提到的一些朋友一样。我正在使用PCSC一个智能卡应用程序我花了大约一个星期,生气了很多变化终于得到了解决方案。

对于我使用我为VS2010安装的PInvoke Extension的工作,你可以在这里下载http://www.red-gate.com/products/dotnet-development/pinvoke/

下载并安装它,关闭visual studio并再次打开,您可以在菜单栏找到扩展名。 enter image description here

如果错误是由于签名不匹配,您只需点击PInvoke.net>插入PInvoke签名

新窗口将如下所示 enter image description here

输入dll的名称并单击搜索,您可以在搜索结果窗口中看到该dll的所有功能,单击该功能,您将获得该特定功能的签名。

使用该签名,您需要根据签名修改您的程序,主要是数据类型。

这解决了我的问题,你可能会遇到不同的问题,比如在导入dll时需要指定callConvention或其他属性。

快乐的编码很好!

答案 3 :(得分:3)

使用VS2010时也遇到了这个问题。 这是什么: Visual Studio默认为“任何CPU”的64位代码。 调用外部Dll时,变量指针(例如字符串)现在变为64位,而所有可靠且可信赖的Dll都使用32位指针。

不要以为你的Dll有什么问题,没有。

更改您的VS设置以生成这样的X86代码(C#的Express版本)

  
      
  1. 转到工具 - >选项。
  2.   
  3. 在“选项”对话框的左下角,选中“显示所有设置”框。
  4.   
  5. 在左侧的树状视图中,选择“项目和解决方案”。
  6.   
  7. 在右侧的选项中,选中“显示高级构建配置”框。
  8.   
  9. 单击“确定”。
  10.   
  11. 转到Build - >配置管理器......
  12.   
  13. 在项目旁边的“平台”列中,单击组合框并选择“”。
  14.   
  15. 在“新平台”设置中,选择“x86”。
  16.   
  17. 单击“确定”。
  18.   
  19. 点击关闭。
  20.   

我还注意到,即使计算机每12个月的功率增加一倍,我目前的计算机内存为1gig,看起来并不比我的第一台带有4兆的486更快。 不要担心使用64位代码,它不会更快或更好,因为它建立在一个庞大的,笨重的面向对象的膨胀塔上。

答案 4 :(得分:0)

我尝试使用CallingConvention ThisCall来调用dll,这对我有用。这是我使用BLOB MS Sql Server的代码。

[DllImport("sqlncli11.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall)]
            private static extern SafeFileHandle OpenSqlFilestream(
                        string FilestreamPath,
                        UInt32 DesiredAccess,
                        UInt32 OpenOptions,
                        byte[] FilestreamTransactionContext,
                        UInt32 FilestreamTransactionContextLength,
                        Int64 AllocationSize);

更多信息:padding