Is there a way to clear the value of GetLastWin32Error?

751 views Asked by At

I have this little bit of code.

[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,
);

then...

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));
}

which takes place within a wider loop running multiple times per second.

I keep getting an errorCode of 183 on every iteration of the loop. When I check in the VS debugger, I can see the Last Win32 Error is 183 before calling SomeoneElsesReadFunction() and still 183 afterwards.

But is there a way of clearing/resetting this value before the method is called, so I can be sure, when I check afterwards, that the error is definitely occurring within the method with each call and not just left over from a previous call?

Edit

To clarify the confusion with the returnCode, the original method for some reason returns a code = 0 even in a particular error condition that I need to check. For this reason I need to call GetLastWin32Error() even if the returnCode is 0 (OK).

2

There are 2 answers

1
Neil On

I think you are confusing error codes and return values. SetLastError should only be called when a function generates an error, it should never do SetLastError(0). It's your job as a developer to check if a function call failed and then work out why it failed.

The error code is extra information about why a function failed, but your code isn't checking the return value to see if there was a failure.

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));
    } 
}
0
ergohack On

Thanks to @Jake's comment on the question I was able to resolve this issue. On some version of Windows™, The behavior of GetLastWin32Error() is unpredictable. I was finding that the errors from previous WIN32 calls were not being cleared by subsequent, successful WIN32 calls. Thus a false negative when checking after a later call without first clearing the error code.

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);
}

Note that some of my imports do not have the , SetLastError = true parameter. Adding this improved error code consistency, but not entirely.

then later, ...

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