주 VCL 스레드의 컨텍스트에서 실행할 때 잘 작동하는 코드가 있습니다. 이 코드는 SendMessage() 호출을 처리하기 위해 자체 WndProc()을 할당했습니다. SendMessage() 트래픽이 주 VCL 스레드에 부정적인 영향을 미치기 때문에 백그라운드 스레드로 이동하려고합니다. 그래서 WndProc() 스레드의 Execute() 메서드에서 스레드의 실행 컨텍스트에서 WndProc() 보장하기 위해 할당 할 목적으로 작업자 스레드를 만들었습니다. WndProc() 들어오는 SendMessage() 호출을 처리합니다. 문제는 작업자 스레드의 WndProc() 메서드는 결코 트리거됩니다.Delphi - 스레드에서 WndProc()을 호출하지 않았습니다
참고 doExecute()는 Delphi의 TThread의 자손 인 TThreadExtended 클래스에서 호출하는 템플릿 메서드의 일부입니다. TThreadExtended는 스레드 Execute() 메서드를 구현하고 루프에서 doExecute()를 호출합니다. 나는 트리플 체크하고 doExecute()가 반복적으로 호출되고있다. 또한 Windows가 스레드의 메시지 대기열을 생성하는지 확인하기 위해 WndProc()을 생성 한 직후 PeekMessage()를 호출합니다. 그러나 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 ========================
덕분에, 로버트
감사합니다. mghie. 가상 키를 처리하지 않으므로 TranslateMessage() 호출이 필요합니까? 아니면 "좋은 습관"일까요? –
@ 로버트 : 필자는 그것이 필요하다고 생각하지 않지만, 그렇게 관용적이어서 코드 블록을 변경 한 적이 없다. 그러나 어떤 메시지를 보내거나 게시할지 여부를 결정하면 메시지를 남겨 두는 것이 안전해야합니다. 익숙한 코드의 경우에만 개인적으로 보관합니다. – mghie