【问题标题】:Delphi XE4 - Form create dynamically in DLL results in AVDelphi XE4 - 在 DLL 中动态创建表单导致 AV
【发布时间】:2014-05-12 12:44:46
【问题描述】:

我的主应用程序中加载了一个 DLL 应用程序。 DLL 包含在运行时创建的表单。 功能是: 在主应用程序中,我有一个菜单,只要按下它就会从 DLL 中调用一个过程。此过程动态创建表单。

procedure doCreateForm;
var
  myForm: TForm1;
begin
  myForm := TForm1.Create(nil)
  try
    ...
  except
    myForm.Free;
  end;
end;

关闭程序:

procedure CloseWindow(ASender: TForm1);
begin
  FreeAndNil(ASender);
  Application.ProcessMessages;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  CloseWindow(Self);
end;

问题(访问冲突)仅在第二次尝试创建表单时出现。不是第一次,不是第 3 次、第 4 次、第 5 次等等。

所以我点击菜单,表单被创建(动态)并关闭(如果在表单创建事件期间不满足条件)。我再次点击菜单,当myForm.Create(nil) 被调用时,AV 就出现了。我再次单击菜单,一切正常。我一次又一次地点击,一切都好。只有在第二次按下时,AV 才会升高。 DLL中动态创建可视化表单有什么问题吗?

更详细的解释:

链条是:

  1. 我创建 MyForm (myForm := TForm1.Create(nil))

  2. 在显示表单之前,我做了一些条件测试。

  3. 如果一切正常,myForm.Show - 工作正常,我也可以正常关闭 myForm

  4. 如果有问题:

一)。我创建了一个消息表单myMessageForm := TMyMessageForm.Create(nil),其中包含一个关闭计时器(表单在 10 秒后关闭)。此表单在 onClose 事件中有 action:=caFree

b)。我调用 myForm.Close。此表单在 onClose 事件中也有 action:=caFree - 此表单在 myMessageForm 关闭之前关闭(由于 myMessageForm 中存在计时器)

这两种形式都是用 nil 所有者创建的,但它们以某种方式连接(我不知道为什么)。并且表格的销毁没有正确执行。下次调用 myForm.Create(nil) 或 myMessageForm.Create(nil) 时,会发生访问冲突。 myMessageForm 应该独立于 myForm 创建,并且它的销毁不应以任何方式限制 myForm 的销毁。

unit1;

procedure doCreateForm;
var
  myForm: TForm1;
begin
  myForm := TForm1.Create(nil)
  try
    with myForm do
      begin
        if <test condition true> then Show
        else
          begin
            ShowErrMessage('Error', 'Error message text', errType);
            Close;
          end;
      end;      
  except
    myForm.Free;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;



unit2;

procedure ShowErrMessage(title, text: string; err: mtErrType);
var
  myMessageForm: TMyMessageForm;
begin
  myMessageForm := TMyMessageForm.Create(nil)
  try
    with myMessageForm do
      begin
        StepDownCounter := 10;
        CloseTimer.Enable := True;
      end;
  except
    myMessageForm.Free;
  end;
end;

procedure TMyMessageForm.CloseTimerTimer(Sender: TObject);
begin
  StepDownCounter := StepDownCounter - 1;
  if (StepDownCounter < 1) then
    begin
      CloseTimer.Enabled := False;
      LabelStepDownText.Visible := False;
      Close;
    end
  else
    begin
      LabelStepDownText.Caption := 'Window will close in ' + IntToStr(StepDownCounter) + 's';
      LabelStepDownText.Visible := True;
    end;
end;

procedure TMyMessageForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

【问题讨论】:

  • 在您的OnClose 事件中使用Action := caFree; 来释放表单。如果您在其他活动中并想释放表单 it-Self,则需要使用 Release
  • 您正在从它自己的一种方法中释放表单。这与锯掉你站在树上的树枝完全一样。正如@TLama 所说,要么在你的FormClose 事件中使用Action := caFree,要么使用Release
  • 在此处发布问题之前,我在 CloseWindow 上使用了 Action := caFree 和 ASender.Release,但没有任何改变。发生相同的 AV。我不禁想知道为什么 AV 只在表单的第二次创建时引发,而不是第一次,不是第 3 次,不是第 4 次,依此类推......
  • 我按照大卫的建议编辑了这篇文章。不是它更详细地说明了问题。
  • SSCCE 是我可以粘贴到编辑器中、编译和运行的东西。制作一个需要你付出相当多的努力。如果你做了一个,那么你会立即得到答案。因为回答变得非常容易。更重要的是,您会得到问题的答案,因为我们实际上 100% 肯定地知道您的问题是什么。你的问题已经变异了。所以我的答案似乎过时了。谁知道你的真实代码是什么样的?你做。没有其他人这样做。 SSCCE 的强大之处在于它能够传达您的代码的真实情况。

标签: delphi dll


【解决方案1】:

您正在销毁正在执行当前方法的对象。该对象被销毁后执行的所有代码都是无效的。

您应该将关闭操作设置为caFree,或使用Release,如前所述。它们通过向队列发布消息以允许在当前方法返回后销毁对象来工作。您正在通过调用ProcessMessages 来颠覆这一点,这会抽出队列。删除对ProcessMessages 的调用。

【讨论】:

  • 我已经编辑了主要问题,所以它现在包含详细版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多