/include/comet/error.h
C Header | 429 lines | 286 code | 52 blank | 91 comment | 50 complexity | d5db7c29eb0ae9478b9da4af7bca1bb3 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
- {
- if (ei_.is_null() == false)
- {
- bstr_t bs;
- if (SUCCEEDED(ei_->GetDescription(bs.out())) && !bs.is_empty())
- {
- ret= bs.s_str();
- return;
- }
- }
-
- char* lpMsgBuf;
- if (FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr_,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- reinterpret_cast<char*>(&lpMsgBuf), 0, NULL))
- {
- char* lpEnd = lpMsgBuf;
- while (*lpEnd != '\0')
- lpEnd++;
-
- while (lpEnd > lpMsgBuf && // Trim trailing newlines
- (*(lpEnd - 1) == '\n' || *(lpEnd - 1) == '\r'))
- lpEnd--;
-
- ret.assign(lpMsgBuf, lpEnd - lpMsgBuf);
- LocalFree(lpMsgBuf);
- }
- }
-
- void get_str(std::wstring& ret) const
- {
- if (ei_.is_null() == false)
- {
- bstr_t bs;
- if (SUCCEEDED(ei_->GetDescription(bs.out())) && !bs.is_empty())
- {
- ret = bs.w_str();
- return;
- }
- }
-
- wchar_t* lpMsgBuf;
- if (FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr_,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- reinterpret_cast<wchar_t*>(&lpMsgBuf), 0, NULL))
- {
- wchar_t* lpEnd = lpMsgBuf;
- while (*lpEnd != L'\0')
- lpEnd++;
-
- while (lpEnd > lpMsgBuf && // Trim trailing newlines
- (*(lpEnd - 1) == L'\n' || *(lpEnd - 1) == L'\r'))
- lpEnd--;
-
- ret.assign(lpMsgBuf, lpEnd - 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);
- }
-
- /**
- * Construct exception for a method called on a raw COM interface.
- *
- * This method aims to imbue the com_error with as much information about
- * the failure as possible:
- * - If the interface supports IErrorInfo, the information is taken from
- * the last ErrorInfo set on the current thread.
- * - If not, the HRESULT alone determines the message.
- *
- * Use this constructor immediately after an interface returns a
- * failure code before any other code can call SetErrorInfo and
- * overwrite the error.
- *
- * \param failure_source Interface whose method returned a failure code.
- * \param hr HRESULT value of error.
- *
- * \todo Can we add an optional user-defined message to this?
- */
- template<typename Itf>
- com_error com_error_from_interface(Itf* failure_source, HRESULT hr)
- {
- if (impl::supports_ErrorInfo(failure_source))
- return com_error(hr, impl::GetErrorInfo());
- else
- return com_error(hr);
- }
-
- template<typename Itf>
- com_error com_error_from_interface(
- com_ptr<Itf> failure_source, HRESULT hr)
- {
- return com_error_from_interface(failure_source.get(), hr);
- }
-
- //@}
- }
-
- #pragma warning(pop)
-
- #endif