PaulH PaulH - 1 month ago 18
C++ Question

Turning GetLastError() in to an exception

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.

Thanks,
PaulH

Answer

Note that if the back_inserter causes std::bad_alloc to be thrown, the memory allocated inside FormatMessage is leaked.