Search code examples
c++visual-studioerror-code

"unknown error" from std::error_code on Windows


I have a strange problem with system error messages obtained from std::error_code on Windows. When I build and run test program 1 (see below) using my locally installed Visual Studio, error messages for all system error codes come out as "unknown error". On the other hand, when building and running the same program on the same version of Visual Studio through Godbolt / Compiler Explorer, proper error messages are produced (see test program 1 and output below).

I tested this with Visual Studio 2022 version 17.3.3 (MSVC 19.33) on Windows 10.

I am using the community version of Visual Studio.

I have tried to build locally using the developer command prompt (cl test.cpp), using a Visual Studio console project (all settings at default), and using a Visual Studio CMake project (all settings at default). It makes no difference. In all cases, all error messages come out as "unknown error".

I am not experienced with Visual Studio, so I may definitely be making a very basic mistake.

Any advice as to how I can further diagnose the problem is also welcome.

Output from test program 1 (see below) when built and run through Godbolt / Compiler Explorer:

message = 'The directory is not empty.' (193331629)

Output from test program 1 (see below) when built and run locally:

message = 'unknown error' (193331629)

Output from test program 2 (see below) when built and run locally:

message = 'The directory is not empty.' (193331629)

Test program 1:

#include <windows.h>
#include <system_error>
#include <stdio.h>

int main()
{
    std::error_code ec(ERROR_DIR_NOT_EMPTY, std::system_category());
    printf("message = '%s' (%lld)\n", ec.message().c_str(), static_cast<long long>(_MSC_FULL_VER));
}

Test program 2 (for contrast):

#include <windows.h>
#include <stdio.h>

int main()
{
    char buffer[256];
    DWORD len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ERROR_DIR_NOT_EMPTY, 0, buffer, 255, NULL);
    while (len > 0 && (buffer[len - 1] == '\n' || buffer[len - 1] == '\r'))
        --len;
    buffer[len] = '\0';
    printf("message = '%s' (%lld)\n", buffer, static_cast<long long>(_MSC_FULL_VER));
}

Solution

  • Ok, the problem in my case is that the system locale is set to "en-GB" and not "en-US".

    If I pass language identifier 2057 (en-GB) to FormatMessage() I get no error message, but if I pass 1033 (en-US), I do.

    So far, I have not been able to change the system-level locale, but even if it can be done, it seems rather suboptimal that system error messages fail to work if my system locale is set to "en-GB".

    I wonder if there is a rational idea behind this behavior, or if it is just plain broken.

    In any case, the solution in my case, I think, is to introduce a custom error category that invokes FormatMessage() with a language identifier of 0 (see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage), and then forward to the native system error categeory in the functions that deal with mapping to generic error condition.