Search code examples
multithreadingdelphimessagedelphi-xe2hwnd

Custom Messages in Non-Windowed Classes - need a default handler?


With a class (TObject) I have :

private
  FHwnd : HWND;
  procedure HandleMyMessage(var Message : TMessage); message TH_MYMESSAGE;

where TH_MYMESSAGE = WM_USER + 1

In the class constructor:

FHwnd := AllocateHWND(HandleMyMessage);

The only object which receives a reference to FHwnd is a private custom TThread (created within this class) and the only message it posts is TH_MYMESSAGE. My understanding is that the message directive in the procedure declaration restricts its handling to only TH_MYMESSAGE.

This was working fine in testing, but upon integration into a much larger application I am getting feedback that HandleMyMessage is firing for other messages as well (with obvious undesired results).

This was easily corrected by adding if Message.Msg <> TH_MYMESSAGE then Exit; in HandleMyMessage. My question is : Why is this happening?

My best guess is that AllocateHWND has made HandleMyMessage the equivalent of a DefWndProc despite it having the message directive. Is there a correct way to implement this which I'm missing?


Solution

  • Well, yes of course. AllocateHWnd accepts a TWndMethod to act as the window procedure of the created window. The confusion, I guess, is caused by that the compiler accepts the messsage directive. Don't put it:

    private
      FHwnd : HWND;
      procedure HandleMyMessage(var Message : TMessage);
    
    ..
    
    procedure TMyClass.HandleMyMessage(var Message: TMessage);
    begin
      case Message.Msg of
        TH_MYMESSAGE: //
      end;
      Message.Result := DefWindowProc(FHWnd, Message.Msg, Message.WParam, Message.LParam);
    end;
    


    edit: (Response to comment). To have the message handled on the class that created the utility window, you can route your message from the window AllocateHWnd creates to your class:

    private
      FHwnd : HWND;
      procedure HandleMyMessage(var Message : TMessage);
      procedure THMyMessage(var Message: TMessage); message TH_MYMESSAGE;
    
    ..
    
    procedure TMyClass.HandleMyMessage(var Message: TMessage);
    begin
      case Message.Msg of
        TH_MYMESSAGE: Dispatch(Message);
      end;
      Message.Result := DefWindowProc(FHWnd, Message.Msg, Message.WParam, Message.LParam);
    end;
    
    procedure TMyClass.THMyMessage(var Message: TMessage);
    begin
      //
    end;