Turning GetLastError () into an exception

I have a Visual Studio 2008 C ++ project that uses a class Win32Exceptionin cases where an exceptional error exists. The class is Win32Exceptionas follows:

/// 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 situations in which it was used. What I would like to know is if there are obvious cases when this will not succeed, which I should know about. Any other corrections, reservations or general suggestions for improvements are welcome.

Note that boost library is not an option for this code.

+5
source share
6 answers

, back_inserter std::bad_alloc, , FormatMessage.

+3
  • ! ! .

  • :

        // this may generate a C4244 warning. It is safe to ignore.
        std::copy( error_messageW, 
                   error_messageW + len, 
                   std::back_inserter( error_messageA ) );
    

    WCHARs . FormatMessageA, (, , ), , UTF-8. , . .

  • . .

+3
  • FormatMessage . " % d" .
  • (ERROR_ALREADY_EXISTS), .
  • (, SHFileOperation), . , , .
  • : ( ), , ( , , , , ). .
+1

, , , . , .

, , - ERROR_SUCCESS. , - , " ". , , .

, , , " ", , , .

, Windows + . , ++. , .

, , , .

ErrorMessage , , , , . . .

ErrorMessage , . return .

hth.,

+1

, . , , , ::FormatMessage, ::LocalFree . , , .

:

class windows_error {
public:
    windows_error(wchar_t const* what);

    // Getter functions
    unsigned long errorCode() const { return _code; }
    wchar_t const* description() const { return _what; }
    std::wstring errorMessage() const { return _sys_err_msg; }
private:
    unsigned long _code;
    wchar_t const* _what;
    std::wstring _sys_err_msg;
};

// This class outsources the problem of managing the string which
// was allocated with ::LocalAlloc by the ::FormatMessage function.
// This is necessary to make the constructor of windows_error exception-safe.
class LocalAllocHelper {
public:
    LocalAllocHelper(wchar_t* string) : _string(string) { }
    ~LocalAllocHelper() {
        ::LocalFree(_string);
    }

    LocalAllocHelper(LocalAllocHelper const& other) = delete;
    LocalAllocHelper(LocalAllocHelper && other) = delete;
    LocalAllocHelper& operator=(LocalAllocHelper const& other) = delete;
    LocalAllocHelper& operator=(LocalAllocHelper && other) = delete;

private:
    wchar_t* _string;
};

windows_error::windows_error(wchar_t const* what)
    : _code(::GetLastError()),
      _what(what) {
    // Create a temporary pointer to a wide string for the error message
    LPWSTR _temp_msg = 0;
    // Retrieve error message from error code and save the length
    // of the buffer which is being returned. This is needed to 
    // implement the copy and assignment constructor.
    DWORD _buffer_size = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                                          FORMAT_MESSAGE_FROM_SYSTEM |
                                          FORMAT_MESSAGE_IGNORE_INSERTS, 
                                          NULL, _code, 0, _temp_msg, 0, NULL);

    if(_buffer_size) {
        // When calling _sys_err_msg.resize an exception could be thrown therefore
        // the _temp_msg needs to be a managed resource.
        LocalAllocHelper helper(_temp_msg);
        _sys_err_msg.resize(_buffer_size + 1);
        std::copy(_temp_msg, _temp_msg + _buffer_size, _sys_err_msg.begin());
    }
    else {
        _sys_err_msg = std::wstring(L"Unknown error. (FormatMessage failed)");
    }
}

, .

0

, , , , V++ 2015 system_error, system_category():

try
{
    throw system_error(E_ACCESSDENIED, system_category(), "Failed to write file");
}
catch (exception& ex)
{
    cout << ex.what();
}

: " : "

0

All Articles