Hi Madshi,
i am using madExcept and have a problem with nested Exception. When i nest exceptions with RaiseOuterException and madExcept is enabled then the inner exception gets lost (value is nil). When I disable madExcept all is fine.
I am using madExcept with version 2.8.3.0 (but I could also reproduce it with version 2.8.8.0) and Delphi 10 Seattle. There were no special settings for madExcept, only the default values. Below a small console-project with which I tested it. With madExcept the variable 'LInnerException' was nil and without the variable contains the first exception.
Do I have to set some options or is madExcept not able to handle nested exceptions?
It's been a looong time since I looked into nested exceptions. I have quite a bit of extra code in madExcept just for nested exceptions. But I'm not sure I've ever seen anybody manually accessing the "InnerException" property. So far all users only wanted to get the inner exceptions reported automatically by madExcept. I guess maybe it's possible that whatever madExcept is doing to automatically show nested exceptions in its exception box might render the "Exception.InnterException" property not working, anymore? I'm not sure. If that's the case, then you're the first user actually noticing...
May I ask for which purpose you need to have access to the "InnerException" property?
I would use it for chains of exception. Currently when I have the case that one exception is raised because of another exception i take the first one and append some text to the error-message. But when I make it this way I loose all data from the second exception and my idea was to change this by using inner exception. Which is also the recommended way for such cases.
Ok, but can't you simply raise a new exception then in your try..except block? Why do you need to access "E.InnerException"? madExcept should still report all the inner exceptions correctly in its bug reports. Or does that not work?
I cannot simply raise another exception with 'raise' because in this case the first exception will be destroyed. As far as i know the first exception will not be destroyed only when i reraise it with 'raise' or wrap it with another exception with 'RaiseOuterException'.
I made some debugging and for some reasons when a activate madexcept this function will not be executed anymore 'Exception.SetInnerException' (which is responsible for setting the current exception as inner exception) when i call 'RaiseOuterException'.
Have you tried simply raising another exception? As I mentioned before it's been a very long time since I last looked into this, but from the top of my head, I think it might just work, because madExcept also tried to make inner exceptions work even for older Delphi versions which had no explicit support for that. But I might be wrong...
I changed my first program a little bit. And only with 'RaiseOuterException' a innerException is available at all, but also only when a disable madexcept. When madexcept is enabled the innerexception is also nil (even with 'RaiseOuterException').
program TestProject;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
LInnerException: Exception;
LExeption : Exception;
begin
try
// First try except
try
raise Exception.Create('First Exception...');
except
on LExeption: Exception do
begin
Exception.RaiseOuterException(Exception.Create('Second Exception...'));
// raise Exception.Create('Second Exception...');
// raise;
end;
end;
except
on LExeption: Exception do
begin
LInnerException := LExeption.InnerException;
Writeln('BaseException: ' + LExeption.Message);
if Assigned(LInnerException) then
begin
Writeln('InnerException: ' + LInnerException.Message);
end
else
begin
Writeln('No Inner Exception');
end;
end;
end;
Readln;
end.
Sometimes it is desirable to catch an exception and throw another exception. If the new exception keeps a reference to the first exception, the first exception is called a nesting exception. The above code is an example of a nesting exception. ... The stack-trace starts when the exception is thrown.
Hi madshi,
thanks for the clarification. I didn't expected to see the both exceptions only in the madexcept callstack. I not really happy that with madexcept i have not more a reference to the first exception object from my sourcecode. Or is there a way how i can get the first exception object?
But anyway now I know where I have to look for the nested exceptions. Thanks.
I'm still trying to understand why you need to access the "InnerException" property in the first place, considering that madExcept already reports all this perfectly, without you having to do anything at all in your code?
Now that i know where i can find the inner exception in the bug-report it is only a theoretical problem which happens when I want to evaluate the innerexception-property inside of a try except. Currently i don't do this (therefor it's only theoretical). What i don't like is the fact that I loose the access to this object (inner exception at run-time) by using madexcept. But i don't need the access right now and I have currently no real world example where I would need it in near future.
Ok, thanks. I understand that it's kinda annoying that access to the property is no longer working when using madExcept, even if you don't have a practical need for it right now. But that said, as I mentioned earlier, no other madExcept user even brought this topc up before - ever. So I assume that in real life there's just no need for this property, because madExcept automatically reports everything correctly in its bug reports already, anyway.
I don't recall the exact reason why the property stops working. But I think it has to do with trying to make everything work without you having to do anything manually (like e.g. calling RaiseOuterException instead of RaiseException etc), and also trying to make everything work with older Delphi versions etc. I'm not sure if it would be easy or hard for me to make the property work. It's been too long since I've dived into the depth of the inner exception logic. So I'd have to reinvestigate. But considering that there's no real practical need for that right now, anyway, I'd rather ignore this, until a critical need for access to the property actually comes up.
Hi! I would like to join this old descussion to add a case that explaines why I do need innerExceptions
So I have an exception class ExceptionFields that contains a set of field-value pairs that I add to bug report. This happens in the code that is called indirectly from exception handler that I register with RegisterExceptionHandler:
procedure AddFieldsToException(const exceptIntf: IMEException);
var
e: ExceptionFields;
Field: string;
Value: string;
begin
if exceptIntf.ExceptObject is ExceptionFields then
begin
e := exceptIntf.ExceptObject as ExceptionFields;
try
for Field in e.Fields do
if e.GetValue(Field, Value) then
exceptIntf.BugReportHeader.Add(Field, Value);
except
end;
end;
end;
So that I can write descendants for this class and add some specific extra information for exceptions that I can get later from bug reports, that will help me to fix the problems. The good example is ESQLException = class(ExceptionFields) which provides me SQL that caused the exception.
The problem is that without Exception.InnerException I only can handle the most outer ExceptionFields and get data from its Fields, not any inner.
I think you might be misunderstanding the concept of "InnerExceptions"? They do not give you access to inherited classes of the same exception object! If you have ESQLException which is inherited from ExceptionFields, then ESQLException will provide you with all the properties of ExceptionFields, as well. So you can directly e.g. use "someESQLException.Fields". This works just fine. InnerExceptions is something completely different.