替代TControl.Perform [英] Alternative to 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屋!