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

发布于 2024-12-12 02:49:06 字数 239 浏览 0 评论 0原文

我很不情愿地再次处理 Win32 结构化异常。我正在尝试生成一个描述异常的字符串。其中大部分都很简单,但我坚持一些基本的事情:如何转换异常代码(GetExceptionCode() 的结果,或EXCEPTION_RECORD)转换成描述异常的字符串?

我正在寻找可以将 0xC0000005 转换为“访问冲突”的东西。它只是对 FormatMessage() 的调用吗?

I'm reluctantly having to deal with Win32 structured exceptions again. I'm trying to generate a string describing an exception. Most of it is straightforward, but I'm stuck on something basic: how can I convert an exception code (the result of GetExceptionCode(), or the ExceptionCode member of an EXCEPTION_RECORD) into a string describing the exception?

I'm looking for something that will convert eg 0xC0000005 to "Access Violation". Is it just a call to FormatMessage()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

喜你已久 2024-12-19 02:49:06

结构化异常代码是通过 NTSTATUS 编号定义的。尽管微软的某人建议此处(该文章已移至此处)使用 FormatMessage() 将 NTSTATUS 数字转换为字符串,我不会这样做。标志 FORMAT_MESSAGE_FROM_SYSTEM 用于转换 GetLastError() 到一个字符串中,所以这里没有意义。将标志 FORMAT_MESSAGE_FROM_HMODULEntdll.dll 一起使用将导致某些代码产生不正确的结果。例如,对于EXCEPTION_ACCESS_VIOLATION,您将得到The instructions at 0x,它的信息量不是很大:)。

当您查看存储在 ntdll.dll 中的字符串时,很明显,其中许多字符串应该与 printf() 函数,不与 FormatMessage()。例如,EXCEPTION_ACCESS_VIOLATION 的字符串为:

0x%08lx 处的指令引用了 0x%08lx 处的内存。内存不能为 %s。

%0FormatMessage() 作为转义序列,表示消息终止符,而不是插入。插入为 %1 到 %99。这就是为什么标志 FORMAT_MESSAGE_IGNORE_INSERTS 没有任何区别。

您可能希望从 ntdll.dll 加载字符串并将其传递给 vprintf() 但您需要完全按照字符串指定的方式准备参数(例如,对于EXCEPTION_ACCESS_VIOLATION,它是unsigned long无符号长char*)。这种方法有一个主要缺点:ntdll.dll 中参数的数量、顺序或大小的任何更改都可能会破坏您的代码。

因此,将字符串硬编码到您自己的代码中更安全、更容易。我发现在没有与我协调的情况下使用其他人准备的字符串是危险的:),而且对于其他功能也是如此。这只是故障的另一种可能性。

Structured exception codes are defined through NTSTATUS numbers. Although someone from MS suggests here (the article has been moved to here) using FormatMessage() to convert NTSTATUS numbers to strings, I would not do this. Flag FORMAT_MESSAGE_FROM_SYSTEM is used to convert result of GetLastError() into a string, so it makes no sense here. Using flag FORMAT_MESSAGE_FROM_HMODULE along with ntdll.dll will lead to incorrect results for some codes. E.g., for EXCEPTION_ACCESS_VIOLATION you will get The instruction at 0x, which is not very informative :) .

When you look at the strings that are stored in ntdll.dll it becomes obvious that many of them are supposed to be used with the printf() function, not with the FormatMessage(). For example, the string for EXCEPTION_ACCESS_VIOLATION is:

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0 is treated by FormatMessage() as the escape sequence meaning message terminator, not an insert. Inserts are %1 to %99. That's why flag FORMAT_MESSAGE_IGNORE_INSERTS does not make any difference.

You might want to load the string from ntdll.dll and pass it to vprintf() but you will need to prepare arguments exactly as the string specifies (e.g. for EXCEPTION_ACCESS_VIOLATION it's unsigned long, unsigned long, char*). And this approach has major drawback: any change in the number, order or size of arguments in ntdll.dll may break your code.

So it's safer and easier to hard code the strings into your own code. I find it dangerous to use strings prepared by someone else without coordination with me :) and moreover for other function. This is just one more possibility for malfunction.

是的。这是一个 NTSTATUS,因此请使用 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE,并从 LoadLibrary("NTDLL.DLL") 传递 HMODULE >

<一href="https://web.archive.org/web/20150121053632/http://support.microsoft.com/kb/259693" rel="noreferrer">来源:KB259693(已存档)

Yes. It's a NTSTATUS, so use FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE, and pass the HMODULE from LoadLibrary("NTDLL.DLL")

Source: KB259693 (archived)

意犹 2024-12-19 02:49:06

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

It is complicated to correctly manage the stream format some of the NTSTATUS strings have. You should consider converting it into a Win32 message with RtlNtStatusToDosError(), which comes in header Winternl.h. You'll need to have ntdll.lib in your linker input.

Example implementation:

// 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;
}
满天都是小星星 2024-12-19 02:49:06

我建议您 使用 bugslayer 。只需使用 EXCEPTION_POINTERS 调用 GetFaultReason 即可。

此外,您还可以使用 GetFirstStackTraceString 和 GetNextStackTraceString 遍历堆栈。

I suggest that you use bugslayer. Just call GetFaultReason with the EXCEPTION_POINTERS.

Additionally you could walk the stack using GetFirstStackTraceString and GetNextStackTraceString.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文