Альтернатива 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;

Выполнение программы ожидает возврата, я прав?

Есть ли альтернатива для размещения сообщения в очереди 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);   

1 ответ

Решение

Чтобы добавить сообщение в очередь потока, связанного с другим окном, необходимо использовать PostMessage Функция Windows API.

PostMessage(WindowHandle, Msg, WParam, LParam);

Теперь, если вы делаете это в другом потоке из потока GUI, то вы не можете использовать Form.Handle получить ручку окна. Это потому, что это приводит к гонке с потоком GUI. И если дескриптор необходимо воссоздать, он будет создан с привязкой к вашему потоку, а не к потоку GUI. Запомните правила: взаимодействуйте только с объектами VCL из потока GUI.

Так вы обычно не используете PostMessage с дескриптором формы VCL, потому что вы не можете легко гарантировать, что сообщение будет доставлено в правильное окно. Даже если вы синхронизируете доступ к дескриптору окна, окно может быть воссоздано, и ваше сообщение не будет доставлено.

Самый простой способ доставить сообщения асинхронно - это вызвать TThread.Queue, Это не требует дескриптора окна для работы и, таким образом, позволяет избежать всех проблем с привязкой объекта VCL к потоку GUI. Процедура, которую вы отправляете при звонке Queue выполняется в потоке GUI и поэтому безопасно выполнять все операции VCL.

Если вы используете более раннюю версию Delphi, TThread.Queue тогда это сложнее. Вы должны в этом случае использовать PostMessage, Но вам придется направить сообщение в окно, не связанное с формой. Направьте его в окно, созданное с помощью AllocateHWnd, Помните, что вы должны позвонить AllocateHWnd в потоке GUI. Windows, созданные таким образом, защищены от повторного создания и являются безопасными объектами для PostMessage, Оконная процедура для этого окна может затем переслать сообщение в вашу форму. И это безопасно, потому что оконная процедура выполняется в потоке, связанном с его окном. В этом случае это поток GUI.

Как в сторону, если вы звоните TControl.Perform далеко от потока GUI, то это тоже неправильно. Ожидайте прерывистый и трудно диагностировать сбои.

Другие вопросы по тегам