Berikut cara yang tepat untuk mendapatkan pesan kesalahan kembali dari sistem untuk HRESULT
(dalam kasus ini dinamai hresult, atau Anda dapat menggantinya dengan GetLastError()
):
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hresult,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText,
0,
NULL);
if ( NULL != errorText )
{
LocalFree(errorText);
errorText = NULL;
}
Perbedaan utama antara ini dan jawaban David Hanak adalah penggunaan FORMAT_MESSAGE_IGNORE_INSERTS
bendera. MSDN agak tidak jelas tentang bagaimana penyisipan harus digunakan, tetapi Raymond Chen mencatat bahwa Anda tidak boleh menggunakannya saat mengambil pesan sistem, karena Anda tidak memiliki cara untuk mengetahui penyisipan mana yang diharapkan sistem.
FWIW, jika Anda menggunakan Visual C ++ Anda dapat membuat hidup Anda sedikit lebih mudah dengan menggunakan _com_error
kelas:
{
_com_error error(hresult);
LPCTSTR errorText = error.ErrorMessage();
}
Bukan bagian dari MFC atau ATL secara langsung sejauh yang saya ketahui.
RegCreateKeyEx
mengembalikan aLONG
. Dokumennya mengatakan saya dapat menggunakanFormatMessage
untuk mengambil kesalahan, tetapi saya harus memasukkannyaLONG
ke fileHRESULT
.Ingatlah bahwa Anda tidak dapat melakukan hal berikut:
{ LPCTSTR errorText = _com_error(hresult).ErrorMessage(); // do something with the error... //automatic cleanup when error goes out of scope }
Saat kelas dibuat dan dimusnahkan di tumpukan, meninggalkan errorText mengarah ke lokasi yang tidak valid. Dalam kebanyakan kasus, lokasi ini masih akan berisi string kesalahan, tetapi kemungkinan itu hilang dengan cepat saat menulis aplikasi berulir.
Jadi selalu lakukan seperti berikut yang dijawab oleh Shog9 di atas:
{ _com_error error(hresult); LPCTSTR errorText = error.ErrorMessage(); // do something with the error... //automatic cleanup when error goes out of scope }
sumber
_com_error
objek dibuat pada stack di kedua contoh Anda. Istilah yang Anda cari bersifat sementara . Dalam contoh sebelumnya, objek adalah sementara yang dihancurkan di akhir pernyataan.std::wstring strErrorText = _com_error(hresult).ErrorMessage();
Coba ini:
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); }
sumber
Ini lebih penambah mayoritas jawaban, tapi bukannya menggunakan
LocalFree(errorText)
penggunaanHeapFree
fungsi:::HeapFree(::GetProcessHeap(), NULL, errorText);
Dari situs MSDN :
Pembaruan
Saya menemukan bahwa
LocalFree
dalam versi 10.0.10240.0 dari SDK (baris 1108 di WinBase.h). Namun, peringatan tersebut masih ada di tautan di atas.#pragma region Desktop Family or OneCore Family #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) WINBASEAPI _Success_(return==0) _Ret_maybenull_ HLOCAL WINAPI LocalFree( _Frees_ptr_opt_ HLOCAL hMem ); #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */ #pragma endregion
Perbarui 2
Saya juga menyarankan menggunakan
FORMAT_MESSAGE_MAX_WIDTH_MASK
bendera untuk merapikan jeda baris dalam pesan sistem.Dari situs MSDN :
Pembaruan 3
Tampaknya ada 2 kode kesalahan sistem tertentu yang tidak mengembalikan pesan lengkap menggunakan pendekatan yang disarankan:
Mengapa FormatMessage hanya membuat pesan sebagian untuk ERROR_SYSTEM_PROCESS_TERMINATED dan ERROR_UNHANDLED_EXCEPTION kesalahan sistem?
sumber
Berikut adalah versi dari fungsi David yang menangani Unicode
void HandleLastError(const TCHAR *msg /* = "Error occured" */) { DWORD errCode = GetLastError(); TCHAR *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; //TRACE("ERROR: %s: %s", msg, err); TCHAR buffer[1024]; _sntprintf_s(buffer, sizeof(buffer), _T("ERROR: %s: %s\n"), msg, err); OutputDebugString(buffer); LocalFree(err);
}
sumber
_sntprintf_s
dalam kasus UNICODE. Fungsi tersebut mengambil jumlah karakter, jadi Anda ingin_countof
atauARRAYSIZE
alias,sizeof(buffer) / sizeof(buffer[0])
bukansizeof
.Sejak c ++ 11, Anda dapat menggunakan pustaka standar sebagai ganti
FormatMessage
:#include <system_error> std::string message = std::system_category().message(hr)
sumber
Seperti yang ditunjukkan dalam jawaban lain:
FormatMessage
mengambilDWORD
hasil bukanHRESULT
(biasanyaGetLastError()
).LocalFree
diperlukan untuk melepaskan memori yang telah dialokasikan olehFormatMessage
Saya mengambil poin di atas dan menambahkan beberapa lagi untuk jawaban saya:
FormatMessage
dalam kelas untuk mengalokasikan dan melepaskan memori sesuai kebutuhanoperator LPTSTR() const { return ...; }
agar kelas Anda dapat digunakan sebagai stringclass CFormatMessage { public: CFormatMessage(DWORD dwMessageId, DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)) : m_text(NULL) { Assign(dwMessageId, dwLanguageId); } ~CFormatMessage() { Clear(); } void Clear() { if (m_text) { LocalFree(m_text); m_text = NULL; } } void Assign(DWORD dwMessageId, DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)) { Clear(); DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessage( dwFlags, NULL, dwMessageId, dwLanguageId, (LPTSTR) &m_text, 0, NULL); } LPTSTR text() const { return m_text; } operator LPTSTR() const { return text(); } protected: LPTSTR m_text; };
Temukan versi yang lebih lengkap dari kode di atas di sini: https://github.com/stephenquan/FormatMessage
Dengan kelas di atas, penggunaannya sederhana:
std::wcout << (LPTSTR) CFormatMessage(GetLastError()) << L"\n";
sumber
Kode di bawah ini adalah kode yang setara dengan C ++ yang telah saya tulis berbeda dengan Microsoft's ErrorExit () tetapi sedikit diubah untuk menghindari semua makro dan menggunakan unicode. Idenya di sini adalah untuk menghindari cast dan mallocs yang tidak perlu. Saya tidak bisa lepas dari semua pemain C tapi ini yang terbaik yang bisa saya kumpulkan. Berkenaan dengan FormatMessageW (), yang membutuhkan pointer untuk dialokasikan oleh fungsi format dan Id Error dari GetLastError (). Penunjuk setelah static_cast dapat digunakan seperti penunjuk wchar_t biasa.
#include <string> #include <windows.h> void __declspec(noreturn) error_exit(const std::wstring FunctionName) { // Retrieve the system error message for the last-error code const DWORD ERROR_ID = GetLastError(); void* MsgBuffer = nullptr; LCID lcid; GetLocaleInfoEx(L"en-US", LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (wchar_t*)&lcid, sizeof(lcid)); //get error message and attach it to Msgbuffer FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ERROR_ID, lcid, (wchar_t*)&MsgBuffer, 0, NULL); //concatonate string to DisplayBuffer const std::wstring DisplayBuffer = FunctionName + L" failed with error " + std::to_wstring(ERROR_ID) + L": " + static_cast<wchar_t*>(MsgBuffer); // Display the error message and exit the process MessageBoxExW(NULL, DisplayBuffer.c_str(), L"Error", MB_ICONERROR | MB_OK, static_cast<WORD>(lcid)); ExitProcess(ERROR_ID); }
sumber