RE: How to correctly write Try..Finally..Except statements?
I'm still confused by the OP's original question. Specifically, the last line of the procedure (outside of the try..finally..end) that reads "Screen.Cursor:=crDefault".
My understanding is that any exceptions raised inside a try..except|finally..end block WILL execute the code after the "end" of the "try".
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Screen.Cursor := crHourGlass;
Obj := TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
Screen.Cursor := crDefault;
end;
In the above example, I don't see any reason why "Screen.Cursor:=crDefault" would not be executed. Please correct me if I'm wrong.
As a further example, I've compiled this little bit of code to help illustrate. When the code is ran, THREE (3) ShowMessage() dialogs will be presented. The first "Exception Raised" and the second "finally" and the third "at end".
procedure TForm1.Button1Click(Sender: TObject);
begin
try
try
showMessage(format('%s', [12]));
except
showMessage('Exception raised');
end;
finally
showMessage('finally');
end;
showMessage('at end');
end;
So, I'm confused on why his "Screen.Cursor:=crDefault" isn't being ran, in it's original form and code. Can someone please elaborate?
The code you posted seems to work fine, because you're able to handle all possibilities. Try changing it somewhat though, so that there's an exception raised your code doesn't handle:
Run this, and you'll see
Finally
, then the exception for42
, but noGot here
message. This is because the exception took you out of the current block, the stack is unwound, and the code from theend
of the finally to the end of the procedure never executes.Move the final
ShowMessage
call from where it is to inside thefinally
and run again.You'll now see both calls to
ShowMessage
in thefinally
block, one after the other, but not the one after thefinally
block'send;
. Code inside thefinally
block is guaranteed to execute, while code beyond it may or may not.To make it even more clear, the presence of the
try..except
block can be removed:The entire purpose of the
try..finally
block is to ensure that code inside thefinally
section will execute before the procedure ends.You don't actually catch the exception. In this case, upon exception, the "finally" block of code will execute, and then the exception will unwind the stack.
In Delphi, the
finally
block doesn't really handle the exception that occured in thetry
block. It only guarantees that the code in thefinally
block will always be executed, whether an exception occured or not in thetry
block. If an exception really happened in there, it won't get caught. And when an exception didn't get caught, you know what happened to the code below it.To catch the exception that might be occured, use the
try...except...
block instead. You can combine these two construct to do those two action: (1) guarantee the execution some piece of code, and (2) catch the exceptions which might occured. The common usage is like this:So, you should change your code and move the
Screen.Cursor := crDefault;
inside thefinally
block. In addition, add thetry...except...
block to surround thetry...finally...
block. Like this:Or, if you are not sure that the code
Obj := TSomeObject.Create;
is safe enough, you should add the secondtry...finally...
block to surround it, like this:There, hope it helps :)