SEH and C++ Exceptions - catch all in one

.

Environment:  Visual C++ 5.0 & SP3, Windows NT 4.0 & SP5, Unicode, MBCS

This article describes how to handle SE and C++ exception together.

Motivation

Everybody sometimes need to write as robust code as possible. The simplest way, in these cases, is to use exception handling. But most code is wrote in C++/MFC, with C++ exception handling (e.g. CdbException). With SEH, it is not possible to catch C++ exception, and C++ typed exception can not catch SE selectively, because it is not typed in a way of C++. Solution with catch(...) is not useful, because you will not know 'type' of exception. SE is possible to catch like unsigned int typed C++ exception, but this solution is not very nice.  

Description of solution

I was looking for a method to handle SE and C++ exception together. I found function

  typedef void (*_se_translator_function)( unsigned int, struct _EXCEPTION_POINTERS* );

In MSDN you can find following description:

The _set_se_translator function provides a way to handle Win32 exceptions (C structured exceptions) as C++ typed exceptions. To allow each C exception to be handled by a C++ catch handler, first define a C exception "wrapper" class that can be used, or derived from, in order to attribute a specific class type to a C exception. To use this class, install a custom C exception translator function that is called by the internal exception-handling mechanism each time a C exception is raised. Within your translator function, you can throw any typed exception that can be caught by a matching C++ catch handler.

And now, it is enough to write wrapper class (I think, my class is quite better than class provided by documentation for _set_se_translator):

  class CSeException : public CException
  {
      DECLARE_DYNAMIC(CSeException)
  public: 
      CSeException(UINT nSeCode, _EXCEPTION_POINTERS* pExcPointers);
      CSeException(CSeException & CseExc);

      UINT GetSeCode(void);
      _EXCEPTION_POINTERS* GetSePointers(void);
      PVOID GetExceptionAddress(void);

      void Delete(void);
      int ReportError(UINT nType = MB_OK, UINT nIDHelp = 0);
      BOOL GetErrorMessage(CString & CsErrDescr, PUINT pnHelpContext = NULL);
      BOOL GetErrorMessage(LPTSTR lpszError, UINT nMaxError, PUINT pnHelpContext = NULL);
  private:
      UINT m_nSeCode;
      _EXCEPTION_POINTERS* m_pExcPointers;
  };

And my own translator function:

  void SeTranslator(UINT nSeCode, _EXCEPTION_POINTERS* pExcPointers)
  {
      throw new CSeException(nSeCode,pExcPointers);
  }

How does it work?

When SE is raised, then it is called our own translator function - if it was installed through _se_translator_function. This translator function simply throw exception again, but now it is our wrapper class exception filled with useful information.

Description of CSeException

CSeException class is based on CException class provided by MFC. I overwrite some of useful methods, but it is working same way like any other exception class based on CException class - you can find description in documentation provided by Visual C++.

Usage

At first of all you need to install SeTranslator function, in every thread of your application. Translator function is  thread specific, it means it is not globally set in application. In single thread application it is possible to install it in constructor of application class (as I do in demo program), however in multithreading application it is best place to install translator function at the beginnings of every thread. When translator function is installed, then it is possible to write code like this:


  char *p = NULL;

  try {

  // do something ...

  p[0] = 0; 

  // do something ...

  } catch (CdbException dbError) {

  //handle it

  } catch(CSeException *e) {
  e->ReportError(MB_OK | MB_ICONSTOP);
  e->Delete();
  }

CSeException class is Unicode and MBCS strings compliant. Please note, delete CSeException in catch() block, because it is dynamically allocated by translator function.

Download

Download demo project - 16 KB

Download source - 2 KB



Comments

  • RE:SEH and C++ Exceptions - catch all in one

    Posted by Legacy on 07/18/2002 12:00am

    Originally posted by: Daniel Slater

    I have to say that I really despise the MFC way of handling exceptions:
    
    

    void someFunc()
    {
    throw new Exception(blah); // ARGH -- ugly and dangerous
    }


    void myfunc()
    {
    try
    {
    }
    catch(CException *e)
    {
    // do something
    e->Delete(); // ARGH!!!! - ugly and dangerous
    // could get a memory exception here
    }
    }

    That's why when I created my own SEH exceptions, I didn't derive from CException. Instead I had my own base clase:

    class SEHException
    {
    };

    and a derived class for each kind:

    class SEHAccessViolation : public SEHException
    {
    };

    class SEHFloatingPointException : public SEHException
    {
    };

    class SEHOverflowException : public SEHFloatingPointException
    {
    };

    etc. - you get the idea.

    my se_translate_function() then looked like this:

    void seh_translate(unsigned int code, struct _EXCEPTION_POINTERS*)
    {
    switch(code)
    {
    case EXCEPTION_ACCESS_VIOLATION:
    throw SEHAccessViolation();
    break;
    etc.
    }
    }

    then in my functions that I wanted to protect:

    void someFunc()
    {

    try
    {
    // do something that may throw an exception
    }
    catch(CException *e)
    {
    // if you're using MFC - still need this
    // handle mfc exception
    e->Delete();
    }
    catch(const SEHException &seh)
    {
    // handle SEH exception
    // no need to delete
    // can have a whole list of SEHException derived
    // catches here - just make sure derived classes
    // come before base classes. - also very import
    // to catch by reference to avoid slicing of the
    // class
    }


    }


    // IF anyone is interested, e-mail me and I'll send you my actual source code. (remove the nospam from my e-mail address to e-mail me.)

    // NEW: I've uploaded the sources to: http://www.geocities.com/dan_slater/src/exceptions/

    Reply
  • SEH and C++ exceptions do not necessarily work and play well together

    Posted by Legacy on 02/20/2001 12:00am

    Originally posted by: Eric Smith

    while checking out the SEH as used in the context of C++ exceptions, I discovered an apparent aberration in the way that the C++ exception handler handles exception.
    
    The only thing I can figure is that perhaps it is a compiler problem as it only occurs in release.

    For example:

    this works in a debug compilation:

    int x = 0,y = 0;

    try
    {
    x = 5/y;
    }
    catch(CSeException *e)
    {
    e->Delete();
    }

    In the above example the catch handler is never called in release. However, the following code does work in release mode.

    int x = 0,y = 0;

    try
    {
    x = 5/y;
    if(x == 0)
    {
    // do something
    Sleep(0);
    }
    }
    catch(CSeException *e)
    {
    e->Delete();
    }

    The exception is now handled.

    The only way around this that I have found is to specify the /EHa compiler option or in the header file of CSeException specify #pragma optimize("g",off). It appears that using these options will allow you use the CSeException reliably even in release mode. Apparently, VC6 now uses synchronous exception handling by default. At this momemt, I am still researching the possible effects of using the asychronous exception in place of the synchonous.
    John Robbins addresses this issue in an articly available on MSDN from Oct. 99.

    Reply
  • Re: C++ Exceptions not Caught!!!

    Posted by Legacy on 02/15/2000 12:00am

    Originally posted by: Martin Ziacek

    Hi Mark,

    You can not catch exception from CFile::Remove(),
    because it throws CFileException and not CFileException *.

    Martin

    Reply
  • C++ Exceptions not Caught!!!

    Posted by Legacy on 01/24/2000 12:00am

    Originally posted by: Mark

     With you demo project, i tried creating a CException , but the exception was never caught by your class....
    

    this should catch C++ Errors As well....

    how do i catch c++ errors with that same class,,


    for example:


    try
    {
    CFile::Remove("Doesnotexistfile") // error hapens here of CFileException
    }
    catch(CSeException *e)
    {
    e->ReportError();
    e->delete();
    }


    this code will never run into the catch even though your class is derived from CException....

    Reply
  • Another form of Unhandled Exeption Trapping

    Posted by Legacy on 06/01/1999 12:00am

    Originally posted by: Jeff Boyle

    While this is nice, I think you should also check out John Robbins web site....he is an author for MSJ (he writes the BugSlayer column) and works for NuMega....he has a wonderful DLL which does all this and much much more, and he also provides source. I think you can get his articles from the magazine on the web also.

    The site is: www.jprobbins.com

    Look for the BugSLayerUtil.DLL

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • This paper introduces IBM Java on the IBM PowerLinux 7R2 server and describes IBM's implementation of the Java platform, which includes IBM's Java Virtual Machine and development toolkit.

  • Not all enterprise applications are created equal. Sophisticated applications need developer support but other more basic apps do not. With the right tools, everyone is a potential app developer with ideas and a perspective to share. Trends such as low-code development and model driven development are fundamentally changing how and who creates applications. Is your organization ready? Read this report and learn: The seven personas of enterprise app delivery How application ownership is spreading to the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds