I was sure this used to work for me, and I've seen it out on the net (Jolyon Smith and David Moorhouse). Having just tried it in a simple program both in D2007 and in XE2 trial, it doesn't keep the modified Message. As soon as the "raise" happens, the message reverts back to the original exception.
What blindlingly obvious thing am I missing ? The alternative is to "raise Exception.Create(...)" but I want to just propogate the original exception back up the chain, only with additional information tagged along at each exception block.
var a: Integer;
begin
try
a := 0;
Label1.Caption := IntToStr(100 div a);
except
on e: Exception do
begin
e.Message := 'Extra Info Plus the original : ' + e.Message;
raise;
end;
end;
end;
Well blow me! This looked so wrong that I had to try it myself, and you're absolutely right! I've narrowed it down to the fact that this is an OS exception (divide by zero) that is generated by the OS itself and not by Delphi. If you try and raise an EIntError yourself you get the expected behaviour, and not what you see above. Note that expected behaviour occurs whenever you raise an exception yourself.
Update: In the System.pas unit there is the following code called when the exception is re-raised:
{ Destroy any objects created for non-delphi exceptions } MOV EAX,[EDX].TRaiseFrame.ExceptionRecord AND [EAX].TExceptionRecord.ExceptionFlags,NOT cUnwinding CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException JE @@delphiException MOV EAX,[EDX].TRaiseFrame.ExceptObject CALL TObject.Free CALL NotifyReRaise
So if the exception is not a Delphi exception (in this case an OS exception) then the (modified) "Delphi" exception is freed and the original exception is re-raised, thereby throwing away any changes made to the exception. Case closed!
Update 2: (couldn't help myself). You can reproduce this with the following code:
type TThreadNameInfo = record InfoType: LongWord; // must be $00001000 NamePtr: PAnsiChar; // pointer to message (in user address space) ThreadId: LongWord; // thread id ($ffffffff indicates caller thread) Flags: LongWord; // reserved for future use, must be zero end; var lThreadNameInfo: TThreadNameInfo; with lThreadNameInfo do begin InfoType := $00001000; NamePtr := PAnsiChar(AnsiString('Division by zero')); ThreadId := $ffffffff; Flags := $00000000; end; RaiseException($C0000094, 0, sizeof(lThreadNameInfo) div sizeof(LongWord), @lThreadNameInfo);
Have fun!
See Misha's explanation. As a workaround, you can do this:
except
on E: Exception do
begin
E := Exception(ExceptObject);
E.Message := '(Extra info) ' + E.Message;
AcquireExceptionObject;
raise E;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With