当我按“F5”在 Visual Studio 2022 中运行我的 C# 应用程序时,MDA 建议使用 PInvokeStackImbalance,但如果我忽略 MDA 并按 F5 继续,则效果很好,C++ api 返回 1。
但是如果我直接在 Windows 中运行我的应用程序,则不会出现异常并且 api 返回 0。
平台设置为Release - x86,我确认文件夹是正确的。 我的C#项目是.NET Framework 4.7.2,winform应用程序。
希望有人可以帮助我解决 PInvokeStackImbalance 问题 - 我知道修复它可能会使我的应用程序在 VS 之外运行。
而且,更重要的是,告诉我为什么“F5”在 Visual Studio 中可以工作,但在外面就不行。
C++ Api 定义(.h):
UPGRADE_API BOOL _stdcall WriteData(USHORT nID, BYTE dest, PBYTE pDataBuffer, USHORT nBufferSize, DWORD dwLayer=0);
//...
#define UPGRADE_API __declspec(dllimport)
我的 C# 代码:
[DllImport("Upgrade.dll", EntryPoint = "WriteData", CallingConvention = CallingConvention.StdCall)]
public static extern int WriteData(int id, byte dest, char[] data, int len);
//...
var resource = "Test";
var array = resource.ToCharArray();
var r = WriteData(33, 0, array, array.Length);
if (r == 0)
{
MessageBox.Show("Failed");
return;
}
MessageBox.Show($"Ok: {resource}");
C++ api 是第三方 dll,我只有 .h 文件,因此无法直接使用 C++ 代码进行调试。
我尝试使用 x64 构建 C# 应用程序,但 c++ api 崩溃了。我构建了调试,与发布相同。
我检查了VS中的启动选项,它是空的。
我测试了很多api参数的数据类型,比如uint/ushort/short id、StringBuilder/string data、int/ushort len。有些类型是错误的,甚至VS中的“F5”也返回0。但是所有这些类型,总是会出现PInvokeStackImbalance。
WriteData
的C++原型,有5个参数。其中之一有默认值,但您仍然需要传递它:具有默认值的参数始终会传递给被调用的函数,您可以在调用中省略它,但处理的方式是由编译器插入该值被设置为该参数的默认值。您不能从 dll 导入中省略它,因为这样就不会传递该参数really,导致(对于 stdcall 函数)向堆栈推送的数据少于被调用函数返回时释放的数据(stdcall 函数负责释放自己的数据)参数)。因此堆栈不平衡。
此外
PBYTE pDataBuffer
建议您应该在 C# 中传递 byte[]
,也许不需要,但该类型并不建议 WriteData
适用于 16 位字符(就像 C# 中的 char
一样)。
您尝试过的不同类型对于
id
和 len
参数不会产生显着差异,当它们被推送到 x86 中的堆栈时,它们都会被推送为双字。