14

しぶしぶ、Win32 構造化例外を再び処理する必要があります。例外を説明する文字列を生成しようとしています。そのほとんどは簡単ですが、基本的なことに行き詰まっています: 例外コード ( の結果GetExceptionCode()、または のExceptionCodeメンバーEXCEPTION_RECORD) を例外を説明する文字列に変換するにはどうすればよいでしょうか?

たとえば、0xC0000005 を「アクセス違反」に変換するものを探しています。への呼び出しだけFormatMessage()ですか?

4

4 に答える 4

13

構造化された例外コードは、NTSTATUS 番号によって定義されます。MS の誰かがFormatMessage()を使用してNTSTATUS 番号を文字列に変換することを提案していますが、私はこれを行いません。フラグはGetLastError()の結果を文字列に変換するために使用されるため、ここでは意味がありません。flag をとともに使用すると、一部のコードで誤った結果が生じることがあります。たとえば、が得られますが、これはあまり有益ではありません :) 。FORMAT_MESSAGE_FROM_SYSTEMFORMAT_MESSAGE_FROM_HMODULEntdll.dllEXCEPTION_ACCESS_VIOLATIONThe instruction at 0x

格納されている文字列を見ると、それらの多くがFormatMessage()ではなく、 printf()関数でntdll.dll使用されることが想定されていることが明らかになります。たとえば、次の文字列は次のとおりです。EXCEPTION_ACCESS_VIOLATION

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0FormatMessage()によって、挿入ではなく、メッセージ ターミネータを意味するエスケープ シーケンスとして扱われます。挿入は %1 から %99 までです。そのため、フラグFORMAT_MESSAGE_IGNORE_INSERTSは何の違いもありません。

から文字列を読み込んでvprintf()ntdll.dllに渡したいかもしれませんが、文字列が指定するとおりに引数を準備する必要があります (たとえば、 , ,の場合)。そして、このアプローチには大きな欠点があります。引数の数、順序、またはサイズを変更すると、コードが壊れる可能性があります。EXCEPTION_ACCESS_VIOLATIONunsigned longunsigned longchar*ntdll.dll

そのため、文字列を独自のコードにハード コードする方が安全で簡単です。私との調整なしに他の誰かが準備した文字列を使用するのは危険だと思います:)さらに他の機能のために。これは、誤動作のもう 1 つの可能性です。

于 2015-10-09T18:27:30.703 に答える
10

はい。ですNTSTATUSので、を使用し、 fromFORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULEを渡しますHMODULELoadLibrary("NTDLL.DLL")

出典: KB259693 (アーカイブ)

于 2011-10-27T11:39:23.410 に答える
4

一部の NTSTATUS 文字列が持つストリーム形式を正しく管理するのは複雑です。ヘッダー Winternl.h に含まれるRtlNtStatusToDosError()を使用して Win32 メッセージに変換することを検討する必要があります。リンカー入力に ntdll.lib が必要です。

実装例:

// Returns length of resulting string, excluding null-terminator.
// Use LocalFree() to free the buffer when it is no longer needed.
// Returns 0 upon failure, use GetLastError() to get error details.
DWORD FormatNtStatus(NTSTATUS nsCode, TCHAR **ppszMessage) {

    // Get handle to ntdll.dll.
    HMODULE hNtDll = LoadLibrary(_T("NTDLL.DLL"));

    // Check for fail, user may use GetLastError() for details.
    if (hNtDll == NULL) return 0;

    // Call FormatMessage(), note use of RtlNtStatusToDosError().
    DWORD dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
        hNtDll, RtlNtStatusToDosError(nsCode), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)ppszMessage, 0, NULL);

    // Free loaded dll module and decrease its reference count.
    FreeLibrary(hNtDll);

    return dwRes;
}
于 2017-05-14T06:47:57.857 に答える