Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

HRESULT Error Check Simplifier

0.00/5 (No votes)
12 Jun 2011 5  
Exception based error check that automates the FAILED() comparison.

Introduction

It is boring to have to write a lot of ifs only to check for failures. At the same time, it is important to take care of every error that can happen in the code. The class described in this article just makes it easy to throw an exception every time a failure is returned from another function. This way you can do only what you have to do in the code and unify error handling.

With a little help from my colleagues from CP, here is an updated version with some traits for a no-throw version, and a new method to show a textual version for the HRESULT error:

template<bool ThrowException>
struct HResultChecker
{
    static void Check(HRESULT hr);
};

template<> struct HResultChecker<false>
{
    static void Check(HRESULT hr) 
    {
        hr;
    }
};

template<> struct HResultChecker<true>
{
    static void Check(HRESULT hr)
    { 
        if( FAILED(hr) ) 
            AtlThrow(hr);
    }
};


/**
* Use this class instead HRESULT in order to the assignement operator be 
* tested. In case of failure, the funcion AtlThrow() will be called.
*
* @sa AtlThrow(), CAtlException.
*/
template<bool ThrowException>
class HResultT
{
public:
    /// Test the HRESULT in the constructor.
    HResultT(HRESULT hr = S_OK)    { Assign(hr); }

    /// Test failure of the received hr. If FAILED(hr), the function 
    /// AtlThrow() will be called.
    HResultT &operator = (HRESULT hr)
    {
        Assign(hr);
        return *this;
    }

    /** 
    * Retrieves the error desription of the HRESULT member.
    * @return string message for the HRESULT.
    *
    * @author ddarko (comment from CodeProject)
    * @date 2005-09
    */
    LPCTSTR ErrorMessage()
    {
        // a lot of code
    }

    /// Extractor of the stored HRESULT.
    operator HRESULT () { return m_hr; }

private:
    void Assign(HRESULT hr) // throw( CAtlException )
    {
        HResultChecker<ThrowException>::Check(m_hr = hr);
    }

    HRESULT m_hr; // the stored HRESULT
    std::basic_string<TCHAR> m_desc; // error description
};

/// Throw exception version.
typedef HResultT<true> HResult;

// No-Throw exception version.
typedef HResultT<false> HResultSafe;

Using the code

The use is very straightforward. You can catch the exceptions inside the function or pass it to the callee:

/**
Using HResult inside the funcion
*/
void function()
{
   HResult hr;

   try
   {
      hr = MakeSomething();
      hr = MakeSomethingElse();
      hr = MakeTheFinalSomething();
   }
   catch(CAtlException& e)
   {
      cout << "wow! Error " << e.m_hr << ": " << e.ErrorMessage() << "\n";
   }
}

/**
Using HResult bypassing the exception
*/
void Class::Method() throw ( CAtlException )
{
   HResult hr = MakeSomething();
   hr = MakeSomethingElse();
   hr = MakeTheFinalSomething();
}

Points of interest

Maybe before using the class above, you would to like to learn about CAtlException, AtlThrow(), and FormatMessage(). Very interesting stuff for exception based error handling.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here