なし:
FormatMessage()
を使用してHRESULT
のエラーテキストを取得するにはどうすればよいですか?
HRESULT hresult = application.CreateInstance("Excel.Application");
if (FAILED(hresult))
{
// what should i put here to obtain a human-readable
// description of the error?
exit (hresult);
}
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は挿入の使用方法について少し不明確ですが、システムメッセージを取得するときは、システムがどの挿入を予期しているかを知る方法がないため、 レイモンドチェンはそれらを使用してはいけないことに注意 .
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の一部ではありません。
次のことはできないことに注意してください。
{
LPCTSTR errorText = _com_error(hresult).ErrorMessage();
// do something with the error...
//automatic cleanup when error goes out of scope
}
クラスが作成され、スタック上で破棄され、errorTextが無効な場所を指すようにします。ほとんどの場合、この場所には引き続きエラー文字列が含まれますが、スレッド化されたアプリケーションを作成すると、その可能性は急速に低下します。
always上記のShog9の回答に従って、次のように実行します。
{
_com_error error(hresult);
LPCTSTR errorText = error.ErrorMessage();
// do something with the error...
//automatic cleanup when error goes out of scope
}
これを試して:
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);
}
以下は、Unicodeを処理するDavidの関数のバージョンです
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);
}
これは回答の大部分に追加されたものですが、LocalFree(errorText)
を使用する代わりにHeapFree
関数を使用します。
::HeapFree(::GetProcessHeap(), NULL, errorText);
Windows 10:
LocalFreeは最新のSDKに含まれていないため、結果バッファーを解放するために使用することはできません。代わりに、HeapFree(GetProcessHeap()、locatedMessage)を使用してください。この場合、これはメモリでLocalFreeを呼び出すのと同じです。
更新LocalFree
がSDKのバージョン10.0.10240.0(WinBase.hの1108行目)にあることがわかりました。ただし、上記のリンクには警告が引き続き存在します。
#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
更新2
また、FORMAT_MESSAGE_MAX_WIDTH_MASK
フラグは、システムメッセージの改行を整理します。
FORMAT_MESSAGE_MAX_WIDTH_MASK
この関数は、メッセージ定義テキスト内の通常の改行を無視します。この関数は、ハードコードされた改行をメッセージ定義テキストに出力バッファーに保存します。この関数は、新しい改行を生成しません。
アップデート3
推奨されるアプローチを使用しても、完全なメッセージを返さない2つの特定のシステムエラーコードがあるようです。
C++ 11以降、FormatMessage
の代わりに標準ライブラリを使用できます。
#include <system_error>
std::string message = std::system_category().message(hr)
他の回答で指摘されているように:
FormatMessage
は、DWORD
ではなくHRESULT
の結果を取ります(通常はGetLastError()
)。LocalFree
は、FormatMessage
によって割り当てられたメモリを解放するために必要です。私は上記のポイントを取り、私の答えにいくつか追加しました:
FormatMessage
をクラスでラップして、必要に応じてメモリを自動的に割り当て、解放しますoperator LPTSTR() const { return ...; }
class CFormatMessage
{
public:
CFormatMessage(DWORD dwError) : m_ErrorText(NULL) { Assign(dwError); }
~CFormatMessage() { Clear(); }
void Clear() { if (m_ErrorText != NULL) { LocalFree(m_ErrorText); m_ErrorText = NULL; } }
void Assign(DWORD dwError) {
Clear();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&m_ErrorText,
0,
NULL);
}
LPTSTR ErrorText() const { return m_ErrorText; }
operator LPTSTR() const { return ErrorText(); }
protected:
LPTSTR m_ErrorText;
};
上記のコードのより完全なバージョンをここで見つけてください: https://github.com/stephenquan/FormatMessage
上記のクラスでは、使用方法は次のとおりです。
std::wcout << (LPTSTR) CFormatMessage(GetLastError()) << L"\n";
以下のコードは、 MicrosoftのErrorExit() とは対照的に記述したC++の同等物ですが、すべてのマクロを避けてUnicodeを使用するようにわずかに変更されています。ここでの考え方は、不必要なキャストとmallocを避けることです。私はすべてのCキャストを逃れることはできませんでしたが、これは私が召集できる最高のものです。 FormatMessageW()に関連します。これは、format関数とGetLastError()からのエラーIDによって割り当てられるポインターを必要とします。 static_castの後のポインターは、通常のwchar_tポインターのように使用できます。
#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);
}