Home > OS >  Why Marshal.GetLastWin32Error after calling CallNtPowerInformation always returns 0?
Why Marshal.GetLastWin32Error after calling CallNtPowerInformation always returns 0?

Time:12-25

I'm trying to get SystemBatteryState using CallNtPowerInformation. I set SetLastError attribute to true, but Marshal.GetLastWin32Error() always returns 0, even when status code returned by CallNtPowerInformation not equals to 0.

Example of code where I'm expecting to GetLastWin32Error return non-zero value (I allocate for outputBuffer less memory than needed):

var outputBufferLength = Marshal.SizeOf(typeof(SYSTEM_BATTERY_STATE)) - 1;
var outputBuffer = Marshal.AllocHGlobal(outputBufferLength);

var statusCode = CallNtPowerInformation(
    POWER_INFORMATION_LEVEL.SystemBatteryState,
    IntPtr.Zero,
    0,
    outputBuffer,
    (uint)outputBufferLength
);

var errorCode = Marshal.GetLastWin32Error();
Console.WriteLine("Win32 error code: "   errorCode);

My CallNtPowerInformation:

[DllImport("powrprof.dll", SetLastError = true, ExactSpelling = true,
            CallingConvention = CallingConvention.Cdecl)]
private static extern uint CallNtPowerInformation(
    [In] POWER_INFORMATION_LEVEL informationLevel,
    [In] IntPtr inputBuffer,
    [In] uint inputBufferLength,
    [Out] IntPtr outputBuffer,
    [In] uint outputBufferLength
);

CallNtPowerInformation returns code 3221225507 (STATUS_BUFFER_TOO_SMALL), but GetLastWin32Error returns 0. Should it at all return some error? Or what am I doing wrong?

P.S. Maybe it's enough to have only status code from CallNtPowerInformation, but why do we need then SetLastError = true?

CodePudding user response:

GetLastWin32Error will only work for methods where the documentation says that they set the last error value. CallNtPowerInformation is not one of those. This method directly returns an error code, so the last error code will not be updated. Using SetLastError = true in the declaration of a method that does not use the last error value is useless and has no effect (other than eventually returning the error code from a previous failed system call).

The documentation explicitly says something like "Use GetLastError to get more information" for functions that update the value returned by GetLastError.

  • Related