How to catch an Exception in a TDataModule.OnCreate event?
The better solution is to fix it for all forms everywhere.
Copy Forms.pas
from the \Vcl\Source folder into either your project folder (or into a common shared library folder so that all projects will benefit from it).
Then change TCustomForm.HandleCreateExcpetion to:
function TCustomForm.HandleCreateException: Boolean;
begin
{
If an exception is raised during a form's OnCreate event, the exception is hidden.
This leaves you with an only partially initialized form.
The correct behavior is to **not** eat the exception.
We do that by returning False. The caller will then throw.
}
// Application.HandleException(Self);
// Result := True;
Result := False;
end;
If you're on earlier versions of Delphi, there is no HandleCreateException. You have to fix the caller directly:
procedure TCustomForm.DoCreate;
begin
{
If the Form.OnCreate event throws an exception, the exception is eaten, and the caller never knows about it.
Don't do that.
}
if Assigned(FOnCreate) then
begin
//try
FOnCreate(Self);
//except
// Just let it throw. Christ you guys are dense.
//Application.HandleException(Self);
//end;
end;
if fsVisible in FFormState then
Visible := True;
end;
TDataModule
1 has special handling of exceptions raised in its OnCreate
event.
The exception is handled here:
procedure TDataModule.DoCreate;
begin
if Assigned(FOnCreate) then
try
FOnCreate(Self);
except
if not HandleCreateException then // <-- here
raise;
end;
end;
function TDataModule.HandleCreateException: Boolean;
begin
if Assigned(ApplicationHandleException) then
begin
ApplicationHandleException(Self); // <-- here
Result := True;
end
else
Result := False;
end;
By default, TApplication
assigns TApplication.HandleException()
to ApplicationHandleException
:
constructor TApplication.Create(AOwner: TComponent);
var
...
begin
inherited Create(AOwner);
...
if not Assigned(System.Classes.ApplicationHandleException) then
System.Classes.ApplicationHandleException := HandleException; // <-- here
if not Assigned(System.Classes.ApplicationShowException) then
System.Classes.ApplicationShowException := ShowException;
...
end;
So, TDataModule.DoCreate()
is catching the exception and passing it to TApplication.HandleException()
, which then displays a popup dialog by default. And since TDataModule.HandleCreateException()
then returns True, the caught exception is not re-raised. The exception is now considered handled, allowing the program to continue normally to its Showmessage('DM started!');
call.
To avoid the popup dialog when the exception is raised, you can assign a TApplication.OnException
event handler:
Vcl.Forms.TApplication.OnException
Use OnException to change the default behavior that occurs when an exception is not handled by application code. The OnException event handler is called automatically in the HandleException method.
But the exception is still going to be caught and dismissed by TDataModule.DoCreate()
. If you want to avoid that, so the exception propagates up the call stack, don't raise the exception from the TDataModule.OnCreate
event at all. Override the virtual TDataModule.Create()
constructor and raise the exception from there instead.
1: The same thing also happens in TCustomForm
.