1

There is a nessesity to use WinAPI for my project. While I was studying WinAPI, I read about the method of getting errors Marshal.GetLastWin32Error().
I coped the example from the website learn.microsoft.com and added console project to .Net Core 5.0.

using System;
using System.Runtime.InteropServices;

internal class Win32
{
    // Use DllImportAttribute to inport the Win32 MessageBox
    // function.  Set the SetLastError flag to true to allow
    // the function to set the Win32 error.
    [DllImportAttribute("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern int MessageBox(IntPtr hwnd, String text, String caption, uint type);
}

class Program
{

    static void Run()
    {
        // Call the MessageBox with normal parameters.

        Console.WriteLine("Calling Win32 MessageBox without error...");

        Win32.MessageBox(new IntPtr(0), "Press OK...", "Press OK Dialog", 0);

        // Get the last error and display it.
        int error = Marshal.GetLastWin32Error();

        Console.WriteLine("The last Win32 Error was: " + error);

        // Call the MessageBox with an invalid window handle to
        // produce a Win32 error.

        Console.WriteLine("Calling Win32 MessageBox with error...");

        Win32.MessageBox(new IntPtr(123132), "Press OK...", "Press OK Dialog", 0);

        // Get the last error and display it.

        error = Marshal.GetLastWin32Error();

        Console.WriteLine("The last Win32 Error was: " + error);
    }

    static void Main(string[] args)
    {
        Run();
    }
}
// This code example displays the following to the console:
//
// Calling Win32 MessageBox without error...
// The last Win32 Error was: 0
// Calling Win32 MessageBox with error...
// The last Win32 Error was: 1400

The first computer that I tried worked well.
After that I bought the new one and tried my project there.
The code began to work with the mistake: the error 1400 always came back after the calling messagebox, but the window showed and returned 1 (IDOK).

Error with WinAPI


The first computer:

  • System manufacturer: MSI GF75 Thin 10UEK;
  • Windows: Windows10 Home x64;
  • Update: 20H2 (KB504237);
  • BIOS: E17FSIMS.102
  • Processor: Intel i7-10750H;

The second computer:

  • System manufacturer: HP ProBook 440 G8;
  • Windows: Windows10 Pro x64;
  • Update: 20H2 (KB504237)
  • BIOS: T70 Ver. 01.03.01
  • Processor: Intel i7-1165G7

If I call GetLastWin32Error before the calling of messagebox, I'll get a error 0.
Has somebody got an experience like that? The problem is not very serious because of checking what window returns. But I'd like to know what has happened.

Gunvel
  • 33
  • 6

1 Answers1

2

Marshal.GetLastWin32Error calls GetLastError.

Calling GetLastError only makes sense when the function in question returned a failed code. For MessageBox, that is 0.

You call GetLastWin32Error regardless, so you cannot trust the value it returns.

To quote the documentation:

Most functions that set the thread's last-error code set it when they fail. However, some functions also set the last-error code when they succeed. If the function is not documented to set the last-error code, the value returned by this function is simply the most recent last-error code to have been set; some functions set the last-error code to 0 on success and others do not.

MessageBox is not documented to set last error to 0 on success.

GSerg
  • 76,472
  • 17
  • 159
  • 346
  • The Console.WriteLine calls before the MessageBox call does sets last error to 0. – Simon Mourier Jul 18 '21 at 11:25
  • @SimonMourier Then, in the process of calling `MessageBox`, the framework invokes some other API, e.g. `GetProcAddress`, which may or may not set the last error code. Then the `MessageBox` itself is invoked, which itself may call other API functions that may set the last error code - which could be because they genuinely failed and `MessageBox` handled the error, or because they pre-set the last error to an error code and then don't bother to clear it on success. And finally `MessageBox` returns success without bothering to clear the last error to zero. – GSerg Jul 18 '21 at 11:29
  • Do some testing and you'll see – Simon Mourier Jul 18 '21 at 14:21