Click here to Skip to main content
Click here to Skip to main content

SEH and C++ Exceptions - catch all in one

By , 16 Mar 2000
 
  • Download demo project - 15 Kb
  • Download source files - 2 Kb
  • 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.

    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

    About the Author

    Martin Ziacek
    Software Developer (Senior)
    United Kingdom United Kingdom
    Member
    No Biography provided

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    QuestionLicense?memberjcastrovinci1 Feb '10 - 8:35 
    Hello Martin,
    Could you please tell me under which license this code is covered? I'd like to use these files in a corporate application.
     
    Thank you,
    Jason
    Questionunable to catch breakpoint exceptionsmemberhans.sch23 Nov '09 - 7:35 
    Martin,
    great article. The _set_se_translator function is a very interesting thing, and I wrote some code like yours before I found your article. However I am unable to catch breakpoint exceptions (code 0x80000003; insert '__asm int 3' in your code to create). Windows keeps saying 'blah.exe has stopped to work' (or similar, I have German Vista). I don't know whether this is a peculiarity of Vista, or of VS2008, or just my failing to do it right Confused | :confused:
    Hans
    QuestionHow to do it well if _set_se_translator() is not available (WinCE)memberBostjan Erzen26 Aug '08 - 0:41 
    Hi,
     
    I develop Windows Mobile applications (Visual Studio 2008, C++, MFC). I wanted to use try-catch for C++ exceptions and C++ wrapper class for SE exceptions, but for latest is not possible since _set_se_translator() is not available on WinCE. Then I thought to also catch SE with catch(...), but then I don't have information about SE exception (code, address,...). Is there any other way how to use C++ catch(?), where '?' means some type that would catch SE only? catch(UINT n) doesn't work, regardless that SE is exactly of that type. I read some posts though, that catch (unsigned int n) should also catch SEH, but it didn't work for me.
     
    Any ideas, any workaround?
     
    Thanks in advance,
    Bostjan Erzen
    QuestionAhoj Martin, prosba o pomocmemberriavale23 Mar '06 - 6:30 
    Sorry to bother you on this forum but your e-mail address I have is not working, can you send me some where I can send you a message? Thanks a lot.
    My address is: val_gornerova@yahoo.co.uk
     
    Valca G.
    GeneralImproved Error Message for Access ViolationsmemberSteve Johnson (Sven)22 Mar '06 - 10:58 
    Replacing the CASE macro as shown will provide the offending location and access type for EXCEPTION_ACCESS_INFORMATION, which is the only exception that currently has additional information available:
     
    #define CASE(nSeCode,CsString) case EXCEPTION_##nSeCode: \
    if ( EXCEPTION_##nSeCode == EXCEPTION_ACCESS_VIOLATION ) \
    { \
    CsString.Format( _T("Exception %s (0x%.8X) at address 0x%.8X. %s 0x%.8X"), \
    _T(#nSeCode),\
    EXCEPTION_##nSeCode,\
    m_pExcPointers->ExceptionRecord->ExceptionAddress, \
    m_pExcPointers->ExceptionRecord->ExceptionInformation[0] ? _T("\r\nUnable to write location:") : _T("\r\nUnable to read location:"), \
    m_pExcPointers->ExceptionRecord->ExceptionInformation[1] ); \
    } \
    else \
    { \
    CsString.Format(_T("Exception %s (0x%.8X) at address 0x%.8X."), \
    _T(#nSeCode),\
    EXCEPTION_##nSeCode,\
    m_pExcPointers->ExceptionRecord->ExceptionAddress); \
    } \
    break;

    GeneralYou can't catch and continue on allmemberDB115 Oct '05 - 17:34 
    In your try/catch handler, you need to check for noncontinuable exceptions, and exit your application if appropriate.
     
    <code>
          try {
                   ....
          }
          catch(CSeException *e)
          {
                   _EXCEPTION_POINTERS* ExPtr = e->GetSePointers();
     
                   if( (ExPtr->ExceptionRecord->ExceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION) ||
                         (ExPtr->ExceptionRecord->ExceptionFlags == EXCEPTION_NONCONTINUABLE ) )
                   {
                         ::PostMessage(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), WM_QUIT, 0,0);
                   }
                   e->Delete();
          }    
    </code>
    GeneralCompiler switch &quot;/EHa&quot; needed with VC 6 &amp; 7memberJamireste28 Sep '05 - 5:43 
    Works fine with Visual C++ .Net 2002 as well. However the asynchronous exception handling model must be enabled through compiler switch "/EHa" (like in VC6).
     
    Why?
     
    MSDN states "Use /EHa instead of /EHsc when using _set_se_translator.".
     
    Practically, under VC7's default "Synchronous Exception Model" (compiler switch "/EHsc"), SEH exceptions are not always caught. In particular in Release mode because the compiler enables some optimizations.
     
    For instance, the INT_DIVIDE_BY_ZERO exception is not caught when the following code is compiled in Release mode under VC7's default "Synchronous Exception Model" :
     

    try {
    int z = 0;
    int n = 10 / z;
    } catch(CSeException *e) {
    TCHAR trcMsg[1024];
    e->GetErrorMessage(trcMsg,1024);
    TRACE(trcMsg);
    TRACE(_T("\n"));
    e->ReportError(MB_OK | MB_ICONSTOP);
    e->Delete();
    }

     
    A very interresting article about this technical subject can be found here :
    http://www.thunderguy.com/semicolon/2002/08/15/visual-c-exception-handling/
    Questionfloating point exceptions as well?membercptspiff28 Nov '03 - 1:00 
    Hi!
     
    How can i catch a fp-exception as well with the provided class.
     
    In principle it should be possible, or?
     
    try
    {
       float a,b,c;
       a= 1.0;
       b= 0.0;
       c = a / b;
    }
    catch(...)
    {
       // got it?
    }
     
    Bye
    CptSpiff Smile | :)
    Generalmore Exceptionsmembergertano24 Mar '03 - 7:52 
    Hi:
    that are the only exceptions? Where can I to find all windows exceptions?
    switch (m_nSeCode) {
    CASE(ACCESS_VIOLATION,CsErrDescr);
    CASE(DATATYPE_MISALIGNMENT,CsErrDescr);
    CASE(BREAKPOINT,CsErrDescr);
    CASE(SINGLE_STEP,CsErrDescr);
    CASE(ARRAY_BOUNDS_EXCEEDED,CsErrDescr);
    CASE(FLT_DENORMAL_OPERAND,CsErrDescr);
    CASE(FLT_DIVIDE_BY_ZERO,CsErrDescr);
    CASE(FLT_INEXACT_RESULT,CsErrDescr);
    CASE(FLT_INVALID_OPERATION,CsErrDescr);
    CASE(FLT_OVERFLOW,CsErrDescr);
    CASE(FLT_STACK_CHECK,CsErrDescr);
    CASE(FLT_UNDERFLOW,CsErrDescr);
    CASE(INT_DIVIDE_BY_ZERO,CsErrDescr);
    CASE(INT_OVERFLOW,CsErrDescr);
    CASE(PRIV_INSTRUCTION,CsErrDescr);
    CASE(IN_PAGE_ERROR,CsErrDescr);
    CASE(ILLEGAL_INSTRUCTION,CsErrDescr);
    CASE(NONCONTINUABLE_EXCEPTION,CsErrDescr);
    CASE(STACK_OVERFLOW,CsErrDescr);
    CASE(INVALID_DISPOSITION,CsErrDescr);
    CASE(GUARD_PAGE,CsErrDescr);
    CASE(INVALID_HANDLE,CsErrDescr);
    default: CsErrDescr = _T("Unknown exception.");
     
    thanks
    GeneralRe: more ExceptionsmemberMartyn Pearson18 Jun '03 - 0:19 
    They are listed in WinBase.h - I could be wrong, but that looks like it covers all of them!
    GeneralRe: more ExceptionssussAnonymous1 Sep '04 - 23:10 
    I am sure that these are complete. Note that SEH exceptions are only CPU exceptions and don't refer to anything of the Windows stuff.

    GeneralQuestion about design.sussHoly Punk6 Feb '03 - 15:36 
    Hi Martin,
     
    I was looking for something like this for a quite some time and somehow couldn't get original MSDN page. Well, that's even better I found your article! Wink | ;) Looks like very neat thing to me.
     
    I'm going to implement your idea with few variations to suit my code better. I was just wondering if there is any specific reason for creating new object in
    void SeTranslator(UINT, _EXCEPTION_POINTERS*) ?
     
    I didn't try anything yet, but I cannot see why cannot one just throw an object? Could you please share your point of view/reasons?
     
    Thank you and best regards,
    Holy Punk.
    GeneralRe: Question about design.sussMike U.28 Apr '03 - 23:32 
    Hi,
    if you want to use it with MFC, be aware that it catches exceptions by pointer, not by reference. If you throw an exception object instead of a pointer, it will not be caught in AfxCallWndProc() (in wincore.cpp).
    If you install an exception handler try/catch, you are able to catch an exception by reference, but let's say you have this call stack:
     
    MyFunc try/catch
    SendMessage
    AfxCallWndProc try/catch
    int x = 5/0;
     
    It is better not to let your C++ exception travel the call stack across Windows internal code and be caught in MyFunc, because of side effects of stack unwinding. AfxCallWndProc will catch exceptions derived from CException and pass them to the application/thread for processing. There you can display an error message. Yes, I don't like it either that they do it by pointer.
    And also I don't like it that you cannot catch std::exception in AfxCallWndProc().
    Mike
     

    GeneralRelease mode weirdnessmemberbooster16 Nov '01 - 4:44 
    It works great in debug mode. I liked it so much I changed my 80k+ lines project to use it. But i'm getting weird results and strange bugs in release mode compiles. Yes I have the /EHa (asynchronous exception handlers) on in the options. The funny thing is when I turn off optimizations it works just great. Any reason for the strange bugs with optimizations on in release mode?
     
    vc++ 6.0 sp5
    The bug I found was that after calling bind() with port 0, getsockname didn't return the port that bind assigned my socket to listen on. works correctly in debug and release without optimizations. I also noticed that with debug info on in release mode, the variables had incorrect pointer address and values. eg a pointer would be 0x00 but I could step through just fine
    GeneralRe: Release mode weirdnessmemberMartin Ziacek16 Nov '01 - 9:19 
    I am happy you like my exception class and I would like to help you with solving troubles, however I cannot reproduce any strange behavioural. Can you please send me a sample code with described problems?
     
    Kind regards,
     
    Martin

    GeneralMFC IndependentmemberAnonymous5 Nov '01 - 18:26 
    Can we make CSeException class , MFC independent. Because we are deriving it from CException.
    I think if we did it , then we can use this class in Win32-SDK also.

    GeneralRe: MFC IndependentmemberMartin Ziacek5 Nov '01 - 19:35 
    CSeException is extension to existing CException from MFC, however, when you will remove all the referencies to MFC from CSeException sources, then you will get CSeException class 'MFC independent' and you can use it in the 'SDK only' projects. Simply remove any reference to CException and delete method BOOL GetErrorMessage(CString & CsErrDescr, PUINT pnHelpContext = NULL);
    Questionmultiple calls i n a thread?memberAnonymous22 Oct '01 - 8:12 
    I'm using win2k and xp thread pooling functions, is it ok to call _set_se_translator multiple times.. eg in the class constructor rather than at the start of the thread?
    AnswerRe: multiple calls i n a thread?memberMartin Ziacek31 Oct '01 - 4:36 
    I see no problem to call this function multiple times, have a look in the MSDN for description:
     
    _set_se_translator returns a pointer to the previous translator function registered by _set_se_translator, so that the previous function can be restored later. If no previous function has been set, the return value may be used to restore the default behaviour; this value may be NULL.
     
    So, answer depends on your scenario, probably good idea would be to restore previous handle in your destructor.

    Questionwhat about exception type?memberAnonymous22 Oct '01 - 7:47 
    can this class tell the exception type? if it can't how is it better than catch(...)?
    AnswerRe: what about exception type?memberMartin Ziacek31 Oct '01 - 4:30 
    Type of the SE exception is always int. You can catch it as int type, but then you have to decide on the value, which exception has occurred. My class does this for you - it can format a message with proper description of exception. And off course, you can catch C++ exception and SE exception with the same code. When you will use only catch(...) then you have no idea of what exception has been thrown.
    GeneralThread ProblemmemberThomas George10 Sep '01 - 10:37 
    When I do this in threads created using CreateThread, it does not come into the exception function. Is there something that I have to do extra? MSDN says that each thread has to register its own function. So I did it at the start of the thread procedure passed to the CreateThread.
     
    Thanks in advance
     
    Thomas
    GeneralRe: Thread ProblemmemberMartin Ziacek10 Sep '01 - 11:01 
    Specify please /EHa option for compiler (asynchronous exception handling model) and your exception has to be caught.

    GeneralRe: Thread ProblemmemberThomas George10 Sep '01 - 12:49 
    Thanks for the reply ...
    but it still does not work.
     
    What I am doing is:
     
    _beginthreadex(NULL, 0, ThreadProc, this, 0, &nThreadId);
     
    In ThreadProc
     
    _set_se_translator(trans_func);
    // code to create exception
     
    When run, this never reaches the trans_func. Instead the access violation error comes up in the standard dialog box.
     
    But the same thing works fine from the primary thread of the application.
     
    Thank you
     
    Thomas
    GeneralRe: Thread ProblemmemberMartin Ziacek10 Sep '01 - 19:01 
    I did something like this:
     
    UINT WINAPI TestThread(LPVOID)
    {
    _set_se_translator(SeTranslator);
     
    char *p = NULL;
     
    try {
    p[0] = 0;
    } catch(CSeException *e) {
    TCHAR trcMsg[1024];
    e->GetErrorMessage(trcMsg,1024);
    TRACE(trcMsg);
    TRACE(_T("\n"));
    e->ReportError(MB_OK | MB_ICONSTOP);
    e->Delete();
    }
     
    return 0;
    }
     
    void CSehDemoDlg::OnThreadex()
    {
    UINT Id = 0;
     
    _beginthreadex(NULL, 0, TestThread, this, 0, &Id);
    }
     
    and it is working fine. I sent you modified demo program (with changes above) by e-mail, please, have a look and compare it with your code. And let me know, what was different, please. Thanks.
    GeneralRe: Thread ProblemmemberThomas George11 Sep '01 - 12:04 
    Hi Martin,
     
    I am in NY (not in Manhattan though) and got caught up watching the action today. It was pretty bad. One of my collegues have his son in the 8th grade. In his class alone, 5 of the kids had one of their parents killed in this tragedy.
     
    Coming back, the problem was that the exception was occurring outside the try catch handler and so the translator was not catching that.
     
    Thank you very much for taking the time to make a demo application and send it to me. I really appreciate that.
     
    Regards
     
    Thomas
    GeneralRe: Thread ProblemmemberMartin Ziacek12 Sep '01 - 10:01 
    Hi Tom,
     
    it was really very bad, what's happened. When I saw it the first time I thought it is some movie, I could not believe it is real.
     
    Thanks for your suggestion. You pointed me to review my code and I found out that compiler switch /EHa is required for VC++ 6, because of changed exception handling.
     
    Kind regards,
     
    Martin
     

    GeneralSame Thread Problemmemberkcselvaraj28 May '06 - 20:28 
    hi ,
    i too facing thread problem .iam downloading xml file from the server
    i used CreateThread() to download each file.After downloading that file an error "application error" the instruction at 0x0000000 referenced memory at 0x00000000 is comming .i tried to catch but can't....
     
    i donot know why such error is comming and where, but when i download without using thread it is working fine ...
     
    can any one guess and help me solve this problem
     
    thanks in advance
    K.C.S
    GeneralUnable use the exception classmemberRameshKumar23 Jul '01 - 4:01 
    I am not able to use the SeException class b'cos in Main() program i am getting error in the line 'p[0] = 0;'
    VC++ throws the Access violation error, b'cos of this error i am not able to test the SeException class. But however when i executed u r demo files it worked fine. what is the reason. I too created same Dialog based project.

    GeneralRe: Unable use the exception classmemberMartin Ziacek24 Jul '01 - 5:48 
    I would say you have not set SeTranslator as structured exception translator function with call _set_se_translator(SeTranslator), as it is done in my demo program:
     
    /////////////////////////////////////////////////////////////////////////////
    // CSehDemoApp construction
     
    CSehDemoApp::CSehDemoApp()
    {
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
    _set_se_translator(SeTranslator);
    }
     
    However, if it will not help, send me your demo program.

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

    Permalink | Advertise | Privacy | Mobile
    Web02 | 2.6.130523.1 | Last Updated 17 Mar 2000
    Article Copyright 2000 by Martin Ziacek
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid