При переводе сообщений об ошибках я получаю указатель на строку (pMsgBuf), которая выглядит следующим образом:
pMsgBuf = "T\0h\0e\0 \0s\t\0r\0a\0...."
Сообщение есть, но разделено нулями. Это должен быть параметр, который я передаю FormatMessage, но понятия не имею, как его исправить.
char* pMsgBuf;
// windows will allocate memory for err string and make our pointer point to it
const DWORD nMsgLen = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&pMsgBuf), 0, nullptr
);
// 0 string length returned indicates a failure
if (nMsgLen == 0)
{
return "Unidentified error code";
}
char joe[100]{};
for (int i = 0, y = 0; i < nMsgLen *2; i++)
{
if (pMsgBuf[i] != '\0')
joe[y++] = pMsgBuf[i];
}
// copy error string from windows-allocated buffer to std::string
std::string errorString = pMsgBuf;
// free windows buffer
size_t size = sizeof(pMsgBuf);
LocalFree(pMsgBuf);
return errorString;
Я должен был вернуть указатель строки с нулевым значением в конце, а не каждый символ с нулевым значением.
Я создал тестовый блок, чтобы подтвердить, что именно это я и получил FormatMessage:
char joe[100]{};
for (int i = 0, y = 0; i < nMsgLen *2; i++)
{
if (pMsgBuf[i] != '\0')
joe[y++] = pMsgBuf[i];
}
Конечно же, Джо, веревка выходит правильно.
Есть ли конкретная причина избегать std::format? Это более интуитивно понятно и гораздо менее подвержено ошибкам.





Вы используете вариант FormatMessage() в Юникоде, для которого требуется буфер wchar_t*.
Большинство функций Win32 API имеют варианты «W» и «A», а простое имя #define соответствует одному из них, в зависимости от настроек компилятора. Итак, в вашем случае FormatMessage разрешается в FormatMessageW.
Как правило, в Windows используйте Unicode, и все строки должны быть std::wstring и wchar_t. Используйте char/std::string с WideCharToMultiByte с CP_UTF8 для преобразований, подходящих для передачи UTF-8, скажем, данных веб-публикации.
Если вы используете версию «A», Windows внутренне преобразует все в UTF-16 в соответствии с локальной кодовой страницей системных настроек для приложений, не поддерживающих Юникод. В последних версиях Windows это может быть UTF-8, но не полагайтесь на это, это глобальная настройка администратора.
Кроме того, UTF-16 копирует Latin-1 в диапазоне кодов 0x00-0xff, который, в свою очередь, копирует ASCII в диапазоне 0x00-0x7f. Вот почему английские тексты отображаются в шестнадцатеричном дампе как «обычные», за исключением нулевых байтов между буквами, потому что это 16-битный код — не имеет особого значения, какая кодировка используется, это всегда одни и те же числа.
В настройках вашего проекта установлен Юникод, поэтому FormatMessage() на самом деле вызывает FormatMessageW(), который выводит строку UTF-16 wchar_t. Но для его получения вы используете указатель char*, поэтому видите необработанные байты. У символов ASCII в UTF-16 старший байт установлен на 0.
Вместо этого вам нужно использовать указатель wchar_t*:
wchar_t* pMsgBuf;
FormatMessage(..., reinterpret_cast<LPWSTR>(&pMsgBuf), ...);
В противном случае, если вы хотите, чтобы сообщение об ошибке выводилось в виде строки char, вы можете напрямую вызвать FormatMessageA():
char* pMsgBuf;
FormatMessageA(..., reinterpret_cast<LPSTR>(&pMsgBuf), ...);
Потому что это UTF-16...