替代TControl.Perform

TControl.Perform代码是:

 var Message: TMessage; begin Message.Msg := Msg; Message.WParam := WParam; Message.LParam := LParam; Message.Result := 0; if Self <> nil then WindowProc(Message); Result := Message.Result; 

程序执行正在等待返回,对吗?

还有一种替代方法,可以在同一个应用程序中的另一个线程中,在TFORM队列中发布消息,而不用等待返回?

编辑

这种方法可以缓解这个问题?

 interface const WM_DOSTUFF = WM_APP + $001; TMyForm = class(TForm) {stuff} public {Other stuff} procedure DoMyStuff(var Msg: TMessage); message WM_DOSTUFF; {More stuff} end; var MyHandle: HWND; implementation constructor TMyForm.Create(AOwner: TComponent); begin inherited; MyHandle := AllocateHWnd(DoMyStuff); end; destructor TMyForm.Destroy; begin DeallocateHWnd(MyHandle); inherited; end; 

并且在一个线程内正常使用:

  PostMessage(MyHandle, WM_DOSTUFF, 0, 0); 

要将消息添加到与另一个窗口关联的线程的队列中,您需要使用PostMessage Windows API函数。

 PostMessage(WindowHandle, Msg, WParam, LParam); 

现在,如果你是在GUI线程的不同线程上执行此操作,则不能使用Form.Handle来获取窗口句柄。 这是因为这样做会引入与GUI线程的比赛。 如果需要重新创建句柄,它将与您的线程相关而不是GUI线程创建。 记住规则:只从GUI线程与VCL对象交互。

因此,您通常不使用PostMessage与VCL表单的句柄,因为您不能轻易保证邮件将被传递到正确的窗口。 即使您同步对窗口句柄的访问,窗口也可以重新创建,并且您的消息不会到达。

异步传递消息最简单的方法是调用TThread.Queue 。 这不需要窗口句柄来操作,因此避免了与GUI线程的VCL对象关联的所有问题。 在调用Queue时发送的过程在GUI线程上执行,因此可以安全地执行所有VCL操作。

如果你使用的是比TThread.Queue更早的Delphi,那么它会更复杂。 你应该在这种情况下使用PostMessage 。 但是您必须将消息引导至与表单无关的窗口。 将其指向使用AllocateHWnd创建的窗口。 请记住,您必须在GUI线程上调用AllocateHWnd 。 以这种方式创建的Windows不受重新创建的影响,并且是PostMessage安全目标。 该窗口的窗口过程可以将消息转发到您的窗体上。 这是安全的,因为窗口过程在与其窗口关联的线程中执行。 在这种情况下,这是GUI线程。

另外,如果你正在调用TControl.Perform远离GUI线程,那么这也是错误的。 期望间歇性且难以诊断故障。