Click here to Skip to main content
15,896,063 members
Articles / Programming Languages / C++
Article

Neat HRESULT to exception converter

Rate me:
Please Sign up or sign in to vote.
3.63/5 (6 votes)
21 Oct 20052 min read 47.4K   244   14   3
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


Written By
Egypt Egypt
I started computing at the age of 11, but first programming experience at age of 15. now i have been programming for 4 years.

I have expericenced C/C++, java, pascal, SQL, assembly(8086,386), C#, DirectX, jsp, asp.net, 3dsMax, Maya, Paintshop, Photoshop, javaScript, HTML. Some of the programs i did was Chess( AI ), Tic-tac-toe ( AI ), Minesweeper. I am interested in the field of Mathematics, and AI so much. If i wasn't a programmer i would like to be a mathematician !

My dream is to live in a lab, in which i can do whatever research i want. My best hobby is to gain knowledge, and of course trying to produce it Smile | :) .

Comments and Discussions

 
JokeUnderscore macros Pin
Kirit Sælensminde6-Jun-06 18:06
Kirit Sælensminde6-Jun-06 18:06 
The underscore is a reserved character for use by the compiler vendor when at the beginning of an identifier. You shouldn't really be using it in your own code. It'll probably be OK, but even so.

Much more serious is the fixed buffer. If you're going to use one (and there's absolutely no reason why you should) then you need to check that it won't overrun.
GeneralA Slightly More Readable Method Pin
Zac Howland25-Oct-05 5:55
Zac Howland25-Oct-05 5:55 
GeneralThe macro _E() Pin
Wanderley Caloni25-Oct-05 2:28
professionalWanderley Caloni25-Oct-05 2:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.