Link to home
Start Free TrialLog in
Avatar of ROWANBRIGHTON
ROWANBRIGHTON

asked on

Getting specific error message from C++ catch()

I'm trying to catch a meaningful error message when an exception is thrown.
When the exception is caught by MFC TRY-CATCH statement, I can retrieve an error message with not problem.
But when it's thrown by non-MFC code, that's when I have the problem.

The reason I'm trying to get a specific error message is because when my code interfaces with a third party DLL, it throws an exception.
Since I have no documents for the DLL, I'm not sure what it's throwing, and it's not being caught by the MFC CATCH_ALL block.

How can I get details of the object being thrown on a C++ catch() statement?

This code is an example of an exception that is not caught by MFC CATCH_ALL.

void main()
{
      char* s = NULL;
      int* p = NULL;
      TRY
      {
            try
            {
                  s = new char[10];
                  *p = 5;
            }
            catch(...)
            {
                  printf("Got Unknown error\n");
            }
      }
      CATCH_ALL(Ex)
      {
            Ex->ReportError();
      }
      END_CATCH_ALL
      delete[] s;
}
Avatar of mrwad99
mrwad99
Flag of United Kingdom of Great Britain and Northern Ireland image

Hmm, first thing is why are you using the expired TRY CATCH macros of MFC ?  You should be using the classic C++ try / catch mechanism...
Ignore comment above; sorry :)
On second thought, you could always get error information from GetLastError() - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/retrieving_the_last_error_code.asp - that brings up what caused the problem regardless of MFC or not...
Avatar of ROWANBRIGHTON
ROWANBRIGHTON

ASKER

>>could always get error information from GetLastError()

That's the first thing I tried, and it bring back zero, as if no errors.

{
      char* s = NULL;
      int* p = NULL;
      TRY
      {
            try
            {
                  s = new char[10];
                  *p = 5;
            }
            catch(...)
            {
                  printf("Last Error = %i\n", GetLastError());
            }
      }
      CATCH_ALL(Ex)
      {
            Ex->ReportError();
      }
      END_CATCH_ALL
      delete[] s;
>>that brings up what caused the problem regardless of MFC or not...

If you run the above code, you'll see that it doesn't bring back the last error.

I believe GetLastError only works with other WINDOWS API functions.
     char* s = NULL;
      int* p = NULL;
      TRY
      {
            try
            {
                  s = new char[10];
                  *p = 5;
            }
            catch(...)
            {
                  int e1 = errno;
                  int e2 = _doserrno;
                  int e3 = GetLastError();
                  printf("Last errno = %i\n", e1);
                  printf("Last _doserrno = %i\n", e2);
                  printf("Last GetLastError = %i\n", e3);
            }
      }
      CATCH_ALL(Ex)
      {
            Ex->ReportError();
      }
      END_CATCH_ALL
      delete[] s;
>> *p = 5;

I think that that is a bad example of getting an exception to be thrown anyway.  Have you tried with a simple C++ class that throws an exception per-se ?
>>I think that that is a bad example of getting an exception to be thrown anyway.  Have you tried with a simple C++ class that throws an exception per-se ?

On my project the exception is being thrown from a DLL.
I don't have controle of the DLL or it's code.

I posted the above code as an example because I get the same exact results when I try to catch the exception from the DLL as I do with the code I posted.

So modifying the example is not going to help me solve my problem.

I need a method that can determine what is being thrown or some type of error message that has any details of the exception.

Unless I'm mistaken and CATCH_ALL catches this, I think that interrupts (such as division by zero, for example) are thrown as ints. So maybe you can try to  try .. catch (int n)  and see what happens.

>>Unless I'm mistaken and CATCH_ALL catches this, I think that interrupts (such as division by zero, for example) are thrown as ints. So maybe you can try to  try ..
>>catch (int n)  and see what happens.


It doesn't.  If it could catch it, then it would enter into the CATCH_ALL block, which it is not.  
Run above code for test, and you'll see.

I also tried catching with int, char, char*, and a few other types.
None of them cought the exception.
Might be a long shot, but you could try using Managed C++ for handling the exception - http://www.codeproject.com/managedcpp/ExceManagedcpp.asp

That has built in methods for displaying info,
Have you set the /EHa compiler option?
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
BTW, see also the VC++ docs about '_set_se_translator()' on how to turn these SEX exceptions into C++ excptions: http://msdn.microsoft.com/library/en-us/vclib/html/_crt__set_se_translator.asp
>>Are you sure it is not a SEH exception?

If it is a SEH exception, how can I used this in conjunction with MFC TRY-CATCH?

I have my project setup so it first tries to capture the exception using MFC TRY-CATCH, because the MFC exception gives me the most information for cause of error.

I need a method that can capture any exceptions not caught by CATCH_ALL(e)

If you look at test1b function, you'll see that the C++ catch(...) is able to capture anything that CATCH_ALL can not.
The problem  is I get no meaningfull information about the exception.

void test1b()
{
      char* s = NULL;
      int* p = NULL;
      try
      {
            TRY
            {
                  s = new char[10];
                  *p = 5;
            }
            CATCH_ALL(Ex)
            {
                  Ex->ReportError();
            }
            END_CATCH_ALL
      }
      catch(...)
      {
            int e1 = errno;
            int e2 = _doserrno;
            int e3 = GetLastError();
            int e4 = _sys_nerr;
            printf("Last errno = %i\n", e1);
            printf("Last _doserrno = %i\n", e2);
            printf("Last GetLastError = %i\n", e3);
            printf("Last _sys_errlist = %s\n", _sys_errlist[e4]);
      }
      delete[] s;
}

When I try the same approach with SEH exception, I get a compile error.
error C2713: Only one form of exception handling permitted per function
error C2712: Cannot use __try in functions that require object unwinding

I get those compile errors for the code below:

void testca()
{
      char* s = NULL;
      int* p = NULL;
      TRY
      {
            __try
            {
                  s = new char[10];
                  *p = 5;
            }
            __except(1)
            {
                  printf("Caught SEH exception = %0x8.8x\n", GetExceptionCode());
            }
      }
      CATCH_ALL(Ex)
      {
            Ex->ReportError();
      }
      END_CATCH_ALL;
      delete[] s;
}
I get same errors for this code too....

void test1a()
{
      char* s = NULL;
      int* p = NULL;
      __try
      {
            TRY
            {
                  s = new char[10];
                  *p = 5;
            }
            CATCH_ALL(Ex)
            {
                  Ex->ReportError();
            }
            END_CATCH_ALL;
      }
      __except(1)
      {
            printf("Caught SEH exception = %0x8.8x\n", GetExceptionCode());
      }
      delete[] s;
}
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
On my machine, using VC++ 6 SP6, with compiler options /nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Debug/TestException.pch" /Yu"stdafx.h" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c

the following program:

#include "stdafx.h"

int main(int argc, char* argv[])
{
      char* s;
      int* p = NULL;
      try
      {
            s = new char[10];
            *p = 5;
      }
      catch(...)
      {
            printf("Got Unknown error\n");
      }
  delete[] s;
}


Produces:

Got Unknown error

Nievergelt,
I'm not having a problem catching it in the C++ catch(...)
The problem is that I'm not getting a specific error message, exception type, or error number.
>>georg74,
I already thought about that as a work around, but that will require me to make a lot of code changes.
I'll have to add a bunch of extra functions.  And if I have a functions that has multiple TRY-CATCH_ALL, I will not be able to tell which block threw the exception.

since CPU/OS exception should not happen often, you can catch them
in the "main" function, or at similar appropriate place. I assume you want
to store "error report" and exit nicely even if your code produces a GPF or DIV0.

> I will not be able to tell which block threw the exception

to know which block it was, but not to have to split a lot of functions to
separate exception handling forms, you can follow one of these ways:

- use a global singleton class dbg_ctx, which will store the description
of the current block. this can be a simple string or a list. example:

class dbg_ctx
{
  public:
    static enter(const char *);  // store (add) context description
    static leave(); // remove context description
   
    static string context;
};

...

try {
    dbg_ctx::enter("this block of code");
    ... do something ...
    dbg_ctx::leave();
}
catch (exception &e) {
    ...
}

in the (outer) SEH, you then use dbg_ctx::context when generating
error message.

- write your own exception handler as described in the given article. complicated.

- include some debugger functionality. even more complicated.

hth,
georg
>>If it is a SEH exception, how can I used this in conjunction with MFC TRY-CATCH?

Because these are stwo unrelated exception handling mechanisms that do not "know" of  each other - unless you provide a translator function as described in http://msdn.microsoft.com/library/en-us/vclib/html/_crt__set_se_translator.asp ("_set_se_translator()")
The problem is that you are declaring an int *, not giving it any memory, and trying to dereference the pointer.  You need to allocate the int * at some point:
 int* p = NULL;
...
 p = new int;
...
*p = 5;
mnashadka,
>>The problem is that you are declaring an int *, not giving it any memory

Of course. LOL

Did you not read the entire question?

Please read the entire question.
>>Because these are stwo unrelated exception handling mechanisms that do not "know" of  each other -
I'm not trying to get them to know about each other.   I just need them to be able to work side by side in the same function.
I decided to use a combination of the three excpetion methods.

std::string glb_LastError;

void test1()
{
      char* s = NULL;
      int* p = NULL;
      try
      {
            TRY
            {
                  s = new char[10];
                  *p = 5;
            }
            CATCH_ALL(Ex)
            {
                  Ex->ReportError();
            }
            END_CATCH_ALL;
      }
      catch(...)
      {
            glb_LastError = "test1";
            throw;
      }
      delete[] s;
}



int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
      __try
      {
            test1();
      }
      __except(1)
      {
            printf("Caught SEH exception = %8.8x\n", GetExceptionCode());
            printf("Exception occurred at %s\n", glb_LastError.c_str());
      }
>> I decided to use a combination of the three excpetion methods

Just in case I have not mentioned this *g* - I'd use a translator as described in http://msdn.microsoft.com/library/en-us/vclib/html/_crt__set_se_translator.asp ("_set_se_translator()")