Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Neat HRESULT to exception converter

3.63/5 (6 votes)
21 Oct 20052 min read 1   244  
A clean and easy way to convert an HRESULT error to an exception including file name and line number.

Introduction

I've got this idea as an expansion to HRESULT Error Check Simplifier By Wanderley Caloni, so I guess his introduction would be better than if I wrote one. Many thanks to Wanderley Caloni for writing the article.

I'll just introduce here what I have added. The article mentioned above, has a class that checks if an HRESULT value is SUCCEEDED or not. If not, it throws an exception. What is added is some extra functionality, to be able to show a message box, with the line number and file name and a custom error message.

Using the code

Take a look at this usage example:

if( NULL == ( direct3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
    throw MyException(_E("Can't create Direct3D object"));
        
hrToException(_E("Can't get adapter display mode")) = 
  direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&Mode);

The throw MyException(_E("Can't create Direct3D object")); is normal and is known to any C++ developer, it only throws an exception.

But the idea is in the next example hrToException(_E("Can't get adapter display mode")) = direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&Mode);: it simply means that if the return HRESULT value from the function call direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&Mode) is FAILED, then throw an exception with the current line number and the current file name and containing the error string "Can't get adapter display mode".

The old way to do this was:

if(FAILED(direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&Mode))
    throw MyException("Can't get adapter display mode",__FILE__,__LINE__);

Imagine your code with this kind of ifs all over the file :-). At least the new class removes the branching logic off your shoulder.

Here's the _E() macro. It just adds the line number and the file name to the parameter of the exception constructor, to save some typing.

#define _E(str) str##,##__FILE__##,##__LINE__

Your code should be in a try-catch block.

#define _MYTRY        try {

There is a pre-defined catch block, to produce the message box, and also to save some typing. You might change the error[] length if you plan to use longer error strings.

// the catch statement that shows the message box
#define _MYCATCH        \
}                        \
catch(MyException ex)    \
{                        \
    char error[255];    \
    sprintf(error,"%s ( HRESULT = %i ), file: %s, line: %i"  , 
            ex.error_str , ex.hr , ex.file , ex.lineNumber);\
    ::MessageBox(hWnd,error , "MyException Caught" , MB_OK);    \
    exit(E_FAIL);    \
}

The exception class holds only these four pieces of information.

// the exception class
struct MyException
{
    ...

    char* error_str;
    char* file;
    int lineNumber;
    HRESULT hr;
};

Check the line:

hrToException(_E("Can't get adapter display mode")) = 
   direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&Mode);

It is done like this:

// the class that throws, if an HRESULT failed
class HResultToException 
{
public:
    HResultToException& operator()(char* error, 
               char* file_name,int line_number)
    {
        error_str = error;
        this->file_name    = file_name;
        this->line_number = line_number;
        return *this; 
    }

    void operator=(HRESULT hr)
    {
        if(FAILED(hr))
            throw MyException(error_str,hr,file_name,line_number);
    }
};

Conclusion

This article is only to show some ideas to enhance readability, but it lacks reusability. I would appreciate if someone can make it more reusable. Anyway, the article is meant to show an example, that the reader is not supposed to use directly. The reader is supposed to catch the idea and re-implement it as it fits him/her the best.

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