替代TControl.Perform [英] Alternative to TControl.Perform

查看:96
本文介绍了替代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;

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

The program execution awaits return, am i right?

还有另一种选择,可以将消息发布到同一应用程序中另一个线程内的TFORM队列中的消息中,而无需等待返回?

There is an alternative, for posting a message in a TFORM queue, inside another thread, in the same Application, without waiting return?

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

This approach could mitigate the problem?

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

推荐答案

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

To add a message to the queue of the thread associated with another window, you need to use the PostMessage Windows API function.

PostMessage(WindowHandle, Msg, WParam, LParam);

现在,如果要在与GUI线程不同的线程上执行此操作,则不能使用Form.Handle获取窗口句柄.那是因为这样做引入了与GUI线程的竞争.而且,如果需要重新创建句柄,将以与您的线程(而不是GUI线程)的关联性创建它.记住规则:仅与GUI线程中的VCL对象进行交互.

Now, if you are doing this on a different thread from the GUI thread, then you cannot use Form.Handle to obtain the window handle. That's because doing so introduces a race with the GUI thread. And if the handle needs to be re-created, it will be created with affinity to your thread rather than the GUI thread. Remember the rules: only interact with VCL objects from the GUI thread.

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

So you typically do not use PostMessage with the handle of a VCL form because you cannot easily guarantee that the message will be delivered to the correct window. Even if you synchronize access to the window handle, the window can be re-created and your message will not arrive.

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

The simplest way to deliver messages asynchronously is to call TThread.Queue. This does not need a window handle to operate and so avoids all the issues with VCL object affinity to the GUI thread. The procedure that you send when you call Queue executes on the GUI thread and so is safe to perform all VCL operations.

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

If you are on an older Delphi that pre-dates TThread.Queue then it is more complicated. You should in that case use PostMessage. But you'll have to direct the message to a window not associated with a form. Direct it to a window created with AllocateHWnd. Remember that you must call AllocateHWnd on the GUI thread. Windows created this way are immune from re-creation and are safe targets for PostMessage. The window procedure for that window can then forward the message on to your form. And that is safe because the window procedure executes in the thread associated with its window. In this case that is the GUI thread.

顺便说一句,如果您在GUI线程之外调用TControl.Perform,那也是错误的.期望断断续续,难以诊断故障.

As an aside, if you are calling TControl.Perform away from the GUI thread, then that is also wrong. Expect intermittent and hard to diagnose failures.

这篇关于替代TControl.Perform的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆