在主 VCL 线程的上下文中运行时,我的代码运行良好。该代码分配了它自己的 WndProc() 以处理 SendMessage() 调用。我现在正试图将其移至后台线程,因为我担心 SendMessage() 流量会对 VCL 主线程产生不利影响。因此,我创建了一个工作线程,其唯一目的是在其线程 Execute() 方法中分配 WndProc(),以确保 WndProc() 存在于线程的执行上下文中。WndProc() 处理传入的 SendMessage() 调用。问题是工作线程的 WndProc() 方法永远不会被触发。
请注意,doExecute() 是模板方法的一部分,由我的 TThreadExtended 类调用,该类是 Delphi 的 TThread 的后代。TThreadExtended 实现了线程 Execute() 方法并在循环中调用 doExecute()。我进行了三次检查,并且重复调用了 doExecute()。另请注意,我在创建 WndProc() 后立即调用 PeekMessage() 以确保 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 ========================
谢谢,罗伯特