如何将Win32异常代码转换为字符串?

时间:2011-10-27 11:27:56

标签: c winapi seh

我不情愿地再次处理Win32结构化异常。我正在尝试生成描述异常的字符串。大部分都是直截了当的,但我坚持一些基本的东西:如何将异常代码(GetExceptionCode()的结果或ExceptionCode的{​​{1}}成员)转换为描述异常的字符串?

我正在寻找能够将例如0xC0000005转换为“访问冲突”的内容。只是拨打EXCEPTION_RECORD吗?

4 个答案:

答案 0 :(得分:9)

结构化异常代码通过NTSTATUS编号定义。虽然来自MS suggests的某人使用FormatMessage()将NTSTATUS号码转换为字符串,但我不会这样做。标记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.

%0FormatMessage()视为转义序列,意味着消息终止符,而不是插入。插入是%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}}

Source: KB259693 (archived)

答案 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

另外,您可以使用GetFirstStackTraceStringGetNextStackTraceString遍历堆栈。