对 PInvoke 函数的调用使堆栈不平衡
本文关键字:堆栈 不平衡 调用 PInvoke 函数 | 更新日期: 2023-09-27 18:33:23
对本机代码进行对 .NET 4 的函数调用会导致以下异常:
对 PInvoke 函数的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。
这是我在本机代码中的定义:
typedef void ( CALLBACK* CB_DOWNLOADING )
(
ULONG, // secs elapsed
LPARAM, // custom callback param
LPBOOL // abort?
);
FETCH_API HttpFetchW
(
LPCWSTR url,
IStream** retval,
LPCWSTR usrname = NULL,
LPCWSTR pwd = NULL,
BOOL unzip = TRUE,
CB_DOWNLOADING cb = NULL,
LPARAM cb_param = 0,
LPWSTR ctype = NULL,
ULONG ctypelen = 0
);
下面是 .NET 对应项:
[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern FETCH HttpFetchW
(
[MarshalAs(UnmanagedType.LPWStr)]
string url,
out System.Runtime.InteropServices.ComTypes.IStream retval,
[MarshalAs(UnmanagedType.LPWStr)]
string usrname,
[MarshalAs(UnmanagedType.LPWStr)]
string pwd,
bool unzip,
dlgDownloadingCB cb,
IntPtr cb_param,
[MarshalAs(UnmanagedType.LPWStr)]
string ctype,
ulong ctypelen
);
其中 FETCH 是一个枚举。
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
internal delegate void dlgDownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort);
internal static void DownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort)
{
// Console.WriteLine("elapsedSec = " + elapsedSec.ToString());
}
任何人都可以在 .NET 4 中提出替代方案吗?
非常感谢您的帮助。
我能看到的HttpFetchW
中唯一明显的错误是 C# ulong
宽 64 位,C++ ULONG
宽 32 位。最后一个参数的 C# 代码应uint
。
要检查的其他事项包括调用约定。你确定是cdecl
吗?你确定SetLastError
应该true
吗?
至于回调,你犯了同样的错误 ulong
.abort
参数是 LPBOOL
.那是指向BOOL
的指针。因此,应将 C# 参数声明为 ref
参数。并且回调是用stdcall
CALLBACK
声明的
所以委托应该是:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void dlgDownloadingCB(
uint elapsedSec,
IntPtr lParam,
ref bool abort
);
或者干脆删除 UnmanagedFunctionPointer
属性,因为默认值为 stdcall
。
我认为由于回调是stdcall
的,函数也是如此。我希望FETCH_API
宏扩展到返回枚举和调用约定。既然你没有提供这些细节,我只能猜测。您需要检查。
我们无法检查的另一件事是 CB_DOWNLOADING
.
无论如何,有了这些假设,函数就变成了:
[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern FETCH HttpFetchW(
string url,
out System.Runtime.InteropServices.ComTypes.IStream retval,
string usrname,
string pwd,
bool unzip,
dlgDownloadingCB cb,
IntPtr cb_param,
string ctype,
uint ctypelen
);
来源 : MSDN
在 .NET Framework 3.5 版中,pInvokeStackImbalance MDA 默认处于禁用状态。将 .NET Framework 3.5 版与 Visual Studio 2005 配合使用时,pInvokeStackImbalance MDA 将显示在"异常"对话框的"托管调试助手"列表中(单击"调试"菜单上的"异常"时显示该对话框时显示该列表(。但是,选中或清除 pInvokeStackImbalance 的"抛出"复选框不会启用或禁用 MDA;它只控制Visual Studio在激活MDA时是否引发异常。
https://msdn.microsoft.com/en-us/library/0htdy0k3(v=vs.110(.aspx