#pragma once
// Copyright (c) 2011, Alf P. Steinbach
//-------------------------------------------------- Dependencies:
#include <progrock/compiler_specific/fixups.h> // CPPX_NOEXCEPT
#include <progrock/cppx/error_handling.h> // cppx::throwX etc.
#include <progrock/cppx/string_building.h> // S
#include <progrock/winapi/wrapper/windows_h.h>
#include <system_error>
//-------------------------------------------------- Interface:
#ifndef CPPX_NOEXCEPT
# define CPPX_NOEXCEPT noexcept
#endif
namespace progrock{ namespace winapi{
using std::string;
typedef DWORD ErrorCode;
typedef cppx::narrow::S NarrowS;
namespace errorMessage {
inline string fromApi( ErrorCode const code )
{
struct RawMessage
{
char const* p;
RawMessage(): p(0) {}
~RawMessage() { ::LocalFree( const_cast<char*>( p ) ); }
};
RawMessage message;
int const stringLength = FormatMessageA(
0 | FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
0, // lpSource
code,
MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
reinterpret_cast<char*>( &message.p ),
0, // nSize
0
);
// Just in case message.p isn't set:
if( stringLength == 0 ) { return ""; }
// Remove trailing control chars:
char const* pEnd = message.p + stringLength;
for( ;; )
{
if( pEnd == message.p ) { break; }
if( *(pEnd - 1) >= ' ' ) { break; }
--pEnd;
}
return string( message.p, pEnd );
}
inline string withCode( ErrorCode code, string const& text )
{
return NarrowS() << text << " (code " << code << ")";
}
inline string forUnknown( ErrorCode const code )
{
return withCode( code, "Unknown error" );
}
inline string explaining( ErrorCode const code )
{
if( code == 0 )
{
// ERROR_SUCCESS.
// Instead of "The operation completed successfully.":
return forUnknown( code );
}
string const rawMessage = fromApi( code );
if( rawMessage.length() == 0 )
{
return forUnknown( code );
}
return withCode( code, rawMessage );
}
} // namespace errorMessage
class WinApiErrorCategory
: public std::error_category
{
public:
virtual const char* name() const CPPX_NOEXCEPT
{
return "WindowsApiError";
}
virtual std::error_condition default_error_condition( int code ) const CPPX_NOEXCEPT
{
return std::error_condition( code, *this );
}
virtual string message( int code ) const
{
return errorMessage::explaining( code );
}
};
inline std::error_category const& winApiErrorCategory()
{
static WinApiErrorCategory const theInstance;
return theInstance;
}
class WinApiError
: public std::system_error
{
private:
mutable std::string fullDescription_;
public:
char const* what() const CPPX_NOEXCEPT
{
if( fullDescription_.length() == 0 )
{
fullDescription_ = NarrowS()
<< std::system_error::what() << ": " << code().message()
<< NarrowS::toString;
}
return fullDescription_.c_str();
}
WinApiError( int code, std::string const& description )
: std::system_error(
std::error_code( code, winApiErrorCategory() ),
description
)
{}
virtual ~WinApiError() CPPX_NOEXCEPT {}
};
bool throwX( ErrorCode errorCode, string const& s )
{
throw WinApiError( errorCode, s );
}
} } // namespace progrock::winapi