Delphi - WndProc() in thread never called

Posted by Robert Oschler on Stack Overflow See other posts from Stack Overflow or by Robert Oschler
Published on 2010-04-10T21:20:06Z Indexed on 2010/04/10 21:23 UTC
Read the original article Hit count: 1045

Filed under:
|
|
|

I had code that worked fine when running in the context of the main VCL thread. This code allocated it's own WndProc() in order to handle SendMessage() calls. I am now trying to move it to a background thread because I am concerned that the SendMessage() traffic is affecting the main VCL thread adversely. So I created a worker thread with the sole purpose of allocating the WndProc() in its thread Execute() method to ensure that the WndProc() existed in the thread's execution context. The WndProc() handles the SendMessage() calls as they come in. The problem is that the worker thread's WndProc() method is never triggered.

Note, doExecute() is part of a template method that is called by my TThreadExtended class which is a descendant of Delphi's TThread. TThreadExtended implements the thread Execute() method and calls doExecute() in a loop. I triple-checked and doExecute() is being called repeatedly. Also note that I call PeekMessage() right after I create the WndProc() in order to make sure that Windows creates a message queue for the thread. However something I am doing is wrong since the WndProc() method is never triggered. Here's the code below:

// ========= 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 ========================

Thanks, Robert

© Stack Overflow or respective owner

Related posts about delphi

Related posts about wndproc