Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Help(convert Delphi to CPP)How to show raised exception in TThread objects?



Permlink Replies: 13 - Last Post: Feb 24, 2016 12:32 AM Last Post By: Vladimir Ulchenko
Adrian Bors

Posts: 12
Registered: 3/25/13
Help(convert Delphi to CPP)How to show raised exception in TThread objects?
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 8:30 AM
Hi,

I would like to show an exception, which is raised in TThread and I found an article in Delphi : [http://edn.embarcadero.com/article/10452]
I converted most of the code to CPP and I am unable to rewrite the below instruction in HandleException(void) member function.

myException = Exception(ExceptObject);

//------Form1----------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{

TMyThread *th = new TMyThread(true) ;
//th->OnTerminate = TermThread ;
th->Start();
}


//---------- TMyThread

void __fastcall TMyThread::DoHandleException(void)
{
// Cancel the mouse capture
if(GetCapture() != NULL)
{
SendMessage(GetCapture(), WM_CANCELMODE, 0, 0 );
}

//Show the Exception
if(dynamic_cast<Exception *> (myException))
{
Application->ShowException(myException);
}
else
{
ShowException(myException,NULL);
}

}


void __fastcall TMyThread::Execute()
{
try
{
throw Exception("Exception Raised!") ;
}
__finally
{
HandleException() ;
}
}

void TMyThread::HandleException(void)
{

myException = Exception(ExceptObject); // HERE IS THE PROBLEM
try
{
if(! (dynamic_cast<EAbort *>(myException)))
{
Synchronize(&DoHandleException);
}
}
__finally
{
delete myException ;
myException = NULL ;
}

}

Can any one please let me know, how to convert myException := Exception(ExceptObject); (Delphi) to CPP.
Thanks in advance

Edited by: Adrian Bors on Feb 16, 2016 8:32 AM

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Help(convert Delphi to CPP)How to show raised exception in TThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 11:21 AM   in response to: Adrian Bors in response to: Adrian Bors
Adrian wrote:

I found an article in Delphi :
[http://edn.embarcadero.com/article/10452]
I converted most of the code to CPP

Your translation is close, but it has two big flaws in it:

1. your Execute() code is using __finally to call HandleException(). That
means HandleException() is always called, even when no exception has been
thrown. You need to use a catch() instead:

void __fastcall TMyThread::Execute()
{
    myException = NULL;
    try
    {
        // throw an Exception
        throw Exception("I raised an exception");
    }
    catch (const Exception &)
    {
        HandleException();
    }
}


2. Your HandleException() code is destroying the object that ExceptObject()
returns. The Delphi code does not do that, and for good reason - the RTL
owns that memory, so DO NOT free the object manually. If you want to take
over management of the Exception's lifetime, you need to use AcquireExceptionObject()
instead of ExceptObject() so the RTL will release its ownership of the memory.

Can any one please let me know, how to convert
myException := Exception(ExceptObject);
(Delphi) to CPP.

The literal translation is:

myException = (Exception*) ExceptObject();


Now, with that said, there is already a mechanism in place to detect uncaught
exceptions from Execute() - the TThread::FatalException property, which contains
a pointer to the object that was thrown and not caught by Execute().

You can override the thread's virtual DoTerminate() method to check the FatalException,
eg:

void __fastcall TMyThread::DoHandleException()
{
    // Cancel the mouse capture
    if (GetCapture() != NULL)
        SendMessage(GetCapture(), WM_CANCELMODE, 0, 0 );
 
    //Show the Exception
    Exception *ex = dynamic_cast<Exception*>(FatalException);
    if (ex) then
        Application->ShowException(ex);
    else
        Sysutils::ShowException(ex, NULL);
}
 
void __fastcall TMyThread::Execute()
{
    throw Exception("Exception Raised!") ;
}
 
void __fastcall TMyThread::DoTerminate()
{
    if (FatalException)
    {
        if (!dynamic_cast<EAbort*>(FatalException))
            Synchronize(&DoHandleException);
    }
    TThread::DoTerminate();
}


Or, you can even check it in the OnTerminate event handler (which is already
Synchronize()'d for you):

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TMyThread *th = new TMyThread(true);
    th->OnTerminate = &TermThread; 
    th->Start();
}
 
void __fastcall TForm1::TermThread(TObject *Sender)
{
    TMyThread *th = (TMyThread*) Sender;
    if (th->FatalException)
    {
        if (!dynamic_cast<EAbort*>(th->FatalException))
        {
            // Cancel the mouse capture
            if (GetCapture() != NULL)
                SendMessage(GetCapture(), WM_CANCELMODE, 0, 0 );
 
            //Show the Exception
            Exception *ex = dynamic_cast<Exception*>(th->FatalException);
            if (ex) then
                Application->ShowException(ex);
            else
                Sysutils::ShowException(ex, NULL);
      }
}


--
Remy Lebeau (TeamB)
Vladimir Ulchenko

Posts: 248
Registered: 1/12/00
Re: Help(convert Delphi to CPP)How to show raised exception in TThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 11:48 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
On Tue, 16 Feb 2016 11:21:33 -0800, Remy Lebeau (TeamB) <no dot spam at no dot spam dot com> wrote:

1. your Execute() code is using __finally to call HandleException(). That

it might be better to avoid using non-standard __finally at all and switch to proper c++ idioms

over management of the Exception's lifetime, you need to use AcquireExceptionObject()

unfortunately AcquireExceptionObject() doesn't work in bcb, at least in "older" versions (not sure about newer ones)

--
Vladimir Ulchenko aka vavan
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Help(convert Delphi to CPP)How to show raised exception inTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 9:59 AM   in response to: Vladimir Ulchenko in response to: Vladimir Ulchenko
Vladimir wrote:

unfortunately AcquireExceptionObject() doesn't work in bcb, at
least in "older" versions (not sure about newer ones)

AFAIK, it works fine in modern versions, that bug was addressed years ago.

--
Remy Lebeau (TeamB)
Vladimir Ulchenko

Posts: 248
Registered: 1/12/00
Re: Help(convert Delphi to CPP)How to show raised exception inTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 18, 2016 1:51 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
On Wed, 17 Feb 2016 09:59:31 -0800, Remy Lebeau (TeamB) <no dot spam at no dot spam dot com> wrote:

AFAIK, it works fine in modern versions, that bug was addressed years ago.

any qc links?
as I use rs2007 I've never tested whether they fixed it or not in the following versions
btw IIRC you mentioned that you keep using bcb6 for your own projects

--
Vladimir Ulchenko aka vavan
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Help(convert Delphi to CPP)How to show raised exceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 18, 2016 9:53 AM   in response to: Vladimir Ulchenko in response to: Vladimir Ulchenko
Vladimir wrote:

btw IIRC you mentioned that you keep using bcb6 for your own projects

Yes, but my TThreads objects don't use the kind of exception handling that
Adrian is asking about. I don't use ShowException(), and I don't delegate
exception handling to the main UI thread. I do make use of TThread.FatalException,
though, which works fine in C++.

The one thing I do hate in BCB6, though, is EAccessViolation (and other EExternal
exceptions) have a NULL ExceptionRecord field if the exception originates
in C++, but works fine if it originates in Delphi. Makes it harder to track
down access violations and such when you don't have the memory addresses
to look at.

--
Remy Lebeau (TeamB)
Vladimir Ulchenko

Posts: 248
Registered: 1/12/00
Re: Help(convert Delphi to CPP)How to show raised exceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 18, 2016 10:47 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
On Thu, 18 Feb 2016 09:53:35 -0800, Remy Lebeau (TeamB) <no dot spam at no dot spam dot com> wrote:

Yes, but my TThreads objects don't use the kind of exception handling that

I meant I find it rather strange you recommended broken AcquireExceptionObject that most likely doesn't work in that version of bcb you keep
using

The one thing I do hate in BCB6, though, is EAccessViolation (and other EExternal
exceptions) have a NULL ExceptionRecord field if the exception originates
in C++, but works fine if it originates in Delphi. Makes it harder to track
down access violations and such when you don't have the memory addresses
to look at.

not sure what you mean without example
doesn't SEH help in that case?

--
Vladimir Ulchenko aka vavan
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Help(convert Delphi to CPP)How to show raisedexceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 19, 2016 9:02 AM   in response to: Vladimir Ulchenko in response to: Vladimir Ulchenko
Vladimir wrote:

I meant I find it rather strange you recommended broken
AcquireExceptionObject that most likely doesn't work in that
version of bcb you keep using

I don't use AcquireExceptionObject().

The one thing I do hate in BCB6, though, is EAccessViolation (and
other EExternal exceptions) have a NULL ExceptionRecord field if the
exception originates in C++, but works fine if it originates in
Delphi. Makes it harder to track down access violations and such
when you don't have the memory addresses to look at.
not sure what you mean without example

try
{
    int *p = NULL;
    *p = 1;
}
catch (const EAccessViolation &e)
{
    // catches the exception fine, but e.ExceptionRecord is NULL!
}


doesn't SEH help in that case?

Sure, but I would have to stop using a normal try/catch() block (as above)
and instead drop down to the SEH layer and use a __try/__except() block instead:

int filter(int ExceptionCode, LPEXCEPTION_POINTERS ExceptionInfo)
{
    if (code == EXCEPTION_ACCESS_VIOLATION)
    {
        // use ExceptionInfo as needed...
        return EXCEPTION_EXECUTE_HANDLER;
    }
    return EXCEPTION_CONTINUE_SEARCH;
}
 
...
 
__try
{
    int *p = NULL;
    *p = 1;
}
__except (filter(GetExceptionCode(), GetExceptionInformation()))
{
    // ...
}


That is fine when debugging code, but not very useful for production code.

--
Remy Lebeau (TeamB)
Vladimir Ulchenko

Posts: 248
Registered: 1/12/00
Re: Help(convert Delphi to CPP)How to show raisedexceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 20, 2016 1:15 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
On Fri, 19 Feb 2016 09:02:17 -0800, Remy Lebeau (TeamB) <no dot spam at no dot spam dot com> wrote:

I don't use AcquireExceptionObject().

yet you recommend it

try
{
int *p = NULL;
*p = 1;
}
catch (const EAccessViolation &e)
{
// catches the exception fine, but e.ExceptionRecord is NULL!
}

EH in bcb is one of its weakest points and bcb rtl doesn't store ExceptionRecord so I'm afraid you won't get it working without patching rtl

if you know they fixed AcquireExceptionObject don't you know whether they changed something regarding EExternal handling?

I believe I personally have both working VAcquireExceptionRecord (utilizing SEH) and patched custom rtl so for me

try
{
int * const p=nullptr;
*p=1;
}
catch(EExternal const &e)
{
//e.ExceptionRecord available/filled here
}

but I rarely (if ever) use these

That is fine when debugging code, but not very useful for production code.

I'm afraid for bcb sticking with SEH sometimes is the only reliable way to handle exceptions

--
Vladimir Ulchenko aka vavan
Jan Dijkstra

Posts: 206
Registered: 11/4/99
Re: Help(convert Delphi to CPP)How to show raisedexceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 22, 2016 4:30 AM   in response to: Vladimir Ulchenko in response to: Vladimir Ulchenko
Vladimir Ulchenko wrote:
On Fri, 19 Feb 2016 09:02:17 -0800, Remy Lebeau (TeamB) <no dot spam at no dot spam dot com> wrote:

I don't use AcquireExceptionObject().

yet you recommend it

try
{
int *p = NULL;
*p = 1;
}
catch (const EAccessViolation &e)
{
// catches the exception fine, but e.ExceptionRecord is NULL!
}

EH in bcb is one of its weakest points and bcb rtl doesn't store ExceptionRecord so I'm afraid you won't get it working without patching rtl

if you know they fixed AcquireExceptionObject don't you know whether they changed something regarding EExternal handling?

I believe I personally have both working VAcquireExceptionRecord (utilizing SEH) and patched custom rtl so for me

try
{
int * const p=nullptr;
*p=1;
}
catch(EExternal const &e)
{
//e.ExceptionRecord available/filled here
}

but I rarely (if ever) use these

That is fine when debugging code, but not very useful for production code.

I'm afraid for bcb sticking with SEH sometimes is the only reliable way to handle exceptions

--
Vladimir Ulchenko aka vavan

I also rely on SEH, but applied differently

LONG CALLBACK LicVectoredExceptionHandler (PEXCEPTION_POINTERS exceptionInfo)
{
  return LicExceptionHandler (exceptionInfo->ExceptionRecord, NULL, exceptionInfo->ContextRecord, NULL);
}
 
typedef LONG  (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo);
typedef PVOID (WINAPI *TAddVectoredHandler) (ULONG firstHandler, PVECTORED_EXCEPTION_HANDLER handler);
typedef ULONG (WINAPI *TRemoveVectoredHandler) (PVOID handler);
 
static PVOID vectoredHandler = 0;
 
void __fastcall LicRegisterSehMonitor (void)
{
  HMODULE hLibrary = GetModuleHandle ("Kernel32.dll");
  FARPROC proc     = hLibrary ? ::GetProcAddress (hLibrary, "AddVectoredExceptionHandler") : NULL;
 
  if (proc)
  {
    vectoredHandler = ((TAddVectoredHandler) proc) (1, &LicVectoredExceptionHandler);
  }
 
//  vectoredHandler = AddVectoredExceptionHandler (1, &LicVectoredExceptionHandler);
}
 
void __fastcall LicUnregisterSehMonitor (void)
{
  if (vectoredHandler)
  {
    HMODULE hLibrary = GetModuleHandle ("Kernel32.dll");
    FARPROC proc     = hLibrary ? ::GetProcAddress (hLibrary, "RemoveVectoredExceptionHandler") : NULL;
 
    if (proc && ((TRemoveVectoredHandler) proc) (vectoredHandler))
//    if (RemoveVectoredExceptionHandler (vectoredHandler))
    {
      vectoredHandler = 0;
    }
  }
}

Where LicExceptionHandler does the actual work. In our case, it logs all sorts of useful info. And, being hooked into the vectored handlers, it sees every single exception as it works it's way through the various try catch blocks. With the obvious benefit that logging only takes place at one location in the code.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Help(convert Delphi to CPP)How to showraisedexceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 22, 2016 10:53 AM   in response to: Jan Dijkstra in response to: Jan Dijkstra
Jan wrote:

In our case, it logs all sorts of useful info. And, being hooked into the
vectored handlers, it sees every single exception as it works it's way
through the various try catch blocks. With the obvious benefit that
logging only takes place at one location in the code.

Interesting approach. I know of the existence of vectored exception handling,
but have never actually used it. I do need logging of exceptions (and no,
using tools like MadExcept or EurekaLog is not an option for my project,
we have our own in-house logging solution instead).

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Help(convert Delphi to CPP)How to showraisedexceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 22, 2016 10:48 AM   in response to: Vladimir Ulchenko in response to: Vladimir Ulchenko
Vladimir wrote:

I don't use AcquireExceptionObject().
yet you recommend it

I did not recommend it, I merely mentioned its existence in case it is
needed.

I believe I personally have both working VAcquireExceptionRecord
(utilizing SEH) and patched custom rtl so for me

try
{
int * const p=nullptr;
*p=1;
}
catch(EExternal const &e)
{
//e.ExceptionRecord available/filled here
}

but I rarely (if ever) use these

Maybe not directly. However, having a non-null ExceptionRecord does allow
the e.Message property to contain a more detailed erorr message containing
the memory addresses and type of access that failed. Very useful for logging
purposes.

--
Remy Lebeau (TeamB)
Vladimir Ulchenko

Posts: 248
Registered: 1/12/00
Re: Help(convert Delphi to CPP)How to showraisedexceptioninTThreadobjects? [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 24, 2016 12:32 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
On Mon, 22 Feb 2016 10:48:17 -0800, Remy Lebeau (TeamB) <no dot spam at no dot spam dot com> wrote:

Maybe not directly

not sure I understood this

However, having a non-null ExceptionRecord does allow

well one can have it with patched rtl, I just don't use it this way

--
Vladimir Ulchenko aka vavan
Adrian Bors

Posts: 12
Registered: 3/25/13
Re: Help(convert Delphi to CPP)How to show raised exception in TThreadobjects?
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 22, 2016 4:45 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thank you Remy Lebeau and I am accepting your reply as an answer to my question.
Once again thanks for your help.

I am also thankful to Vladimir Ulchenko and Jan Dijkstra .

Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02