Decoding Error Codes

Of course you know that GetLastError returns a 32-bit error code, but do you know what the code means? The traditional way to figure out a code is to scan through WINERROR.H, but that's not something you can tell the average user to do. It would be nice if you could convert the code to a human-readable string.

Luckily, this is easy to do by calling FormatMessage. This routine is a general purpose call that you can use to format language-dependent messages that your own program wants to generate. However, Windows uses it too.

You can look up the exact parameters, but most of them are used when you are using a custom message file. When you use the system messages, you'll just supply a few defaults.

Here is a simple way to format an error code when a CreateFile fails :

   . . .
    h=CreateFile(fn,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
    if (h==INVALID_HANDLE_VALUE)
    {
        char buf[1024];  // big buffer
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
                      FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL,GetLastError(),0,
                      buf,0,NULL);

        MessageBox(NULL, buf, NULL, MB_OK | MB_ICONINFORMATION);
    }

Or, you could ask Windows to allocate a buffer so you don't have to worry about the size yourself:

    h=CreateFile(fn,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
    if (h==INVALID_HANDLE_VALUE)
    {
        void *buf;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                      FORMAT_MESSAGE_FROM_SYSTEM |
                      FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL,GetLastError(),0,
                      (LPTSTR) &buf,0,NULL);

        MessageBox(NULL, (LPTSTR)buf, NULL, MB_OK | MB_ICONINFORMATION);
// Free the buffer
        LocalFree(buf);
    }

Notice that any placeholders in the string are ignored because of the FORMAT_MESSAGE_IGNORE_INSERTS flag.