diff --git a/include/boost/system/detail/system_category_win32.hpp b/include/boost/system/detail/system_category_win32.hpp index 99d0990..ff07ac2 100644 --- a/include/boost/system/detail/system_category_win32.hpp +++ b/include/boost/system/detail/system_category_win32.hpp @@ -12,6 +12,7 @@ #include #include #include +#include // @@ -86,10 +87,63 @@ inline char const * system_category_message_win32( int ev, char * buffer, std::s return buffer; } +struct local_free +{ + void * p_; + + ~local_free() + { + boost::winapi::LocalFree( p_ ); + } +}; + inline std::string system_category_message_win32( int ev ) { - char buffer[ 256 ]; - return system_category_message_win32( ev, buffer, sizeof( buffer ) ); + using namespace boost::winapi; + + void * lpMsgBuf = 0; + + DWORD_ retval = boost::winapi::FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER_ | FORMAT_MESSAGE_FROM_SYSTEM_ | FORMAT_MESSAGE_IGNORE_INSERTS_, + NULL, + ev, + MAKELANGID_( LANG_NEUTRAL_, SUBLANG_DEFAULT_ ), // Default language + (LPWSTR_) &lpMsgBuf, + 0, + NULL + ); + + local_free lf_ = { lpMsgBuf }; + + if( retval == 0 ) + { + return "Unknown error"; + } + + std::string buffer( retval * 2 + 1, char() ); + + int r = boost::winapi::WideCharToMultiByte( CP_ACP_, 0, static_cast( lpMsgBuf ), -1, &buffer[0], static_cast( buffer.size() ), NULL, NULL ); + + if( r == 0 ) + { + return "Unknown error"; + } + + --r; // exclude null terminator + + while( r > 0 && ( buffer[ r-1 ] == '\n' || buffer[ r-1 ] == '\r' ) ) + { + --r; + } + + if( r > 0 && buffer[ r-1 ] == '.' ) + { + --r; + } + + buffer.resize( r ); + + return buffer; } inline error_condition system_category_default_error_condition_win32( int ev ) BOOST_NOEXCEPT diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 893f364..7fbff70 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -125,6 +125,7 @@ system-run win32_hresult_test.cpp ; system-run error_category_test.cpp ; system-run generic_category_test.cpp ; +system-run system_category_test.cpp ; # Quick (CI) test run quick.cpp ; diff --git a/test/generic_category_test.cpp b/test/generic_category_test.cpp index 63e813a..0d53815 100644 --- a/test/generic_category_test.cpp +++ b/test/generic_category_test.cpp @@ -25,7 +25,7 @@ int main() // message - for( int i = -1; i < 1024; ++i ) + for( int i = -2; i < 1024; ++i ) { { BOOST_TEST_CSTR_EQ( cat.message( i ).c_str(), std::strerror( i ) ); diff --git a/test/system_category_test.cpp b/test/system_category_test.cpp new file mode 100644 index 0000000..663fae7 --- /dev/null +++ b/test/system_category_test.cpp @@ -0,0 +1,112 @@ + +// Copyright 2018 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/system + +// Avoid spurious VC++ warnings +# define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include + +// + +#if defined(BOOST_WINDOWS_API) + +#include + +std::string sys_strerror( int ev ) +{ + void * lpMsgBuf = 0; + + DWORD retval = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + + struct local_free + { + void * p_; + + ~local_free() + { + LocalFree( p_ ); + } + }; + + local_free lf_ = { lpMsgBuf }; + + if( retval == 0 ) + { + return "Unknown error"; + } + + std::string str( static_cast( lpMsgBuf ) ); + + while( !str.empty() && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + { + str.erase( str.size()-1 ); + } + + if( !str.empty() && str[str.size()-1] == '.' ) + { + str.erase( str.size()-1 ); + } + + return str; +} + +#else + +std::string sys_strerror( int ev ) +{ + return std::strerror( ev ); +} + +#endif + +// + +namespace sys = boost::system; + +static void test_message( sys::error_category const & cat, int ev ) +{ + BOOST_TEST_EQ( cat.message( ev ), sys_strerror( ev ) ); + + char buffer[ 2048 ]; // yes, really + BOOST_TEST_CSTR_EQ( cat.message( ev, buffer, sizeof( buffer ) ), sys_strerror( ev ).c_str() ); +} + +int main() +{ + sys::error_category const & cat = sys::system_category(); + + // message + + for( int i = -2; i < 1024; ++i ) + { + test_message( cat, i ); + } + + test_message( cat, 5810 ); + + for( int i = 10000; i < 11032; ++i ) + { + test_message( cat, i ); + } + + return boost::report_errors(); +}