92

Without:

  • MFC
  • ATL

How can I use FormatMessage() to get the error text for a 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);
 }
4

8 に答える 8

137

システムから返されるエラー メッセージを取得する適切な方法を次に示します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 は、システム メッセージを取得するときに挿入を使用してはならないことを指摘しています。

_com_errorFWIW、Visual C++ を使用している場合は、次のクラスを使用して作業を少し楽にすることができます。

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();
   
   // do something with the error...

   //automatic cleanup when error goes out of scope
}

私の知る限り、MFC または ATL の一部ではありません。

于 2009-01-18T17:32:16.423 に答える
14

次のことはできませんのでご注意ください。

{
   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
}
于 2009-09-16T22:15:28.663 に答える
11

Try this:

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);
}
于 2009-01-18T16:57:41.313 に答える
5

これは、回答の大部分への追加ですが、使用する代わりに関数をLocalFree(errorText)使用します。HeapFree

::HeapFree(::GetProcessHeap(), NULL, errorText);

MSDN サイトから:

Windows 10 :
LocalFree は最新の SDK に含まれていないため、結果バッファーを解放するために使用することはできません。代わりに、HeapFree (GetProcessHeap(), allocatedMessage) を使用してください。この場合、これはメモリ上で 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

Update 2フラグを使用して、システム メッセージの改行を整理する
こともお勧めします。FORMAT_MESSAGE_MAX_WIDTH_MASK

MSDN サイトから:

FORMAT_MESSAGE_MAX_WIDTH_MASK
関数は、メッセージ定義テキストの通常の改行を無視します。この関数は、メッセージ定義テキスト内のハードコーディングされた改行を出力バッファーに格納します。関数は新しい改行を生成しません。

更新 3
推奨される方法を使用しても完全なメッセージが返されない 2 つの特定のシステム エラー コードがあるようです。

FormatMessage が ERROR_SYSTEM_PROCESS_TERMINATED および ERROR_UNHANDLED_EXCEPTION システム エラーの部分的なメッセージしか作成しないのはなぜですか?

于 2015-07-21T13:57:25.693 に答える
0

以下のコードは、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);
}
于 2017-11-15T04:26:16.093 に答える