对 native 代码进行 .NET 4 函数调用会导致以下异常:
A call to PInvoke function has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
这是我在 native 代码中的定义:
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
参数。回调是用 CALLBACK
声明的,它是 stdcall
。
所以代表应该是:
[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
);
关于c# - 对 PInvoke 函数的调用使堆栈不平衡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19082923/