我有一些代码。
[DllImport("library.dll", EntryPoint = "SomeoneElsesReadFunction")]
[return: MarshalAs(UnmanagedType.U4)]
private static extern UInt32 SomeoneElsesReadFunction(
Int16[] data,
Int16[] dataOrig,
[MarshalAs(UnmanagedType.U2)]
Int16 buffsize,
ref int smpNum,
);
然后...
var returnCode = SomeoneElsesReadFunction(Buffer, OrigBuffer, Consts.BufferSize, ref _sampleNumber);
int errorCode;
if ((errorCode = Marshal.GetLastWin32Error()) != 0)
{
throw new Exception(string.Format("Device read failed. Windows System Error Code: {0}", errorCode));
}
发生在每秒运行多次的更宽的循环中。
在循环的每次迭代中,我一直得到183的errorCode
。当我签入VS调试器时,可以看到在调用SomeoneElsesReadFunction()
之前,最后一次Win32错误是183,之后仍然是183。
但是有没有一种方法可以在调用该方法之前清除/重置此值,因此可以确定,当我事后检查时,每次调用肯定在方法内发生错误,而不仅仅是从方法中遗留下来。以前的电话?
修改
为了澄清与returnCode
的混淆,即使出于某种原因,原始方法也会返回代码= 0,即使在我需要检查的特定错误条件下也是如此。因此,即使returnCode为0(确定),我也需要调用GetLastWin32Error()
。
答案 0 :(得分:0)
我认为您在混淆错误代码和返回值。 SetLastError
仅应在函数产生错误时调用,而绝对不能执行SetLastError(0)
。作为开发人员,您需要检查函数调用是否失败,然后找出为什么失败。
错误代码是有关函数失败原因的额外信息,但是您的代码没有检查返回值以查看是否是失败。
var returnCode = SomeoneElsesReadFunction(Buffer, OrigBuffer, Consts.BufferSize, ref _sampleNumber);
if(!returnCode) // Did it fail?
{
int errorCode;
if ((errorCode = Marshal.GetLastWin32Error()) != 0) // Why did it fail?
{
throw new Exception(string.Format("Device read failed. Windows System Error Code: {0}", errorCode));
}
}
答案 1 :(得分:0)
感谢 @Jake's 对问题的评论,我能够解决这个问题。在某些版本的 Windows™ 上,GetLastWin32Error()
的行为是不可预测的。我发现之前 WIN32 调用中的错误没有被后续成功的 WIN32 调用清除。因此,在未先清除错误代码的情况下在稍后调用后进行检查时会出现误报。
internal static class WIN32
{
[DllImport("kernel32.dll")]
internal static extern bool AllocConsole();
[DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", SetLastError = true)]
internal static extern void SetLastErrorEx(uint dwErrCode, uint dwType);
}
请注意,我的一些导入没有 , SetLastError = true
参数。添加此改进了错误代码的一致性,但并非完全如此。
然后,……
// clear any previous WIN32 error code, otherwise
WIN32.SetLastErrorEx(0, 0);
IntPtr hWnd = WIN32.GetConsoleWindow();
if (Marshal.GetLastWin32Error() > 0) { /* do something */ }
if (hWnd == IntPtr.Zero)
{
WIN32.SetLastErrorEx(0, 0);
WIN32.AllocConsole();
if (Marshal.GetLastWin32Error() > 0) { /* do something else */ }
}