如何在TDataModule.OnCreate事件中捕获异常?

时间:2017-10-31 20:07:29

标签: delphi exception-handling

我很恳请您就我在Delphi中使用try/except块遇到的以下问题提出建议。

我有一个简单的应用程序 - 一个名为fr_MAIN的MainForm和一个名为TDataModule的{​​{1}}。 DM不会自动创建,但会在DM的{​​{1}}事件中的运行时创建:

fr_MAIN

Button2.OnClick在其procedure Tfr_MAIN.Button2Click(Sender: TObject); begin try DM := TDM.Create(nil); Showmessage('DM started!'); except on E:Exception do begin Showmessage('DM not started!'); end; end; 事件中包含一些代码:

DM

问题在于,当我点击OnCreate时,我收到procedure TDM.DataModuleCreate(Sender: TObject); begin raise Exception.Create('this is error!'); // DM code here ... end; 异常消息,Button2的其余部分未运行 - 这是正确的!但是,我还收到'this is error!'消息而不是DM code here消息。

'DM started!'引发的异常会中断操作,但不会在表单的'DM not started!'块中捕获!

为什么会这样?

2 个答案:

答案 0 :(得分:22)

TDataModule 1 对其OnCreate事件中引发的异常进行了特殊处理。

此处处理异常:

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;

默认情况下,TApplication会将TApplication.HandleException()分配给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;

因此,TDataModule.DoCreate()正在捕获异常并将其传递给TApplication.HandleException(),然后默认情况下会显示一个弹出对话框。然后由于TDataModule.HandleCreateException()返回True,因此不会重新引发捕获的异常。此异常现在被视为已处理,允许程序正常继续进行Showmessage('DM started!');调用。

要在引发异常时避免弹出对话框,您可以分配TApplication.OnException事件处理程序:

  

Vcl.Forms.TApplication.OnException

     

使用OnException更改时出现的默认行为   异常不由应用程序代码处理。 OnException事件   在HandleException方法中自动调用handler。

TDataModule.DoCreate()仍然会抓住并驳回异常。如果你想避免这种情况,那么异常会在调用堆栈中向上传播,根本不会从TDataModule.OnCreate事件中引发异常。覆盖虚拟TDataModule.Create()构造函数并从那里引发异常。

1 :同样的事情也发生在TCustomForm

答案 1 :(得分:0)

更好的解决方案是针对所有形式的所有地方对其进行修复。

从{strong> \ Vcl \ Source 文件夹中复制Forms.pas到您的项目文件夹(或公共共享库文件夹,以便所有项目都可以从中受益)。

然后将 TCustomForm.HandleCreateExcpetion 更改为:

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;

如果您使用的是早期版本的Delphi,则不会出现 HandleCreateException 。您必须直接修复呼叫者:

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;