对.NET 4进行本机代码的函数调用会导致以下异常:
对PInvoke函数的调用使堆栈失衡。这很可能是因为托管PInvoke签名与非托管目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。
以下是我在Native Code中的定义:
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中建议替代方案吗?
非常感谢你的帮助。
答案 0 :(得分: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
);
答案 1 :(得分:0)
来源:MSDN
在.NET Framework 3.5版中,默认情况下禁用pInvokeStackImbalance MDA。在Visual Studio 2005中使用.NET Framework 3.5版时,pInvokeStackImbalance MDA将显示在“例外”对话框的“托管调试助手”列表中(单击“调试”菜单上的“例外”时会显示该列表)。但是,选择或清除pInvokeStackImbalance的Thrown复选框不会启用或禁用MDA;它仅控制在激活MDA时Visual Studio是否抛出异常。
https://msdn.microsoft.com/en-us/library/0htdy0k3(v=vs.110).aspx