Вопрос

У меня был код, который работал нормально при запуске в контексте основной резьбы VCL. Этот код выделил свой WNDProc () для обработки вызовов SendMessage (). Сейчас я пытаюсь переместить его в фоновую нить, потому что я обеспокоен тем, что трафик SendMessage () отрицательно влияет на основной резьб VCL. Поэтому я создал рабочую нить с единственной целью выделения WNDProc () в своем методе execute () для обеспечения того, чтобы WNDProc () существует в контексте выполнения потока. WNDPROC () обрабатывает вызовы SendMessage (), когда они вошли. Проблема в том, что метод WHEPROC WHEPPROC () рабочего нити никогда не срабатывает.

Примечание, Doexecute () является частью метода шаблона, который называется моим TthreadextExtended классом, который является потомком TTHEAD DELPHI. TTHREADEXTESTEDENDALTELETELETION EXECUTE () метод Execute () и вызывает Doexecute () в цикле. Я тройной проверен и doexecute () называется неоднократно называться. Также обратите внимание, что я звоню Peekmessage () сразу после того, как я создаю WNDProc (), чтобы убедиться, что Windows создает очередь сообщений для потока. Однако что-то я делаю, неправильно, поскольку метод WNDPROC () никогда не запускается. Вот код ниже:

// ========= BEGIN: CLASS - TWorkerThread ========================

constructor TWorkerThread.Create;
begin
    FWndProcHandle := 0;

    inherited Create(false);
end;

// ---------------------------------------------------------------

// This call is the thread's Execute() method.
procedure TWorkerThread.doExecute;
var
    Msg: TMsg;
begin
    // Create the WndProc() in our thread's context.
    if FWndProcHandle = 0 then
    begin
        FWndProcHandle := AllocateHWND(WndProc);

        // Call PeekMessage() to make sure we have a window queue.
        PeekMessage(Msg, FWndProcHandle, 0, 0, PM_NOREMOVE);
    end;

    if Self.Terminated then
    begin
        // Get rid of the WndProc().
        myDeallocateHWnd(FWndProcHandle);
    end;

    // Sleep a bit to avoid hogging the CPU.
    Sleep(5);
end;

// ---------------------------------------------------------------

procedure TWorkerThread.WndProc(Var Msg: TMessage);
begin
    // THIS CODE IS NEVER CALLED.
    try
        if Msg.Msg = WM_COPYDATA then
        begin
            // Is LParam assigned?
            if (Msg.LParam > 0) then
            begin
                // Yes.  Treat it as a copy data structure.
                with PCopyDataStruct(Msg.LParam)^ do
                begin
      ... // Here is where I do my work.
                end;
            end; // if Assigned(Msg.LParam) then
        end; // if Msg.Msg = WM_COPYDATA then
    finally
        Msg.Result := 1;
    end; // try()
end;

// ---------------------------------------------------------------

procedure TWorkerThread.myDeallocateHWnd(Wnd: HWND);
var
    Instance: Pointer;
begin
    Instance := Pointer(GetWindowLong(Wnd, GWL_WNDPROC));

    if Instance <> @DefWindowProc then
    begin
        // Restore the default windows procedure before freeing memory.
        SetWindowLong(Wnd, GWL_WNDPROC, Longint(@DefWindowProc));
        FreeObjectInstance(Instance);
    end;

    DestroyWindow(Wnd);
end;

// ---------------------------------------------------------------


// ========= END  : CLASS - TWorkerThread ========================

Спасибо, Роберт

Это было полезно?

Решение

Проблема в том, что вы создаете окно для получения сообщений, но у вас нет стандартной циклы сообщений, чтобы фактически извлечь сообщения из очереди сообщений, и пусть целевое окно обрабатывает их. То, что вам нужно, это эквивалент Application Loop сообщений, который в его форме API выглядит:

while integer(GetMessage(Msg, HWND(0), 0, 0)) > 0 do begin
  TranslateMessage(Msg);
  DispatchMessage(Msg);
end;

Это (или что-то подобное) в коде потока потребуется.

Обратите внимание, что вам на самом деле не нужна окно вспомогательного ввода в вашу рабочую нить, так как нить может иметь сама очередь сообщений, какие сообщения могут быть включены в очередь, вызывая PostThreadMessage(). Отказ Это эквивалент стандарта PostMessage() Функциональный вызов. Оба не будут ждать обработки сообщения, но возвращайте немедленно. Если это не будет работать для вас, то вы действительно должны создать окно в вашей теме и позвонить SendMessage() для этого. Петля сообщения, однако, будет необходимо во всех случаях.

С GetMessage() это блокирующий звонок, который вы также не должны бояться «ввода ЦП», поэтому Sleep() Звонки не нужны.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top