Как я должен использовать FormatMessage () правильно в C++?

84
задан Shog9 6 September 2012 в 18:08
поделиться

3 ответа

Вот надлежащий способ вернуть сообщение об ошибке от системы для HRESULT (названный hresult в этом случае, или можно заменить его GetLastError()):

LPTSTR errorText = NULL;

FormatMessage(
   // use system message tables to retrieve error text
   FORMAT_MESSAGE_FROM_SYSTEM
   // allocate buffer on local heap for error text
   |FORMAT_MESSAGE_ALLOCATE_BUFFER
   // Important! will fail otherwise, since we're not 
   // (and CANNOT) pass insertion parameters
   |FORMAT_MESSAGE_IGNORE_INSERTS,  
   NULL,    // unused with FORMAT_MESSAGE_FROM_SYSTEM
   hresult,
   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   (LPTSTR)&errorText,  // output 
   0, // minimum size for output buffer
   NULL);   // arguments - see note 

if ( NULL != errorText )
{
   // ... do something with the string `errorText` - log it, display it to the user, etc.

   // release memory allocated by FormatMessage()
   LocalFree(errorText);
   errorText = NULL;
}

основное отличие между ответом этого и David Hanak является использованием эти FORMAT_MESSAGE_IGNORE_INSERTS флаг. MSDN немного неясен о том, как вставки должны использоваться, но Raymond Chen отмечает, что Вы никогда не должны использовать их при получении системного сообщения, поскольку у Вас нет способа знать, какие вставки система ожидает.

FWIW при использовании Visual C++ можно сделать жизнь немного легче при помощи _com_error класс:

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

Не часть MFC или ATL непосредственно, насколько я знаю.

128
ответ дан peterh says reinstate Monica 24 November 2019 в 08:34
поделиться

Попробуйте это:

void PrintLastError (const char *msg /* = "Error occurred" */) {
        DWORD errCode = GetLastError();
        char *err;
        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                           NULL,
                           errCode,
                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
                           (LPTSTR) &err,
                           0,
                           NULL))
            return;

        static char buffer[1024];
        _snprintf(buffer, sizeof(buffer), "ERROR: %s: %s\n", msg, err);
        OutputDebugString(buffer); // or otherwise log it
        LocalFree(err);
}
12
ответ дан rogerdpack 24 November 2019 в 08:34
поделиться

Имейте в виду, что вы не можете делать следующее:

{
   LPCTSTR errorText = _com_error(hresult).ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

Поскольку класс создается и уничтожается в стеке, оставляя errorText для указания на недопустимое местоположение. В большинстве случаев это место по-прежнему будет содержать строку с ошибкой, но эта вероятность быстро падает при написании многопоточных приложений.

Итак, всегда делайте это следующим образом, как ответил Shog9 выше:

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}
14
ответ дан 24 November 2019 в 08:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: