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);
答案 0 :(得分:5)
要将消息添加到与另一个窗口关联的线程的队列,您需要使用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线程。
顺便说一句,如果你从GUI线程调用TControl.Perform
,那也是错误的。期望间歇性且难以诊断故障。