我刚从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指令中添加一组不同的参数吗?
答案 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)
将其关闭:
- CTRL + ALT + E
- "托管调试助手"取消选中PInvokeStackImbalance。
醇>
答案 2 :(得分:8)
更好地解决这个问题在这里并不困难我提到了一些方法,它可能与我上面提到的一些朋友一样。我正在使用PCSC一个智能卡应用程序我花了大约一个星期,生气了很多变化终于得到了解决方案。
对于我使用我为VS2010安装的PInvoke Extension的工作,你可以在这里下载http://www.red-gate.com/products/dotnet-development/pinvoke/
下载并安装它,关闭visual studio并再次打开,您可以在菜单栏找到扩展名。
如果错误是由于签名不匹配,您只需点击PInvoke.net>插入PInvoke签名
新窗口将如下所示
输入dll的名称并单击搜索,您可以在搜索结果窗口中看到该dll的所有功能,单击该功能,您将获得该特定功能的签名。
使用该签名,您需要根据签名修改您的程序,主要是数据类型。
这解决了我的问题,你可能会遇到不同的问题,比如在导入dll时需要指定callConvention或其他属性。
快乐的编码很好!
答案 3 :(得分:3)
使用VS2010时也遇到了这个问题。 这是什么: Visual Studio默认为“任何CPU”的64位代码。 调用外部Dll时,变量指针(例如字符串)现在变为64位,而所有可靠且可信赖的Dll都使用32位指针。
不要以为你的Dll有什么问题,没有。
更改您的VS设置以生成这样的X86代码(C#的Express版本)
- 转到工具 - >选项。
- 在“选项”对话框的左下角,选中“显示所有设置”框。
- 在左侧的树状视图中,选择“项目和解决方案”。
- 在右侧的选项中,选中“显示高级构建配置”框。
- 单击“确定”。
- 转到Build - >配置管理器......
- 在项目旁边的“平台”列中,单击组合框并选择“”。
- 在“新平台”设置中,选择“x86”。
- 单击“确定”。
- 点击关闭。
醇>
我还注意到,即使计算机每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