2011-10-27 16 views
11

私は、Win32の構造化された例外を再び扱わなければならなくなりました。私は例外を記述する文字列を生成しようとしています。そのほとんどは簡単ですが、私は何か基本的なことに固執しています。例外コードを(例外のコードをGetExceptionCode()またはExceptionCodeEXCEPTION_RECORDに変換して)例外を説明する文字列に変換するにはどうすればよいですか?Win32例外コードを文字列に変換するにはどうすればよいですか?

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

+0

はい、 'FormatMessage'はトリックを行う必要があります。 – avakar

答えて

3

はい。それはNTSTATUSなのでFORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULEを使用し、LoadLibrary("NTDLL.DLL")

Source

+0

Win32はさらに別のエラーコードのセットです。 – MSalters

+0

ありがとう、それは非常にほぼ動作します。残念ながら、NTDLL.DLLの文字列は、FormatMessageの正しい形式コードを使用していないようです。 0xc0000005の文字列は '%pの命令を%pで参照しています。'と思いますが、どのFormatMessageが '0x'(命令)の命令に変換されるのでしょうか。この[関連する質問](http://stackoverflow.com/questions/321898/how-to-get-the-name-description-of-an-exception)も参照してください。 –

+0

あなたは実際の住所を渡しましたか? 'FormatMessage'は2つの'%p'パラメータを見て、最初のアドレスのフォーマットに失敗したように見えます。 – MSalters

7

からHMODULEを通過する構造化例外コードはNTSTATUS番号によって定義されます。 MS suggestsから誰かがNTSTATUS数値を文字列に変換するのにFormatMessage()を使用していますが、私はこれをしません。フラグFORMAT_MESSAGE_FROM_SYSTEMは、GetLastError()の結果を文字列に変換するために使用されるため、ここでは意味がありません。フラグFORMAT_MESSAGE_FROM_HMODULEntdll.dllを一緒に使用すると、一部のコードでは誤った結果になります。たとえば、EXCEPTION_ACCESS_VIOLATIONの場合は、The instruction at 0xが得られますが、これはあまり有益ではありません。

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

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

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

あなたはntdll.dllから文字列をロードし、また、vprintfするためにそれを渡したいかもしれませんが、あなたは、文字列を指定します(例えばEXCEPTION_ACCESS_VIOLATIONのために、それはだunsigned longunsigned longchar*)とまったく同じ引数を準備する必要があります。そして、このアプローチには重大な欠点があります:ntdll.dllの引数の数、順序またはサイズを変更するとコードが壊れる可能性があります。

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

+0

あなたの答えをありがとう! (質問はかなり古いものですが)他の回答についての私のコメントを見ると、あなたが言及した問題を発見したことがわかります。私は厄介なメッセージを特別に扱いました。私はあなたが示唆するようにすべてをハードコーディングすることを好むと思う。 (特に、将来的にはエラーが追加される可能性があるため) –

+0

もちろん、味の問題です。コード番号(指定した可能性のある新しいエラーに役立つ)、文字列表現(例:「EXCEPTION_INVALID_DISPOSITION」)、およびEXCEPTION_RECORD構造体の他の値を印刷することを選択しました。私のニーズには十分です。エンドユーザーに冗長な説明を表示することは意味がないと思います。とにかくほとんどの人はそれをほとんど理解しません。また、高度なものであっても有用ではなく、あなたのプログラムを修正することはありません。エンドユーザーは調査のためにその情報を開発者に渡すだけです。また、私は開発者としてインターネットのエラーコードの最新の説明を読むことができます。 – 4LegsDrivenCat

1

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; 
} 
+0

0xC0000005が与えられたら、それは何をしますか? –

+0

@AlanStokes ERROR_NOACCESSに変換されます(英語のローカリゼーションでは「メモリの場所へのアクセスが無効です」)。 –

関連する問題