如何将 Win32 异常代码转换为字符串?
我很不情愿地再次处理 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
结构化异常代码是通过 NTSTATUS 编号定义的。尽管微软的某人建议此处(该文章已移至此处)使用 FormatMessage() 将 NTSTATUS 数字转换为字符串,我不会这样做。标志
FORMAT_MESSAGE_FROM_SYSTEM
用于转换 GetLastError() 到一个字符串中,所以这里没有意义。将标志FORMAT_MESSAGE_FROM_HMODULE
与ntdll.dll
一起使用将导致某些代码产生不正确的结果。例如,对于EXCEPTION_ACCESS_VIOLATION
,您将得到The instructions at 0x
,它的信息量不是很大:)。当您查看存储在 ntdll.dll 中的字符串时,很明显,其中许多字符串应该与 printf() 函数,不与 FormatMessage()。例如,
EXCEPTION_ACCESS_VIOLATION
的字符串为:0x%08lx 处的指令引用了 0x%08lx 处的内存。内存不能为 %s。
%0
由 FormatMessage() 作为转义序列,表示消息终止符,而不是插入。插入为 %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 flagFORMAT_MESSAGE_FROM_HMODULE
along withntdll.dll
will lead to incorrect results for some codes. E.g., forEXCEPTION_ACCESS_VIOLATION
you will getThe 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 forEXCEPTION_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 flagFORMAT_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. forEXCEPTION_ACCESS_VIOLATION
it'sunsigned long
,unsigned long
,char*
). And this approach has major drawback: any change in the number, order or size of arguments inntdll.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 useFORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE
, and pass theHMODULE
fromLoadLibrary("NTDLL.DLL")
Source: KB259693 (archived)
正确管理某些 NTSTATUS 字符串所具有的流格式很复杂。您应该考虑使用 RtlNtStatusToDosError() 将其转换为 Win32 消息,位于头文件 Winternl.h 中。您需要在链接器输入中包含 ntdll.lib。
实施示例:
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:
我建议您 使用 bugslayer 。只需使用
EXCEPTION_POINTERS
调用GetFaultReason
即可。此外,您还可以使用 GetFirstStackTraceString 和 GetNextStackTraceString 遍历堆栈。
I suggest that you use bugslayer. Just call
GetFaultReason
with theEXCEPTION_POINTERS
.Additionally you could walk the stack using
GetFirstStackTraceString
andGetNextStackTraceString
.