我不情愿地再次处理 Win32 结构化异常。我正在尝试生成一个描述异常的字符串。大部分都很简单,但我坚持一些基本的问题:如何将异常代码(的结果GetExceptionCode()
或ExceptionCode
an 的成员EXCEPTION_RECORD
)转换为描述异常的字符串?
我正在寻找可以将例如 0xC0000005 转换为“访问冲突”的东西。这只是一个电话FormatMessage()
吗?
结构化异常代码是通过 NTSTATUS 编号定义的。虽然来自 MS 的人建议使用FormatMessage()将 NTSTATUS 数字转换为字符串,但我不会这样做。FlagFORMAT_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
可能破坏您的代码。
因此,将字符串硬编码到您自己的代码中会更安全、更容易。我发现在没有与我协调的情况下使用其他人准备的字符串是很危险的:) 以及其他功能。这只是故障的另一种可能性。
是的。它是 a NTSTATUS
,所以使用FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE
并传递HMODULE
fromLoadLibrary("NTDLL.DLL")
正确管理某些 NTSTATUS 字符串具有的流格式很复杂。您应该考虑使用RtlNtStatusToDosError()将其转换为 Win32 消息,该消息位于标头 Winternl.h 中。您需要在链接器输入中包含 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;
}
我建议你使用 bugslayer。只需调用GetFaultReason
.EXCEPTION_POINTERS
GetFirstStackTraceString
此外,您可以使用and遍历堆栈GetNextStackTraceString
。