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

Delphi 如何捕获TDataModule.OnCreate事件中的异常?,delphi,exception,Delphi,Exception,我在Delphi中遇到了一个try/except块的以下问题 我有一个简单的应用程序——一个名为fr\u MAIN的主窗体和一个名为DM的TDataModule的主窗体DM不是自动创建的,而是在运行时在fr\u MAIN的按钮2中创建的。OnClick事件: procedure Tfr_MAIN.Button2Click(Sender: TObject); begin try DM := TDM.Create(nil); Showmessage('DM started!');

我在Delphi中遇到了一个
try/except
块的以下问题

我有一个简单的应用程序——一个名为
fr\u MAIN
的主窗体和一个名为
DM
TDataModule
的主窗体
DM
不是自动创建的,而是在运行时在
fr\u MAIN
按钮2中创建的。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;
procedure TDM.DataModuleCreate(Sender: TObject);
begin
  raise Exception.Create('this is error!');
  // DM code here ...
end;
DM
在其
OnCreate
事件中有一些代码:

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;
procedure TDM.DataModuleCreate(Sender: TObject);
begin
  raise Exception.Create('this is error!');
  // DM code here ...
end;
问题是,当我点击
按钮2
时,我收到
“这是错误!”异常消息,此处的
DM代码的其余部分不运行-这是正确的!但随后我也收到了
“DM start!”消息,而不是
'DM not started!'消息

DM
引发的异常会中断操作,但不会在表单的
块中捕获,除非

这是为什么?

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

要避免引发异常时出现弹出对话框,可以指定
TApplication.OnException
事件处理程序:

Vcl.Forms.TApplication.OneException

使用OneException可更改 应用程序代码不处理异常。OneException事件 HandleException方法中会自动调用处理程序

但是异常仍然会被
TDataModule.DoCreate()
捕获并排除。如果要避免这种情况,因此异常会向上传播到调用堆栈,则根本不要从
TDataModule.OnCreate
事件引发异常。重写虚拟
TDataModule.Create()
构造函数,并从那里引发异常


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

中,更好的解决方案是对所有表单进行修复

Forms.pas
\Vcl\Source文件夹复制到项目文件夹中(或复制到公共共享库文件夹中,以便所有项目都能从中受益)

然后将TCustomForm.HandleCreateException更改为:

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;

默认情况下,
TApplication
告诉
TDataModule
接受由
TDataModule.OnCreate
事件引发的异常(有关具体细节,请参阅Tom的回答)。要执行您要求的操作,您应该重写虚拟的
TDataModule.Create()
构造函数来引发异常,而不是使用
TDataModule.OnCreate
事件。非常感谢亲爱的Lebeau先生和Brunberg先生!这次我学到了一些非常重要的东西,关于TDataModule创建事件的进展情况。为了更清楚地了解这一点,在不久的将来,DM将从TService中创建(并发布)——这对我来说会使事情更加复杂。我知道你提出的想法,但凭借我在德尔福的技能,我现在不想再去想它了——至少在我建立TService之前是这样的——目前我将通过一个事实来了解,除了加薪例外。在DM内部创建。从另一个单位创建非常感谢你,致以最良好的问候