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;

TDataModule1 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.