【问题标题】:When do I need to free a Data Module created by the Application?我什么时候需要释放应用程序创建的数据模块?
【发布时间】:2015-05-21 15:03:58
【问题描述】:

我的代码如下:

begin
  Application.Initialize;
  Application.Title := 'Controle Bancário';
  Application.CreateForm(T_DMEstagio, _DMEstagio);
  Application.CreateForm(T_frmLogin, _frmLogin);
  if (_frmLogin.ShowModal = 1) then
    begin
      FreeAndNil(_frmLogin);
      Application.CreateForm(T_frmPrincipal, _frmPrincipal);
      Application.Run;
    end;
    _DMEstagio.Free;

end.

如果我没有像在代码中那样显式释放 DM,我会收到访问冲突异常,但在另一个应用程序中,代码是这样的:

begin
    Application.Initialize;
    Application.Title := ' > Sistema de Gestão Comercial <';
    if HPrevInst = 0 then
    begin
      Application.CreateForm(TFrmPrincipal, FrmPrincipal);
      Application.CreateForm(TIBDM, IBDM);
      Application.Run;
    end ;
end.

我不必释放 DM,也没有任何异常。这是为什么呢?

【问题讨论】:

  • 答案在于您没有显示的代码。大概在 DM 代码的某个地方。将其缩减为 MCVE。甚至使用调试器来识别 AV 发生的位置。
  • 回答您的问题“我什么时候需要释放由应用程序创建的数据模块/表单?”从来没有。为什么你有 AV 是完全不同的问题和答案在你的其他代码中......
  • 我的 DM 中还没有代码,为了发生问题,我什至不必在我的主表单中输入,如果我一出现就关闭 _frmLogin,我已经收到错误.如果我调试它,我会在尝试销毁 RxHook 时得到 AV,我认为它不正确..
  • @DalijaPrasnikar 我想我发现了它是什么。当我确实在我的主表单上输入时,我没有收到任何 AV,如果您查看我的代码,您会看到 Application.Run; 仅在我访问主表单时才被激活,但如果我将此代码放在我的 if 之前得到一个不同的错误cannot make visible a modal form。我现在该怎么办?
  • @DavidHeffernan 问题似乎是Application.Run 只有在登录名和密码正确的情况下才会执行。到目前为止,处理它的最简单方法是确实释放 DM。有什么想法吗?

标签: delphi memory-management datamodule


【解决方案1】:

回答你的问题

“我什么时候需要释放应用程序创建的数据模块?”

永远不会。

使用Application.CreateForm 方法创建的所有数据模块和/或表单将归Application 所有并自动处理。


但看起来,您的问题与自动销毁过程无关。以下代码应该可以解决您的问题,因为某些组件和类需要应用程序完成其完整的初始化/运行周期才能优雅地销毁。 RXHook 可能就是其中之一。

begin
  Application.Initialize;
  Application.Title := 'Controle Bancário';
  Application.ShowMainForm := false;
  Application.CreateForm(T_DMEstagio, _DMEstagio);
  Application.CreateForm(T_frmLogin, _frmLogin);
  if (_frmLogin.ShowModal = 1) then
    begin
      FreeAndNil(_frmLogin);
      Application.ShowMainForm := true;
      Application.CreateForm(T_frmPrincipal, _frmPrincipal);
    end
  else Application.Terminate;
  Application.Run;
end.

那么上面的代码到底发生了什么?

您正在尝试显示登录表单并根据登录结果继续运行您的应用程序或终止它。

请务必注意,您创建的第一个表单将变为Application.MainForm,如果该表单在Application.Run 执行之前被释放,Application.MainForm 将被设置回nil。这将确保下一个创建的表单可以成为主表单。

在您的情况下,这意味着 _frmLogin 将被设置为您的 Application.MainForm。如果登录成功,将被释放,_frmPrincipal 将接管。但是如果登录不成功_frmLogin在执行Application.Run时仍然会是Application.MainForm,并且会再次显示。

这就是Application.ShowMainForm 出现的地方。当它设置为false Application.Run 时将运行而不显示任何表单。在您的情况下,它将阻止 _frmLogin 再次出现。当然,在成功登录后,您要将Application.ShowMainForm 设置回true 以确保应用程序正常启动。

在登录失败的情况下调用Application.Terminate 将确保您的应用程序退出应用程序主消息循环,该循环将从调用Application.Run 开始并正常终止。

【讨论】:

  • 差不多。如果我在你的示例中最后使用Application.Run,如果我只是执行应用程序并尝试关闭它,我必须关闭它两次。如果我使用Application.ShowMainForm 并在关闭应用程序时尝试做同样的事情,它会继续执行,但我再也看不到窗口了。我现在所做的是将Application.Terminate 放在登录表单的onClose 事件上。它正在工作,但也许我缺少一个更优雅的方法。
  • 您必须按原样使用上述代码 sn-p。所有部分都很重要。如果你省略一些你会得到错误的行为。不要将Application.Terminate 放入onClose 事件中并使用上面的代码而不进行修改,然后告诉我您面临的问题是什么。
  • 抱歉没有解释清楚。当我使用您的示例中的代码时,如果我尝试关闭登录表单,程序会继续运行,但我再也看不到登录表单了。
  • 如果你有Application.Terminate 就像上面的例子,那么问题就在你的登录表单中。你怎么关闭它?可以发一些代码吗?
  • 哎呀,必须说我没有使用Application.Terminate,因为我认为如果我第一次登录尝试失败,它会关闭我的应用程序。我的错。现在它工作得很好,谢谢先生!
猜你喜欢
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
相关资源
最近更新 更多