Delphi XE4:关闭内部包表单导致应用程序终止。

3
我在我的应用程序中有一个名为test.bpl的包,其中包含一个名为myPackageForm的表单。 当我加载我的包并尝试关闭myPackageForm时,应用程序将终止。
主项目初始化:
Application.Initialize;
Application.CreateForm(TMainForm,MainForm);
Application.Run;

主窗体的创建事件(FormCreate):
aPackage := LoadPackage('my bpl path'+test.bpl);
@P_ItemClick := GetProcAddress(aPackage,'ItemClickExcecute');

主窗体点击按钮: P_ItemClick(Sender); 测试包命令单元:
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); 

对于我的PackageForm创建;

有人知道在Delphi XE4中使用CreateForm命令时发生了什么吗?这是关于包的问题。


没有任何改变。使用CreateForm创建的第一个表单是主表单。 - David Heffernan
@David Heffernan 您是正确的。但是为什么我在使用Application.CreateForm命令时,在Delphi7中关闭包表单时没有任何问题呢? - Mohammad Gohari
我相当确定我知道发生了什么。我会写一个答案。 - David Heffernan
2个回答

3

TApplication.CreateForm 不仅仅是创建一个窗体,还会将通过该方法创建的第一个窗体设置为TApplication.MainForm

关闭主窗体也会导致应用程序关闭。

更新

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

  1. 常规应用程序
  2. BPL内部

所以BPL内部的窗体将成为BPL的主窗体。Application并关闭此窗体将在主应用程序进程的上下文中执行PostQuitMessage(0),这将强制整个应用程序退出。


调用该包的主项目有一个 MainForm。您认为它会在内部包中使用 createForm 进行更改吗?在旧版本的 Delphi(例如 7.0)中,它可以工作! - Mohammad Gohari
应用程序 MainForm 依赖于由 TApplication.CreateForm 创建的第一个表单。这不是静态的,而是取决于创建时间而不是位置。请在您的问题中添加更多代码,以显示我们何时创建表单。 - Sir Rufo
感谢Rufo先生的完整回答。但是另一个问题是,PostQuitMessage在DelphiXE中是一项新功能吗?因为我在我的包中使用Application.CreateForm命令时,在Delphi 7中没有任何问题。 - Mohammad Gohari

3
Sir Rufo已经掌握了基本方法。使用CreateForm调用创建的第一个表单成为主表单。当主表单关闭时,应用程序也会关闭。
现在,你展示了两个CreateForm的调用。一个在宿主应用程序中,另一个是在动态加载的包中。很明显第一个运行的是来自宿主应用程序的调用。那么,包中的表单如何使应用程序崩溃呢?嗯,只有在进程中存在两个应用程序实例时才会发生这种情况。
那么下一个问题是,在进程中怎么可能存在两个应用程序实例?这不应该发生。包的整个目的是允许Delphi单元在不同模块之间共享。如果你正确地构建了应用程序,那么你将只有一个TApplication实例,它在宿主可执行文件和所有包之间共享。
因此,唯一合理的结论是你的模块之一没有使用运行时包进行构建。例如,也许宿主应用程序包括RTL/VCL,静态链接在可执行文件内。而你的包则链接到RTL/VCL运行时包。或者也许是动态加载的包包含静态链接的RTL/VCL。虽然我IRC,编译器会阻止这种情况发生。
无论出了什么问题,解决方案是所有模块都必须使用运行时包进行构建。所有的RTL/VCL库必须通过运行时包链接,并且不能静态链接。
因此,将Application.CreateForm替换为TMyPackageForm.Create只是压制了更广泛的问题。重要的是,在应用程序中只有一个RTL/VCL实例。通过在所有模块中使用运行时包来实现这一点。
当然,TMyPackageForm.Create创建一个表单是正确的方式。我只在主表单中使用Application.CreateForm。我从不在其他任何地方使用它。但不要仅仅通过从包中删除Application.CreateForm来修复你的立即问题。修复与RTL/VCL的链接。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接