如何检查Application.MainForm是否有效?

时间:2015-06-25 15:41:03

标签: delphi delphi-7

我怎样才能确定在我的VCL应用程序生命周期的某些时刻Application.MainForm是有效的,所以我可以向它发布一条消息(来自MadExcept ExceptionHandler)。

这可能是我的应用程序中的任何点(在任何线程的上下文中)(也是initializationfinalization等...)

我在想:

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;

这是对的吗?

2 个答案:

答案 0 :(得分:3)

  

我怎么能确定在我的VCL应用程序生命周期的某些时候,Application.MainForm是有效的,所以我可以向它发布消息。

行。

  

这可能是我的应用程序中的任何点(在任何线程的上下文中)(也是初始化,终结等...)

哦,哦。

  

...

     

这是对的吗?

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

在您的特定情况下,请考虑以下事件序列:

  1. 您在if中执行测试,最终评估Application.MainForm.HandleAllocatedTrue。暂时忽略你在主线程之外这样做的事实。
  2. 然后,您开始准备调用PostMessage。但在这种情况下,主要形式被摧毁。
  3. 当你的线程开始访问Application.MainForm时,它已经消失了。
  4. 你需要在这里努力一点。你需要做这样的事情:

    // 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;
    

    你还需要创建和销毁关键部分,但我认为你知道如何做到这一点。

    在您的主要表单中,您可以覆盖CreateWndDestroyWnd,并安排他们致电RegisterMainFormHandleUnregisterMainFormHandle

    然后你可以随时从任何线程中调用PostMessageToMainForm

    当然,如果重新创建主窗体的窗口,那么您将丢失一些消息。这听起来像是一个问题。使用AllocateHwnd创建一个窗口,您可以控制其生命周期,这比使用主窗体的窗口更好。

答案 1 :(得分:0)

在开头创建一些全局变量标记= false

让你的主变形转为true

检查该标志以查看主表单是否已初始化。

您可以从主要形式的OnActivate事件或覆盖TMainForm.Loaded方法

等地方进行制作

同样,当你的应用程序终止并且主窗体被隐藏(后来甚至被破坏)时 - 你会将标志重置回false