Delphi 如何检查Application.main表单是否有效?
如何确保在我的VCL应用程序生命周期的某个时刻,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
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