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

l7mqbcuq  于 2023-08-03  发布在  其他
关注(0)|答案(4)|浏览(111)

我不情愿地不得不再次处理Win32结构化异常。我正在尝试生成一个描述异常的字符串。大部分都很简单,但我被一些基本的东西卡住了:如何将异常代码(GetExceptionCode()的结果,或EXCEPTION_RECORDExceptionCode成员)转换为描述异常的字符串?
我正在寻找的东西,将转换为例如0xC0000005“访问违规”。它只是对FormatMessage()的调用吗?

llew8vvj

llew8vvj1#

结构化异常代码通过NTSTATUS编号定义。虽然有人从MS建议here(这篇文章已被转移到here)使用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.
FormatMessage()%0视为转义序列,表示消息终止符,而不是插入。插入为%1到%99。这就是为什么标志FORMAT_MESSAGE_IGNORE_INSERTS没有任何区别。
您可能希望从ntdll.dll加载字符串并将其传递给vprintf(),但您需要完全按照字符串指定的方式准备参数(例如:对于EXCEPTION_ACCESS_VIOLATION,它是unsigned longunsigned longchar*)。这种方法有一个主要缺点:ntdll.dll中参数的数量、顺序或大小的任何更改都可能破坏代码。
因此,将字符串硬编码到您自己的代码中更安全、更容易。我发现在没有与我协调的情况下使用其他人准备的字符串是危险的:),而且用于其他函数。这只是故障的另一种可能性。

ijnw1ujt

ijnw1ujt2#

是的。它是一个NTSTATUS,所以使用FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE,并从LoadLibrary("NTDLL.DLL")传递HMODULE
Source: KB259693 (archived)

mrfwxfqh

mrfwxfqh3#

正确管理某些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;
}

字符集

6jjcrrmo

6jjcrrmo4#

我建议你use bugslayer。只需使用EXCEPTION_POINTERS调用GetFaultReason
此外,您可以使用GetFirstStackTraceStringGetNextStackTraceString遍历堆栈。

相关问题