Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I convert a Win32 exception code to a string?

Tags:

c

winapi

seh

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()?

like image 830
Alan Stokes Avatar asked Oct 27 '11 11:10

Alan Stokes


People also ask

What is a Win32 exception?

Win32 exceptions are typically exceptions mapped from errors returned from P/Invoked Windows API routines. To be able to debug them properly, you may need to check "Enable native debugging" in project and/or ide settings.

How do I get error messages in C++?

C++ perror() The perror() function in C++ prints the error message to stderr based on the error code currently stored in the system variable errno.


2 Answers

Structured exception codes are defined through NTSTATUS numbers. Although someone from MS suggests 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.

like image 119
4LegsDrivenCat Avatar answered Oct 15 '22 09:10

4LegsDrivenCat


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)

like image 11
MSalters Avatar answered Oct 15 '22 09:10

MSalters