Вот надлежащий способ вернуть сообщение об ошибке от системы для 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 непосредственно, насколько я знаю.
Попробуйте это:
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);
}
Имейте в виду, что вы не можете делать следующее:
{
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
}