【问题标题】:Which is the proper way to terminate a delphi application?终止delphi应用程序的正确方法是什么?
【发布时间】:2023-11-10 07:49:01
【问题描述】:

我想在不执行任何其他代码行的情况下终止 Delphi 应用程序,我想知道哪种方法是正确的方法。此外,我想知道我目前正在做的事情是否有问题。 基本上,我的代码如下所示:

//Freeing all objects (Obj1.Free, etc..)
Application.Terminate;
Halt;

这是停止 Delphi 应用程序的正确方法还是应该以其他方式完成?

【问题讨论】:

  • 关闭主窗体是正确的方法。如果您愿意,可以直接使用Application.MainForm.Close;
  • 关闭 MainForm 只需调用Application.Terminate,因此您可以在需要时直接调用它。但是,不要说它只能在主线程的上下文中调用,不能在工作线程中调用。
  • @RemyLebeau 调用Application.MainForm.Close 不会简单地调用Application.Terminate,但如果分配了主窗体的OnCloseQueryOnClose 事件,它将处理它们。您甚至可以通过将OnCloseQuery 事件的CanClose 变量设置为false 来阻止应用程序关闭。但是调用Application.Terminate 不会处理这些事件。
  • 为了防止当前过程中的附加代码执行,在Application.Terminate;之后使用Exit;而不是Halt;
  • @SilverWarior - 是的,Close 将首先调用 DoClose() 然后终止。

标签: delphi terminate halt


【解决方案1】:

Application.Terminate() 打破TApplication.Run()TForm.ShowModal() 中的消息循环,让主线程正常退出,执行必要的清理等操作。

Vcl.Forms.TApplication.Terminate

结束应用程序执行。

调用Terminate 以编程方式结束应用程序。通过调用 Terminate 而不是释放应用程序对象,您允许应用程序以有序的方式关闭

Terminate 调用 Windows API PostQuitMessage 函数来执行应用程序的有序关闭。 Terminate 不是即时的。 Terminate 在 WM_QUIT 消息和主窗体关闭时自动调用。

另一方面,Halt() 是立即异常终止。基本上,将进程从内存中提取出来。仅在没有其他选项可用的极端情况下使用它。

System.Halt

启动程序的异常终止

Halt 执行程序异常终止并返回操作系统。

要正常终止 Delphi 应用程序,请在全局 Application 对象上调用 Terminate 方法。如果应用程序不使用提供Application 对象的单元,请从主程序块调用Exit 过程。

【讨论】:

  • 在这种特定情况下,我的目标是停止应用程序而不执行任何其他代码行(我只想释放所有内容并终止应用程序)。由于 Application.Terminate 不是立即的,我应该使用 Halt 还是使用它有任何可能的问题?
  • Halt 不会释放太多空间,但它确实会尝试进行一些内部系统清理。如果您的目标是立即退出进程,您可以使用Halt(),但如果执行的代码仍然太多,那么您将不得不求助于 Win32 API TerminateProcess() 函数。
  • 感谢您的澄清,我想 Halt 足以满足我的要求。您的消息非常有帮助,+1 并被接受。
【解决方案2】:

我想终止一个 Delphi 应用程序而不执行任何其他代码。

Application.TerminateHalt 都无法实现这一点。前者执行有序终止。会执行很多代码。致电Halt 更有希望。那是异常终止。但是单元完成代码被执行。

如果您希望尽快退出,同时执行最少的代码,请致电ExitProcess。这是Halt 的最后一步,通过直接调用ExitProcess,您可以避免Halt 在调用ExitProcess 之前执行的所有步骤。

【讨论】:

  • ExitProcess 将执行代码。比如DllMain。应该使用 TerminateProcess。
  • @Alex TerminateProcess 确实更残忍。
  • TerminateProcess 曾经对我来说是必要的邪恶。我们需要的第三方库在退出时导致异常。 TerminateProcess = 异常消失。 :-)
  • 如果不知道进程中所有线程的状态,最好调用TerminateProcess而不是ExitProcess
【解决方案3】:

我在使用 Application.Terminate 时遇到了一些问题,因为我必须启动 Form Close 程序,所以我只做了:

Form1.Close;

我在 .dproj 中找到了一个新的解决方案

begin
  ReportMemoryLeaksOnShutdown := True;
  Application.Initialize;
  Application.CreateForm(TFormMain, FormMain);
  if Not(VerifyCode()) then
  begin
      ShowMessage('Software unregistered!');
      Application.Terminate;
  end
  else
  Application.Run;
end.

【讨论】:

    【解决方案4】:

    如果代码必须在主窗体 OnCreate 上,只是为了说明一个额外的问题。

    在主窗体 OnCreate 事件上尝试这样的代码。它没有按预期工作,显示主窗体,然后应用程序完成。

    为了能够看到它,添加另一个表单并在其创建过程中放置​​一个长循环。

    似乎主项目源上的所有Application.CreateForm都已执行。

    示例代码:

    procedure TMyMainForm.FormCreate(Sender: TObject);
    begin
         ShowMessage('[1] This must allways be shown');
         if mrOK=MessageDlg('Exit?',mtConfirmation,[mbOK,mbCancel],0)
         then begin
                   Application.Terminate;
                   Exit;
              end;
         ShowMessage('[2] This must not allways be shown');
    end;
    procedure TMyOtherForm.FormCreate(Sender: TObject);
    begin
         ShowMessage('[3] This must not allways be shown');
    end;
    

    使用该代码,消息 [1] 和 [3] 始终显示。

    不显示 [3] 的唯一方法是调用 Halt。

    注意:为什么 MainForm OnCreate 上有这样的代码?简单的答案可能是,exe 检查要运行的条件并查看它们是否不满足(缺少文件等),粗鲁的一个(抱歉),只是因为我想要/需要。

    【讨论】:

    • Application.ShowMainForm := False;
    • 我的意思是,在创建主窗体时调用 Application.Terminate,它几乎什么都不做,因为主窗体创建是在项目文件“.dpr”中的主应用程序源调用 Application.Run 之前处理的。终止是中断主循环,但它仍然没有开始!并且 Application.Run 在开始主消息处理循环之前会显示先前创建的 MainForm。但也有解决方案:它有特殊的标志不显示形式。使 Application.ShowMainForm := False;主窗体根本不会显示。
    • 但是 [3] 你还是会看到,它是表单构造函数的一部分。从构造函数中退出不会破坏对象的构造。它可以通过引发异常来中断/例如,您可以调用 Abort,但有些事情必须处理。
    最近更新 更多