【问题标题】:Delphi XE4 : Closing Internal Package Form Causes Application TerminationDelphi XE4:关闭内部包表单导致应用程序终止
【发布时间】:2014-01-10 16:34:34
【问题描述】:

我的应用程序中有一个 test.bpl 包,它有一个名为 myPackageForm 的表单。 当我想关闭 myPackageForm 时加载我的包后,应用程序将终止。

主项目初始化:

Application.Initialize;
Application.CreateForm(TMainForm,MainForm);
Application.Run;

MainForm 表单创建:

aPackage := LoadPackage('my bpl path'+test.bpl);
@P_ItemClick := GetProcAddress(aPackage,'ItemClickExcecute');

主窗体按钮点击:

P_ItemClick(Sender);

testPackage 命令单元:

Procedure ItemClickExecute(Sender : TObject)
begin
   TmyPackageForm.ShowForm();
end;

exports
  ItemClickExecute;

end.

myPackagForm 有一个类过程来显示它:

Class Procedure TmyPackagForm.ShowForm;
begin
 if not Assigned(myPackagForm)
    myPackagForm := Application.CreateForm(TmyPackagForm ,myPackagForm );
 myPackagForm.Show;
end;

并且在 OnClose 程序中有:

Release;

作为解决方案,我尝试了另一个命令:

myPackagForm := TmyPackagForm.Create(Application); 

到 myPackagForm 创建;

谁能知道 Delphi XE4 在包上使用 CreateForm 命令时发生了什么?

【问题讨论】:

  • 没有任何改变。用 CreateForm 制作的第一个表单是主表单。
  • @David Heffernan 你是对的。但是为什么在我的包中使用 Application.CreateForm 命令时在 Delphi7 中关闭包表单没有问题?
  • 我有理由确定我知道发生了什么。我会写一个答案。

标签: delphi package delphi-xe4 terminate bpl


【解决方案1】:

TApplication.CreateForm不仅创建了一个表单,还把这个方法创建的第一个表单变成了TApplication.MainForm

关闭 MainForm 会导致关闭应用程序。

更新

您的应用程序中有 2 个TApplication 实例。

  1. 您的正常应用程序
  2. 在 BPL 中

因此,您在 BPL 中的表单将成为 BPL 的 MainForm。Application 关闭此表单将在您的主应用程序进程的上下文中执行 PostQuitMessage(0),这会强制整个应用程序退出。

【讨论】:

  • 调用包的主工程有一个MainForm。你认为它会随着内部包中的 createForm 而改变吗?在旧版本的 delphi(例如 7.0)中它可以工作!
  • 应用程序 MainForm 依赖于TApplication.CreateForm 创建的第一个表单。这不是静态的,取决于创建时间而不是位置。请在您的问题中添加更多代码,以便在创建表单时向我们显示
  • 感谢 Rufo 爵士的完整回答。但另一个问题是 PostQuitMessage 是 DelphiXE 中的新表现?因为我在 Delphi 7 中使用我的包中的 Application.CreateForm 命令没有问题。
【解决方案2】:

Rufo 爵士已经掌握了基本知识。调用CreateForm 创建的第一个表单成为主表单。当主窗体关闭时,应用程序关闭。

现在,您已经显示了对CreateForm 的两次调用。一个在主机应用程序中,一个在动态加载的包中。很明显,第一个运行的是来自主机应用程序。那么,封装中的表单如何才能让应用程序崩溃呢?好吧,正如 Rufo 爵士所说,只有在您的进程中有两个应用程序实例时,才会发生这种情况。

那么下一个问题是,你的进程中怎么会有两个应用程序实例?那不应该发生。包的全部意义在于允许 Delphi 单元在不同模块之间共享。如果您正确构建了应用程序,那么您将只有一个 TApplication 实例,该实例在主机可执行文件和所有包之间共享。

因此,唯一合理的结论是您的模块之一不是使用运行时包构建的。例如,主机应用程序可能包含 RTL/VCL,静态链接在可执行文件中。并且您的包链接到 RTL/VCL 运行时包。或者可能是动态加载的包,其中包含静态链接的 RTL/VCL。尽管 IIRC,编译器阻止了这种情况的发生。

无论出了什么问题,解决方案是您的所有模块都必须使用运行时包构建。所有 RTL/VCL 库都必须通过运行时包链接,不得静态链接。

因此,将Application.CreateForm 替换为TMyPackageForm.Create 只是在抑制更广泛的问题。在您的应用程序中只有一个 RTL/VCL 实例至关重要。通过在所有模块中使用运行时包来实现这一点。

TMyPackageForm.Create 无疑是在您的包中创建表单的正确方法。我只使用Application.CreateForm 作为主表单。我从不在其他任何地方使用它。但是不要试图仅仅通过从你的包中删除Application.CreateForm 来解决你的直接问题。修复与 RTL/VCL 的链接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 2019-11-19
    • 2014-05-12
    • 2016-08-01
    相关资源
    最近更新 更多