Exception classThe BaseUp to now, I have been throwing an int exception. As I said before, you can use throw any type of exception. So let’s define a more useful error reporting class. Example class BaseException { public: BaseException( const char * const err ) { strncpy( buf, err, 128 ); } virtual const char * what() // get the error string { return buf; } protected: char buf[128]; // store the error string }; I use a char buffer for simplicity, but I recommend using the STL string class to replace all the strings in your programs. So now instead of throwing an int, we throw a BaseException object and pass a meaningful error string to the constructor. Later in the catch handler, we can retrieve the error string using the what() function. Example try { } catch( BaseException &e ) // note we catch by reference { cout << e.what() << endl; } Getting exceptions to work in Windows is the same as in a console program. Just wrap the main message pump function with a try/catch block. What can we do with it?Now we have a base exception class, we can use inheritance to create specific types of exceptions. Each derived class can correspond to a different type of error - File not found, Not enough memory, etc. I will give two examples here - one for dealing with Windows errors and the other for handling SEH exceptions. Windows exception classI bet you have noticed Window functions use return codes to signal errors and GetLastError() to find out what the error was. Since we are coding in Windows, we have to adapt to their weak error handling implementation. You can see the WindowsException class in the sample later on. It just translates the GetLastError code to a system message. It’s pretty simple to understand so you can just look at the source. SEH Exception classSEH in VC++ encompasses hardware exceptions too, but I bet you figured that out already. In any case, Microsoft 'suggests’ C++ exception handling to be used over SEH, and has kindly provided us with a means to translate SEH exceptions to C++ exceptions. The function we are interested in is _set_se_translator. Whenever a hardware exception occurs, the registered translator function will be called. So what we do is throw a C++ exception within the translator function, like so Example // the translator function void SEH_To_C++( unsigned int u, EXCEPTION_POINTERS *exp ) { throw int; // throw an exception of type int } void main() { try { _set_se_translator( SEH_To_C++ ); // register the translator // now all hardware exceptions will generate an C++ int // exception } catch(...) {} } Note: _set_se_translator must be called for each separate thread. SampleCombining all your newfound knowledge, I present a simple sample with the exception class in action. You will see how we can incorporate and extend the base exception in the Windows environment. I don’t normally use MFC, but since I’m not getting paid for this, oh well, too bad for the code bloat. Don’t blame me; I’m not the one who wrote the wizard. The main points to note are
More! I want more!I know you want more, so here it is More informationYou can store the line and source file where the exception occurred by passing in two additional parameters. Use the __FILE__, __LINE__ macros. You can also do a stackwalk inside the exception class too. Take a look at the BugSlayer column by John Robbins at MSDN on how to do this. Inherit from STL exception classInstead of defining a new class by itself, your base exception class can be inherited from the STL exception class. This would allow you to catch exceptions from the standard library as well as your exceptions using one catch handler. Evil AssertAssertions are evil. No wait, I don’t mean there are not useful, I meant the default assert implementation just calls abort, and that may not be exception safe. I recommend throwing an exception instead when an assertion failure occurs. You can do this easily by extending the base exception class. Extending it for DirectXMany times, I see ingenious hacks being invented for error handling in DirectX. Personally, I’m guilty of those hacks too. So, this is the latest hack using exceptions for a full screen DirectX application.
If you have worked in full screen DirectX applications before, you will probably realize a MessageBox does not always show up. This is precisely the reason why I throw an exception for all the errors, even for assertion failures. When the exception reaches up to the main function, I restore the display mode and then I display the MessageBox describing the error. Anyway, the above 'hack’ is for DirectX 7.0. I haven’t worked with DirectX 8 yet so I cannot guarantee if there are more 'hacks’ needed. |