EPr*_*und 2 windows delphi vcl message-queue
该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;
Run Code Online (Sandbox Code Playgroud)
程序执行等待返回,我是对的吗?
有一种替代方法,用于在同一个应用程序中的另一个线程内的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;
Run Code Online (Sandbox Code Playgroud)
并且通常在线程内使用:
PostMessage(MyHandle, WM_DOSTUFF, 0, 0);
Run Code Online (Sandbox Code Playgroud)
要将消息添加到与另一个窗口关联的线程的队列,您需要使用PostMessageWindows API函数.
PostMessage(WindowHandle, Msg, WParam, LParam);
Run Code Online (Sandbox Code Playgroud)
现在,如果您在与GUI线程不同的线程上执行此操作,则无法使用Form.Handle获取窗口句柄.那是因为这样做引入了GUI线程的竞赛.如果需要重新创建句柄,它将与您的线程而不是GUI线程创建关联.记住规则:只与GUI线程中的VCL对象进行交互.
因此,您通常不使用PostMessageVCL表单的句柄,因为您无法轻松保证将消息传递到正确的窗口.即使您同步访问窗口句柄,也可以重新创建窗口,并且您的消息不会到达.
异步传递消息的最简单方法是调用TThread.Queue.这不需要窗口句柄来操作,因此避免了与GUI线程的VCL对象关联的所有问题.调用时发送的过程Queue在GUI线程上执行,因此可以安全地执行所有VCL操作.
如果您使用的是较旧的Delphi,TThread.Queue那么它会更复杂.你应该在那种情况下使用PostMessage.但是您必须将消息定向到与表单无关的窗口.将它指向一个用它创建的窗口AllocateHWnd.请记住,您必须调用AllocateHWndGUI线程.以这种方式创建的Windows不受重新创建的影响,是安全的目标PostMessage.然后,该窗口的窗口过程可以将消息转发到您的表单.这是安全的,因为窗口过程在与其窗口关联的线程中执行.在这种情况下,这是GUI线程.
顺便说一句,如果你要TControl.Perform远离GUI线程,那也是错误的.期望间歇性且难以诊断故障.