/include/comet/error.h
C Header | 365 lines | 251 code | 41 blank | 73 comment | 35 complexity | 3262f6e2d9f820b41645cf478c993635 MD5 | raw file
- /** \file
- * Provide COM Error support.
- */
- /*
- * Copyright Š 2000, 2001 Sofus Mortensen
- *
- * 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.
- * http://www.lambdasoft.dk/comet
- */
-
- #ifndef COMET_ERROR_H
- #define COMET_ERROR_H
-
- #include <comet/config.h>
-
- #include <stdexcept>
- #include <string>
-
- #include <comet/error_fwd.h>
- #include <comet/bstr.h>
- #include <comet/ptr.h>
- #include <comet/uuid_fwd.h>
-
- #pragma warning(push)
- #pragma warning(disable : 4290)
-
- namespace comet {
-
- namespace impl {
-
- inline com_ptr<IErrorInfo> GetErrorInfo() throw()
- {
- IErrorInfo* ei = 0;
- ::GetErrorInfo(0, &ei);
- return com_ptr<IErrorInfo>(auto_attach(ei));
- }
-
- inline com_ptr<ICreateErrorInfo> CreateErrorInfo() throw()
- {
- ICreateErrorInfo* cei = 0;
- ::CreateErrorInfo(&cei);
- return com_ptr<ICreateErrorInfo>(auto_attach(cei));
- }
-
- template<typename Itf> inline bool supports_ErrorInfo(Itf* p)
- {
- com_ptr<ISupportErrorInfo> q = com_cast(com_ptr<Itf>(p));
- if (q == 0) return false;
- return S_OK == q->InterfaceSupportsErrorInfo(uuidof<Itf>());
- }
-
- }
-
-
- /** \class com_error error.h comet/error.h
- * COM error.
- */
- class com_error : public std::runtime_error
- {
- public:
- //! Construct com_error from HRESULT.
- /*!
- \param hr
- HRESULT value of error.
- */
- explicit com_error(HRESULT hr) : hr_(hr), std::runtime_error("")
- {}
-
- //! Construct com_error from HRESULT and textual description.
- /*!
- \param msg
- Description of error.
- \param hr
- HRESULT value of error.
- */
- explicit com_error(const bstr_t& msg, HRESULT hr = E_FAIL) : hr_(hr), std::runtime_error("")
- {
- com_ptr<ICreateErrorInfo> cei(impl::CreateErrorInfo());
- if ( !cei.is_null() ) {
- try {
- cei->SetDescription(msg.in());
- ei_ = com_ptr<IErrorInfo>( com_cast(cei)) ;
- } catch (std::bad_alloc&)
- {}
- }
- }
- //! Construct com_error from HRESULT, textual description, source, iid, help.
- /*!
- \param msg Description of error.
- \param hr HRESULT value of error.
- \param src Description of source line
- \param iid Interface the error was on
- \param helpFile Name of help file
- \param helpContext Name of help Context
- */
- explicit com_error(const bstr_t &msg, HRESULT hr, const bstr_t &src, const uuid_t &iid = uuid_t(),
- const bstr_t &helpFile=bstr_t(), DWORD helpContext = -1)
- : hr_(hr), std::runtime_error("")
- {
- com_ptr<ICreateErrorInfo> cei(impl::CreateErrorInfo());
- if ( ! cei.is_null() )
- {
- try {
- cei->SetDescription(msg.in());
- if (!src.is_null() )
- cei->SetSource( src.in() );
- if (iid != uuid_t())
- cei->SetGUID( iid );
- if (!helpFile.is_null())
- {
- cei->SetHelpFile( helpFile.in() );
- cei->SetHelpContext( helpContext );
- }
- ei_ = com_ptr<IErrorInfo>( com_cast(cei)) ;
- } catch (std::bad_alloc&)
- {}
- }
- }
-
- /// Construct with an error-info and hresult.
- explicit com_error(HRESULT hr, const com_ptr<IErrorInfo>& ei) : hr_(hr), ei_(ei), std::runtime_error("")
- {}
-
- public:
- //! Return a string with a description of the error
- /*!
- what() uses Description from IErrorInfo if such is present, otherwise FormatMessage is used
- to create a description of the HRESULT error value.
-
- \retval
- A const char* string with a textual description of the error.
- */
- const char* what() const throw()
- {
- try {
- if (what_.empty()) {
- what_ = s_str();
- }
- } catch (std::bad_alloc&) {
- return 0;
- }
-
- return what_.c_str();
- }
- /// Returns a std::string with a description of the error.
- std::string s_str() const
- {
- std::string ret;
- get_str(ret);
- return ret;
- }
- /// Returns a std::wstring with a description of the error.
- std::wstring w_str() const
- {
- std::wstring ret;
- get_str(ret);
- return ret;
- }
- /// Returns a tstring with a description of the error.
- tstring t_str() const
- {
- tstring ret;
- get_str(ret);
- return ret;
- }
-
- private:
- void get_str( std::string &ret) const throw()
- {
- if (ei_.is_null() == false) {
- bstr_t bs;
- if (SUCCEEDED(ei_->GetDescription(bs.out())) && !bs.is_empty()) {
- ret= bs.s_str();
- return;
- }
- }
- LPVOID lpMsgBuf;
- if (FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, hr_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPSTR) &lpMsgBuf, 0, NULL))
- {
- ret = (const char*)lpMsgBuf;
- LocalFree(lpMsgBuf);
- }
- }
- void get_str( std::wstring &ret) const throw()
- {
- if (ei_.is_null() == false) {
- bstr_t bs;
- if (SUCCEEDED(ei_->GetDescription(bs.out())) && !bs.is_empty()) {
- ret = bs.w_str();
- return;
- }
- }
- LPVOID lpMsgBuf;
- if (FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, hr_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPWSTR) &lpMsgBuf, 0, NULL))
- {
- ret = (const wchar_t*)lpMsgBuf;
- LocalFree(lpMsgBuf);
- }
- }
- public:
-
- /** Return the HRESULT for the error.
- */
- HRESULT hr() const throw()
- {
- return hr_;
- }
-
- /// \name wrappers for IErrorInfo
- //@{
-
- /// Description of the error.
- bstr_t description() const
- {
- bstr_t rv;
- if (!ei_.is_null()) ei_->GetDescription( rv.out() ) | raise_exception;
- return rv;
- }
-
- /// The error source description.
- bstr_t source() const
- {
- bstr_t rv;
- if (!ei_.is_null()) ei_->GetSource( rv.out() ) | raise_exception;
- return rv;
- }
-
- /// Interface IID.
- GUID guid() const
- {
- GUID rv;
- if (!ei_.is_null()) ei_->GetGUID( &rv ) | raise_exception;
- else ZeroMemory(&rv, sizeof(rv));
- return rv;
- }
-
- /// Helpfile name.
- bstr_t help_file() const
- {
- bstr_t rv;
- if (!ei_.is_null()) ei_->GetHelpFile( rv.out() ) | raise_exception;
- return rv;
- }
-
-
- /// Help conext.
- DWORD help_context() const
- {
- DWORD rv = 0;
- if (!ei_.is_null()) ei_->GetHelpContext( &rv ) | raise_exception;
- return rv;
- }
- //@}
-
- /// Return the error-info object.
- com_ptr<IErrorInfo> get_ei() const
- {
- return ei_;
- }
-
- private:
- mutable std::string what_;
- com_ptr<IErrorInfo> ei_;
- HRESULT hr_;
- };
-
-
- namespace impl {
-
- inline HRESULT return_com_error(HRESULT hr, const bstr_t &desc, const bstr_t &src = auto_attach(BSTR(NULL)),
- const uuid_t &iid=CLSID_NULL, const bstr_t &helpFile=bstr_t(), DWORD helpContext = -1)
- {
- com_ptr<ICreateErrorInfo> cei(impl::CreateErrorInfo());
- if (cei.is_null() == false) {
- try {
- cei->SetDescription(desc.in());
- if (!src.is_null() )
- cei->SetSource( src.in() );
- if (iid != uuid_t())
- cei->SetGUID( iid );
- if (!helpFile.is_null())
- {
- cei->SetHelpFile( helpFile.in() );
- cei->SetHelpContext( helpContext );
- }
- com_ptr<IErrorInfo> ei = com_cast(cei);
- ::SetErrorInfo(0, ei.in());
- } catch (std::bad_alloc&)
- {}
- }
- return hr;
- }
- inline HRESULT return_com_error(const std::exception& err, const bstr_t &src = auto_attach(BSTR(NULL)),
- const uuid_t &iid=CLSID_NULL, const bstr_t &helpFile=bstr_t(), DWORD helpContext = -1)
- {
- return return_com_error( E_FAIL, bstr_t(err.what()),src,iid,helpFile, helpContext );
- }
- inline HRESULT return_com_error(const com_error& err, const bstr_t &src = bstr_t(), const uuid_t &iid = CLSID_NULL) throw()
- {
- const bstr_t &cursrc =err.source();
- const uuid_t &curiid =err.guid();
- // Return error info with more info.
- return return_com_error( err.hr(), err.description(), cursrc.is_null()?src:cursrc,
- curiid.is_null()?iid:curiid, err.help_file(), err.help_context());
- }
-
-
- inline void throw_com_error_(HRESULT hr, const com_ptr<IErrorInfo>& ei)
- {
- throw_error_handler<true>::throw_error(hr, ei);
- }
-
- // Raising an HRESULT with a message
- inline void raise_exception_t::operator()(const bstr_t& msg, HRESULT hr/* = E_FAIL*/) const
- {
- throw com_error(msg, hr);
- }
-
- // Raising an HRESULT
- inline void raise_exception_t::operator()(HRESULT hr) const
- {
- throw com_error(hr);
- }
-
- } // namespace impl
-
- /*! \addtogroup ErrorHandling
- */
- //@{
-
- /** Throw COM error using com_error, using HRESULT and IErrorInfo.
- */
- template<typename Itf> inline void throw_com_error(Itf* p, HRESULT hr)
- {
- if (impl::supports_ErrorInfo(p))
- {
- com_ptr<IErrorInfo> ei = impl::GetErrorInfo();
- if (ei.is_null() == false) impl::throw_com_error_(hr, ei);
- }
- throw com_error(hr);
- }
-
- template<bool OVERRIDE>
- inline void throw_error_handler<OVERRIDE>::throw_error(HRESULT hr, const com_ptr<IErrorInfo> &ei)
- {
- throw com_error(hr, ei);
- }
- //@}
- }
-
- #pragma warning(pop)
-
- #endif