Альтернатива TControl.Выполнять


Код 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, внутри другого потока, в том же приложении, без ожидания возврата?

EDIT

Такой подход мог бы смягчить проблему?

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 2

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. Окна созданные таким образом невосприимчивы к воссозданию и являются безопасными мишенями для PostMessage. Процедура окна для этого окна может затем переслать сообщение в вашу форму. И это безопасно, потому что процедура окна выполняется в потоке, связанном с его окном. В данном случае это поток GUI.

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