在另一个窗体的 OnDestroy 事件中释放窗体时发生访问冲突

Access violation while freeing a form in another form's OnDestroy event

我正在处理 Delphi 7。我在释放表单时遇到访问冲突错误。

1) 创建新应用程序 Delphi 7 (Unit1)

2) 添加新表格 (Unit2)

3) 对于 Unit1 使用子句添加 Unit2 并编写下面的代码

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, unit2, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  form2 : TForm2;
begin
  try
    form2 := TForm2.Create(Application);
    //form2.ShowModal;
  finally
    //FreeAndNil(form2);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Form2 <> nil then
    FreeAndNil(form2);
end;

end.

4) 运行 应用程序并关闭 Form1 -- 出现以下错误。

我不想在 OnClose 或 OnCloseQuery 上释放 Form2 对象,因为我在这些上有一些代码events.I想在 OnClose 或 OnCloseQuery 后释放 Form2 对象。

为什么我会收到错误信息以及如何解决这个问题?

问题是 Form2 将在 unit2 中声明,并再次在此表单的 FormCreate 中声明。你只是用错了。

我建议把unit2的Form2的声明去掉,只用本单元的那个,同时把声明移到private section

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    Form2: TForm2; // Declare the form here, not in unit2
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form2 := TForm2.Create(nil);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // no need to check if Form2 exists, it is created in the FormCreate and will thus always exist
  // unless there is code somewhere that we cant see that destroys it.
  // Also no need to set the variable to nil as mentioned in the Tom's answer
  Form2.Free;
end;

您描述的问题可以在 Delphi 7 中重现,按照您的步骤操作。访问冲突的原因是 Form2 是在 .dpr 文件中自动创建的(这使应用程序成为表单的所有者),但您还试图通过调用 [=13= 来控制其生命周期] 在 Form1OnDestroy 事件中。当您尝试释放表单时,应用程序已将其释放。

不太清楚,为什么当应用程序(大概)即将终止(因为主窗体正在被销毁)时,您试图释放 Form2。由于应用程序是所有者,您可以安全地让应用程序处理它的职责。

您需要决定,您希望谁成为 Form2 的所有者。

  1. 如果是你,你应该从自动创建的表单列表中删除 Form2(请参阅 Project - Options - Forms 并将 Form2 移至 Available forms)。
  2. 如果您希望应用程序成为所有者,只需不要 Free 表单,如果需要,使用 hideshow 方法来控制其可见性,但离开它交给应用程序根据其设计销毁它。

顺便说一句,您在TForm1.FormCreate()中的代码与您看到的AV无关。那Form2是一个单独的实例,如果本意是为了展示一个splash形式,也可以,如下:

procedure TForm1.FormCreate(Sender: TObject);
var
  form2 : TForm2;
begin
  form2 := TForm2.Create(nil);
  try
    form2.ShowModal;
  finally
    form2.Free;
  end;
end;

表单不需要所有者,因此 Create 中的 nil。由于变量 form2 是本地变量,因此绝对没有必要将其设为 nil。