Win32 API Error reporting and handling Error reported with additional information on failure


Example

In addition to a failure/success return value, some API calls also set the last error on failure (e.g. CreateWindow). The documentation usually contains the following standard wording for this case:

If the function succeeds, the return value is <API-specific success value>.
If the function fails, the return value is <API-specific error value>. To get extended error information, call GetLastError.

if ( CreateWindowW( ... ) == NULL ) {
    // Failure: get additional information.
    DWORD dwError = GetLastError();
} else {
    // Success: must not call GetLastError.
}

It is vital that you call GetLastError() IMMEDIATELY. The last error code can be overwritten by any other function, so if there's an extra function call between the function that failed and the call to GetLastError(), the return from GetLastError() will no longer be reliable. Take extra caution when dealing with C++ constructors.

Once you get an error code, you will need to interpret it. You can get a comprehensive list of error codes on MSDN, at the System Error Codes (Windows) page. Alternatively, you can look in your system header files; the file with all the error code constants is winerror.h. (If you have Microsoft's official SDK for Windows 8 or newer, this is in the shared subfolder of the include folder.)

Notes on calling GetLastError() in other programming languages

.net languages (C#, VB, etc.)

With .net, you should not P/Invoke to GetLastError() directly. This is because the .net runtime will make other Windows API calls on the same thread behind your back. For instance, the garbage collector might call VirtualFree() if it finds enough memory that it is no longer using, and this can happen between your intended function call and your call to GetLastError().

Instead, .net provides the Marshal.GetLastWin32Error() function, which will retrieve the last error from the last P/Invoke call that you yourself made. Use this instead of calling GetLastError() directly.

(.net does not seem to stop you from importing GetLastError() anyway; I'm not sure why.)

Go

The various facilities provided by Go for calling DLL functions (which reside in both package syscall and package golang.org/x/sys/windows) return three values: r1, r2, and err. r2 is never used; you can use the blank identifier there. r1 is the function's return value. err is the result of calling GetLastError() but converted into a type that implements error, so you can pass it up to calling functions to handle.

Because Go does not know when to call GetLastError() and when not to, it will always return a non-nil error. Therefore, the typical Go error-handling idiom

r1, _, err := syscall.Syscall12(CreateWindowW.Addr(), ...)
if err != nil {
    // handle err
}
// use r1

will not work. Instead, you must check r1, exactly as you would in C, and only use err if that indicates the function returned an error:

r1, _, err := syscall.Syscall12(CreateWindowW.Addr(), ...)
if r1 == 0 {
    // handle err
}
// use r1