2

the TControl.Perform code is:

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?

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

EDIT

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;

And use normally inside a thread:

  PostMessage(MyHandle, WM_DOSTUFF, 0, 0);   
4

1 回答 1

5

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

PostMessage(WindowHandle, Msg, WParam, LParam);

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

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

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

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

顺便说一句,如果您TControl.Perform从 GUI 线程调用,那么这也是错误的。预计会出现间歇性且难以诊断的故障。

于 2013-04-18T18:30:01.787 回答