我不情願再次處理Win32結構化異常。我試圖生成一個描述異常的字符串。大部分內容很簡單,但我堅持一些基本的東西:如何將異常代碼(GetExceptionCode()
或ExceptionCode
的成員EXCEPTION_RECORD
的成員)轉換爲描述異常的字符串?如何將Win32異常代碼轉換爲字符串?
我正在尋找的東西,將例如0xC0000005轉換爲「訪問衝突」。這只是致電嗎?
我不情願再次處理Win32結構化異常。我試圖生成一個描述異常的字符串。大部分內容很簡單,但我堅持一些基本的東西:如何將異常代碼(GetExceptionCode()
或ExceptionCode
的成員EXCEPTION_RECORD
的成員)轉換爲描述異常的字符串?如何將Win32異常代碼轉換爲字符串?
我正在尋找的東西,將例如0xC0000005轉換爲「訪問衝突」。這只是致電嗎?
是的。這是一個NTSTATUS
,所以使用FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE
,並通過HMODULE
從LoadLibrary("NTDLL.DLL")
Win32是另一組錯誤代碼。 – MSalters
謝謝,這非常有效。不幸的是,NTDLL.DLL中的字符串似乎沒有爲FormatMessage使用正確的格式代碼。 0xc0000005的字符串是'%p處的指令引用了%p處的內存',我想這是FormatMessage轉換爲'0x'(原文如此)的指令。另請參閱此[相關問題](http://stackoverflow.com/questions/321898/how-to-get-the-name-description-of-an-exception)。 –
呃,你是否在傳遞實際的地址? 'FormatMessage'看到兩個'%p'參數,輸出看起來像是沒有格式化第一個地址。 – MSalters
結構化異常代碼通過NTSTATUS數字定義。儘管MS suggests使用FormatMessage()將NTSTATUS數字轉換爲字符串,但我不會這樣做。 Flag FORMAT_MESSAGE_FROM_SYSTEM
用於將GetLastError()的結果轉換爲字符串,因此這裏沒有意義。使用標記FORMAT_MESSAGE_FROM_HMODULE
和ntdll.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 long
,unsigned long
,char*
)。這種方法有一個主要缺點:ntdll.dll
中參數的數量,順序或大小發生任何變化都可能會破壞您的代碼。
因此,將字符串硬編碼到自己的代碼中會更安全,更容易。我發現使用別人編寫的字符串而不與我協調:)是危險的,而且還有其他功能。這只是另一種故障的可能性。
感謝您的回答! (即使這個問題現在已經很老了)。如果你看看我對另一個答案的評論,你會發現我發現你提到的問題。我只是特別介紹了麻煩的信息;我認爲我更喜歡按照您的建議對所有內容進行硬編碼。 (特別是因爲將來可能會增加更多的錯誤。) –
這是一個當然的味道問題。我選擇打印代碼號(對於可能出現的新錯誤非常有用),其字符串表示形式(例如「EXCEPTION_INVALID_DISPOSITION」)和EXCEPTION_RECORD結構體中的其他值。爲了我的需要就夠了。我認爲向最終用戶顯示詳細描述是沒有意義的。無論如何,他們中的大多數人都很難理解。即使是先進的,它也不會有用,他們不會修復你的程序。最終用戶應該將這些信息傳遞給開發人員進行調查。作爲開發人員,我可以閱讀Internet上最新的錯誤代碼描述。 – 4LegsDrivenCat
正確管理某些NTSTATUS字符串所具有的流格式很複雜。你應該考慮將它轉換成一個Win32消息,其中包含頭文件Winternl.h中的RtlNtStatusToDosError()。你需要在你的鏈接器輸入中有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;
}
給定0xC0000005時會做什麼? –
@AlanStokes它將被轉換爲ERROR_NOACCESS(英文本地化:「對內存位置的訪問無效。」)。 –
是,'FormatMessage'應該做的伎倆。 – avakar