/** \file * Wrapper for Win32 API HANDLE. */ /* * Copyright © 2001,2004 Sofus Mortensen, Michael Geddes * * This material is provided "as is", with absolutely no warranty * expressed or implied. Any use is at your own risk. Permission to * use or copy this software for any purpose is hereby granted without * fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is * granted, provided the above notices are retained, and a notice that * the code was modified is included with the above copyright notice. * * This header is part of Comet version 2. * https://github.com/alamaison/comet */ #ifndef COMET_HANDLE_H #define COMET_HANDLE_H #include #include #include #include #include #include namespace comet { /*! \addtogroup COMType */ //@{ /** Base and policy class for auto_handle_wrap_t type. * This provides the destroy/detach operations for auto_handle_wrap_t as well as * providing a base class to contain the handle and to add functions to * that are specific to the handle type. * \relates auto_handle_wrap_t * \sa auto_handle_wrap_t */ template< typename H, long INVALID_HANDLE_ > class handle_policy_base_t { public: /// Default constructor. handle_policy_base_t() : handle_(reinterpret_cast(INVALID_HANDLE_)) {} explicit handle_policy_base_t( H handle) : handle_(handle) {} typedef H value_type; //! Implicit conversion to HANDLE operator H() const throw() { // This function seemed not to work with returning a namespaced // type. return handle_; } static inline H invalid_handle() { return reinterpret_cast(INVALID_HANDLE_) ;} /// Is the handle valid? bool valid() const { return handle_ != invalid_handle(); } /// Detach a raw handle H detach_handle() { return swap_handle(invalid_handle()); } //! Detaches currently held handle without closing it. static inline value_type detach( handle_policy_base_t &handle )throw() { return handle.detach_handle(); } protected: /// Destructor to prevent one of these from being created by itself. ~handle_policy_base_t() { } /// Detach the contained handle to the passed in. void detach_to(handle_policy_base_t &rhs) throw() { value_type handle(handle_); handle_= invalid_handle(); rhs.handle_ = handle; } H get_handle() const { return handle_; } H *get_handle_ptr() { return &handle_;} H swap_handle(H new_handle) { H old = handle_; handle_ = new_handle; return old; } private: H handle_; }; /** \class handle_nothrow_error_policy_t handle.h comet/handle.h * Nothrow Error policy. * \relates auto_handle_wrap_t */ struct handle_nothrow_error_policy_t { static void on_error() { } }; /** \class handle_throw_error_policy_t handle.h comet/handle.h * Throwing Error policy. * \relates auto_handle_wrap_t */ struct handle_throw_error_policy_t { static void on_error() { DWORD err = GetLastError(); raise_exception(HRESULT_FROM_WIN32(err)); } }; /** \class auto_handle_wrap_t handle.h comet/handle.h * Wrapper for a Win32 API/GDI HANDLE. * Behaves similarly to an auto_ptr in that it implements single-reference, * reference counting, with reference-transferring assignment and * copy-construction. */ template class auto_handle_wrap_t : public handle_policy_base_t { typedef typename handle_policy_base_t::value_type value_type; protected: /// Call destroy_handle static inline bool destroy_( value_type h) { return C_::destroy_handle(h); } /// Destroy the handle passed in. /** Must be implemented by the parent class. */ static bool destroy_handle(value_type h); typedef handle_policy_base_t policy_base ; void set_handle( value_type h ) throw() { destroy_(this->swap_handle( h)); } static bool expect_nonzero( BOOL value) { bool is_ok = (value != FALSE); if (!is_ok) ERROR_POLICY::on_error(); return is_ok; } public: /// default constructor. auto_handle_wrap_t() throw() {} /// A reference to a handle. typedef const C_ &ref; /** Assign by auto_attach. */ auto_handle_wrap_t( const impl::auto_attach_t &handle ) throw() : policy_base(handle.get()) {} /** Non-const copy constructor - takes control of the reference. * \param rhs Handle to detach from. */ auto_handle_wrap_t( auto_handle_wrap_t &rhs) throw() { rhs.detach_to(*this); } /** Non-const copy constructor - takes control of the reference. * \param rhs Handle to detach from. */ auto_handle_wrap_t( policy_base &rhs) throw() { rhs.detach_to(*this); } /** Destructor - closes the handle. */ ~auto_handle_wrap_t() throw() { destroy_(get()); } //! Assignment from similar handles. /** Typically, there might be a different error policy. */ template auto_handle_wrap_t & operator=(auto_handle_wrap_t& rhs) throw() { close_handle(); rhs.detach_to(*this); return *this; } //! Assign by auto_attach C_ &operator=(const impl::auto_attach_t &handle ) { close_handle(); set_handle(handle.get()); return *static_cast(this); } //! Closes the currently held handle (if any). bool close() throw() { return destroy_(policy_base::detach(*this)); } //! \name Accessor methods //@{ //! Fitter method. /*! Used when calling a function that take a HANDLE* argument. \code auto_handle read_pipe, write_pipe; CreatePipe(read_pipe.out(), write_pipe.out(), 0, 0)); \endcode */ typename policy_base::value_type* out() throw() { close_handle(); return this->get_handle_ptr(); } typename policy_base::value_type get() const throw() { return this->get_handle(); } typename policy_base::value_type in() const throw() { return this->get_handle(); } typename policy_base::value_type *inout() throw() { return this->get_handle_ptr(); } //@} static inline const C_ &create_const_reference(const value_type &val) { return *reinterpret_cast(&val); } static inline C_ &create_reference(value_type &val) { return *reinterpret_cast(&val); } /// Destroy a reference. static bool destroy_reference(value_type h) { return true; } private: //! Closes the currently held handle (if any). inline void close_handle() { if (!close()) ERROR_POLICY::on_error(); } }; namespace impl { /** \internal */ class THIS_IS_NOT_ALLOWED { ~THIS_IS_NOT_ALLOWED() {} }; } /// Disallow closing of a const handle. template< typename H, long INVALID_HANDLE_ > inline impl::THIS_IS_NOT_ALLOWED CloseHandle(const handle_policy_base_t&); /// Make sure closing of an auto_handle_wrap_t detaches first. /** \return true if CloseHandle was successful. */ template< typename H, long INVALID_HANDLE_ > bool CloseHandle(handle_policy_base_t &rhs) { return rhs.close(); } /// Wrapper for HANDLE type template< typename ERROR_POLICY = handle_nothrow_error_policy_t > struct auto_handle_t : auto_handle_wrap_t< auto_handle_t, HANDLE, 0, ERROR_POLICY > { typedef auto_handle_wrap_t< auto_handle_t, HANDLE, 0, ERROR_POLICY > handle_base; /// Default constructor. auto_handle_t() {} /// Copy constructor. auto_handle_t( auto_handle_t &rhs) : auto_handle_wrap_t< auto_handle_t, HANDLE, 0, ERROR_POLICY >(rhs) {} /// Auto_attach constructor. auto_handle_t( const impl::auto_attach_t< HANDLE > &rhs ) : auto_handle_wrap_t< auto_handle_t, HANDLE, 0, ERROR_POLICY >(rhs) { } /// Default assignment. auto_handle_t &operator=(auto_handle_t &rhs) { handle_base::operator=(rhs); return *this; } auto_handle_t &operator=( const impl::auto_attach_t &rhs) { handle_base::operator=(rhs); return *this; } /// Destroy a handle static bool destroy_handle( HANDLE h) { return ::CloseHandle(h) != FALSE; } }; /// Auto handle - wrapper for HANLDE. typedef auto_handle_t<> auto_handle; /// Auto handle - throwing wrapper for HANDLE. typedef auto_handle_t< handle_throw_error_policy_t > auto_handle_throw; /// Create a reference object to a handle that doesn't destroy it's contents. template struct auto_reference_t : T { auto_reference_t( const comet::impl::auto_attach_t &rhs ) : T(rhs) {} ~auto_reference_t() { destroy_reference(this->detach_handle()); } }; //@} } using comet::CloseHandle; #endif