Thanks to visit codestin.com
Credit goes to github.com

Skip to content

<system_error>: FormatMessageA needs be used in a different way #2451

@snnn

Description

@snnn

Describe the bug

Windows settings have “user language id” and “system language id”. They can be different. std::system_category().message() returns "???" when they are different.

By default FormatMessage returns a string in “user language”. The Unicode version of FormatMessage works good in all cases. But the ANSI version, like all other ANSI version Windows APIs, would try to convert the result string to a multibyte string based on “system language id”. It goes wrong when the two ids are different. For example, If your user language is Chinese but the system language is English, it can only returns “????”, because you can’t encode a Chinese string in ISO-8859-1.

So if you need to return the error message in std::string type, there are two solutions:

  1. Pass the system language id to FormatMessageA
  2. If you use FormatMessageW, you can set the language id to the system language or thread ACP(the user language). Then when you use WideCharToMultiByte, use CP_ACP for the system language and CP_THREAD_CP for the user language.

Command-line test case

int main() {
    setlocale(LC_ALL, "");
	LANGID user_language_id = GetUserDefaultLangID();
	WCHAR buf[1024];
	int ret = GetUserDefaultLocaleName(buf,sizeof(buf)/sizeof(buf[0]));
	assert(ret != 0);
	std::wcout << user_language_id << L" " << buf << "\n";
	ret = GetSystemDefaultLocaleName(buf, sizeof(buf) / sizeof(buf[0]));
	assert(ret != 0);
	LANGID system_language_id = GetSystemDefaultLangID();
	std::wcout << system_language_id << L" " << buf << std::endl;
    
    wil::unique_hfile file_handle(CreateFile(L"D:\\non_exist_file.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
    if (file_handle.get() == INVALID_HANDLE_VALUE) {
        const auto error_code = GetLastError();
        std::string errmsg = std::system_category().message(error_code); //Sometimes the string only contains "???"
    }
  return 0;
}

To compile it:
C:\Temp>cl /EHsc .\repro.cpp

To reproduce the error:
I assume you have a clean Windows installation. Then please create a new user without Administrator privilege. Then login to the user, go to settings and change the display language to something different. Like, Chinese. In such a case, you only changed the user's locale, not the system. Because the user doesn't have the privilege to change system level settings.

Then run the code, use your debugger to inspect the binary content of the error message. Do not print it out. Printing is a different problem. Just look the raw bytes.

Expected behavior
The error message should contain useful information.

STL version
VS 2022 17.0.3

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions