У меня был код, который работал нормально при запуске в контексте основного потока VCL. Этот код выделил свой собственный WndProc () для обработки вызовов SendMessage (). Сейчас я пытаюсь переместить его в фоновый поток, поскольку обеспокоен тем, что трафик SendMessage () отрицательно влияет на основной поток VCL. Поэтому я создал рабочий поток с единственной целью выделить WndProc () в его методе Execute () потока, чтобы гарантировать, что WndProc () существует в контексте выполнения потока. WndProc () обрабатывает вызовы SendMessage () по мере их поступления. Проблема в том, что метод WndProc () рабочего потока никогда не запускается.
Обратите внимание, doExecute () является частью шаблонного метода, который вызывается моим классом TThreadExtended, который является потомком Delphi TThread. TThreadExtended реализует потоковый метод 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 ========================
Спасибо,
Роберт