Delphi 如何检查Application.main表单是否有效?

Delphi 如何检查Application.main表单是否有效?,delphi,delphi-7,Delphi,Delphi 7,如何确保在我的VCL应用程序生命周期的某个时刻,application.MainForm是有效的,这样我就可以向它发布消息(来自MadExceptionHandler) 这可能在我的应用程序中的任何点(在任何线程的上下文中)(也包括初始化,完成等…) 我在想: if Assigned(Application) and (not Application.Terminated) and Assigned(Application.MainForm) and Applicatio

如何确保在我的VCL应用程序生命周期的某个时刻,
application.MainForm
是有效的,这样我就可以向它发布消息(来自MadExceptionHandler)

这可能在我的应用程序中的任何点(在任何线程的上下文中)(也包括
初始化
完成
等…)

我在想:

if Assigned(Application)
    and (not Application.Terminated)
    and Assigned(Application.MainForm)
    and Application.MainForm.HandleAllocated then
  begin
    PostMessage(Application.MainForm.Handle, MyMessage, 0, 0);
  end;

这是否正确?

在开始时设置一些全局变量标志
=false

使主窗体将其设置为
true

检查该标志,查看主窗体是否已初始化

您可以从mainform的
OnActivate
事件或覆盖的
tmaninform.Loaded
方法等位置进行设置

类似地,当您的应用程序将终止并且主窗体将被隐藏(后来甚至被销毁)时,您可以将标志重置回
false

如何确保在VCL应用程序生命周期的某个时刻,application.MainForm是有效的,以便我可以向其发布消息

这可能是在我的应用程序中的任何点(在任何线程的上下文中)(还有初始化、终结等…)

这是正确的吗

不,当然不是。您的代码永远不能成为线程安全的,因为不允许从主线程外部访问VCL对象

在你的具体案例中,考虑以下事件:

  • if
    中执行测试,最终评估
    Application.MainForm.HandleAllocated
    True
    。暂时忽略这样一个事实,即您在主线程之外执行此操作
  • 然后开始准备对
    PostMessage
    的调用。但就在这种情况下,主要形式被破坏了
  • 当线程开始访问
    Application.MainForm
    时,它已经消失了
  • 你需要在这里更努力一点。您需要执行以下操作:

    // interface section of some unit
    
    procedure RegisterMainFormHandle(Wnd: HWND);
    procedure UnregisterMainFormHandle;
    procedure PostMessageToMainForm(...);
    
    // implementation section 
    
    var
      MainFormHandleLock: TCriticalSection;
      MainFormHandle: HWND;
    
    procedure RegisterMainFormHandle(Wnd: HWND);
    begin
      MainFormHandleLock.Acquire;
      try
        MainFormHandle := Wnd;
      finally
        MainFormHandleLock.Release;
      end;
    end;
    
    procedure UnregisterMainFormHandle;
    begin
      MainFormHandleLock.Acquire;
      try
        MainFormHandle := 0;
      finally
        MainFormHandleLock.Release;
      end;
    end;
    
    procedure PostMessageToMainForm(...);
    begin
      MainFormHandleLock.Acquire;
      try
        if MainFormHandle <> 0 then
          PostMessage(MainFormHandle, ...)
      finally
        MainFormHandleLock.Release;
      end;
    end;
    
    //某个单元的接口部分
    程序注册信息处理(Wnd:HWND);
    程序取消注册;主窗体句柄;
    程序后消息通知(…);
    //执行科
    变量
    MainFormHandleLock:TCriticalSection;
    MainFormHandle:HWND;
    程序注册信息处理(Wnd:HWND);
    开始
    MainFormHandleLock.Acquire;
    尝试
    MainFormHandle:=Wnd;
    最后
    MainFormHandleLock.释放;
    结束;
    结束;
    程序取消注册;主窗体句柄;
    开始
    MainFormHandleLock.Acquire;
    尝试
    MainFormHandle:=0;
    最后
    MainFormHandleLock.释放;
    结束;
    结束;
    程序后消息通知(…);
    开始
    MainFormHandleLock.Acquire;
    尝试
    如果MainFormHandle为0,则
    PostMessage(MainFormHandle,…)
    最后
    MainFormHandleLock.释放;
    结束;
    结束;
    
    您还需要创建和销毁关键部分,但我假设您知道如何创建和销毁关键部分

    在主窗体中,重写
    CreateWnd
    destrownd
    ,并安排它们调用
    registerInformHandle
    UnregisterMainFormHandle

    然后,您可以随时从任何线程调用
    PostMessageToMainForm


    当然,如果重新创建主窗体的窗口,则会丢失一些消息。这听起来可能是个问题。使用
    AllocateHwnd
    来拥有一个您可以控制其生存期的窗口,通常比像这样使用主窗体的窗口更好

    有时,对于具有初始屏幕的应用程序,创建一个主窗体,然后销毁,然后创建另一个主窗体。因此,即使
    Application.MainForm.HandleAllocated
    它仍然可能出错(被发布到启动屏幕而不是真正的主窗口)@Arioch'只有在应用程序设计错误的情况下才是如此。启动屏幕不是主要形式。只能调用
    Application.CreateForm
    一次。如果
    MainFormHandleLock
    在我调用
    PostMessageToMainForm
    的那一刻已被释放,该怎么办?你认为我什么时候需要创建/释放(和nil)它?你必须先清理你的线程,然后才能完成这个单元,它的完成会破坏锁。换句话说,请确保您描述的场景不会发生。我记得在D5/D7中,首先创建的任何表单都被设置为主表单,包括
    TForm1。创建(应用程序)
    -在创建主表单之前显示的初始屏幕被临时视为主表单。它没有导致过早终止,因为这一切都发生在
    应用程序之前。运行
    如果没有同步,则无法执行此操作。测试完标志后,如何阻止主线从下方拉出地毯?好吧,您可以使用变量0-or-HWND而不是布尔值,这样可以减少一些延迟。无论如何,完美的同步都是不可能的,因为您使用的是PostMessage not SendMessage,并且在消息排队时可以拉入rug。后一个选项应该考虑重新创建的WND…这不是一个好的设计,特别是当您需要考虑线程时。您应该使用
    AllocateHWnd()
    来创建自己的专用HWND,您可以将邮件发送到该HWND。不要将它们发布到
    MainForm
    窗口。您也可以检查其他属性,但这仍然不能保证。例如,csDestroying的ComponentState