我不情愿地再次处理Win32结构化异常。我正在尝试生成描述异常的字符串。大部分都是直截了当的,但我坚持一些基本的东西:如何将异常代码(GetExceptionCode()
的结果或ExceptionCode
的{{1}}成员)转换为描述异常的字符串?
我正在寻找能够将例如0xC0000005转换为“访问冲突”的内容。只是拨打EXCEPTION_RECORD
吗?
答案 0 :(得分:9)
结构化异常代码通过NTSTATUS编号定义。虽然来自MS suggests的某人使用FormatMessage()将NTSTATUS号码转换为字符串,但我不会这样做。标记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
,{{ 1}},unsigned long
)。这种方法有一个主要缺点:char*
中参数的数量,顺序或大小的任何变化都可能会破坏您的代码。
因此,将字符串硬编码到您自己的代码中会更安全,更容易。我发现使用别人准备的字符串而不与我协调是危险的:)而且还有其他功能。这只是故障的另一种可能性。
答案 1 :(得分:5)
是。这是NTSTATUS
,因此请使用FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE
,然后传递HMODULE
的{{1}}
答案 2 :(得分:3)
正确管理一些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;
}
答案 3 :(得分:-1)
我建议您use bugslayer。只需用GetFaultReason
呼叫EXCEPTION_POINTERS
。
另外,您可以使用GetFirstStackTraceString
和GetNextStackTraceString
遍历堆栈。