有没有办法清除GetLastWin32Error的值?

时间:2018-09-28 08:54:18

标签: c# pinvoke system-error windowserror

我有一些代码。

[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()

2 个答案:

答案 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 */ }
}