Delphi XE4 - 表格在DLL中动态创建AV结果

时间:2014-04-01 16:01:50

标签: delphi dll

我有一个在我的主应用程序中加载的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. 如果出现问题:

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

    B)。我叫myForm.Close。这个表单还有一个动作:= onClose事件中的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;
    

1 个答案:

答案 0 :(得分:1)

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

您应该将关闭操作设置为caFree,或使用Release,如上所述。这些工作通过向队列发布消息以允许在当前方法返回后销毁对象。你正在通过调用ProcessMessages调用队列来破坏它。移除对ProcessMessages的呼叫。