I have a Visual Studio 2008 C++ project that uses a Win32Exception
class in cases where there is an exceptional error. The Win32Exception
class looks like this:
/// defines an exception based on Win32 error codes. The what() function will
/// return a formatted string returned from FormatMessage()
class Win32Exception : public std::runtime_error
{
public:
Win32Exception() : std::runtime_error( ErrorMessage( &error_code_ ) )
{
};
virtual ~Win32Exception() { };
/// return the actual error code
DWORD ErrorCode() const throw() { return error_code_; };
private:
static std::string ErrorMessage( DWORD* error_code )
{
*error_code = ::GetLastError();
std::string error_messageA;
wchar_t* error_messageW = NULL;
DWORD len = ::FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
*error_code,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
reinterpret_cast< LPWSTR >( &error_messageW ),
0,
NULL );
if( NULL != error_messageW )
{
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
::LocalFree( error_messageW );
}
return error_messageA;
};
/// error code returned by GetLastError()
DWORD error_code_;
}; // class Win32Exception
The class works well in the situations it has been used in. What I would like to know is if there are any obvious cases where this will fail that I should be aware of. Any other gotchas, caveats, or general suggestions on improvements are welcome.
Please note that the boost library is not an option for this code.
An application can retrieve the last-error code by using the GetLastError function; the error code may tell more about what actually occurred to make the function fail. The documentation for system functions will indicate the conditions under which the function sets the last-error code.
GetLastError() returns an integer value, not a text message.
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.
Ironically, your code is not exception safe.
if( NULL != error_messageW )
{
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
::LocalFree( error_messageW );
}
Note that if the back_inserter
causes std::bad_alloc
to be thrown, the memory allocated inside FormatMessage
is leaked.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With