17

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?

gabr
  • 26,580
  • 9
  • 75
  • 141
J...
  • 30,968
  • 6
  • 66
  • 143
  • 4
    your guess is correct `HandleMyMessage` becomes `WndProc` of created non-visual window. so it recieves all messages; your solution to filter `Message.Msg` is correct too. `message` method modificator us used by Delphi for default handling `TObject.Dispatch` calls (in non-windowed classes) – teran Jun 06 '12 at 12:24
  • @teran Assuming, then, that I did want a default `WndProc` for other messages would `HandleMyMessage` filter properly with the `message` directive if I had done `AllocateHWND` on some other general procedure? – J... Jun 06 '12 at 12:27
  • 1
    @Ken No problem with WM_USER here. – David Heffernan Jun 06 '12 at 12:50

1 Answers1

13

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;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • 1
    Does AllocateHwnd create a window that receives broadcasts? For something like this I'd be looking for a message only window, HWND_MESSAGE. – David Heffernan Jun 06 '12 at 12:42
  • 1
    This makes sense. The second part of the question : could, in the same class, another procedure be defined which did use the `message` directive to steer specific messages away from the main handler? – J... Jun 06 '12 at 12:44
  • 1
    @David - Sure, but using AllocateHWnd is so much easier. My system is full of 'TPUtilWindow's at any given time. – Sertac Akyuz Jun 06 '12 at 12:46
  • 1
    TObject.DefaultHandler will do the routing I guess but it's overkill unless you have a lot of messages. – David Heffernan Jun 06 '12 at 12:51
  • 1
    No, I remembered wrong, Dispatch does the routing. @Sertac Why not call Dispatch always? Why the case? Pick up unhandled messages in DefaultHandler. – David Heffernan Jun 06 '12 at 12:59
  • 1
    @David - Now I think understand your question. No, we're in the window procedure of the utility window, as far as the OS is concerned it is where messages that should be handled by *that window* is delivered. When we call 'Dispatch' we are calling a message handler of an entirely different class which may have a window of its own. – Sertac Akyuz Jun 06 '12 at 13:28
  • 1
    Hmm, if this class encapsulates a single window, then I can't see any objection to calling Dispatch for all messages. – David Heffernan Jun 06 '12 at 13:48
  • 1
    @David - Yes. I was thinking of wincontrols as an objection reason. – Sertac Akyuz Jun 06 '12 at 13:53
  • Hey, just a question, why does my WndProc (of a class) isn't working when i call AllocateHWnd from the Constrctor or AfterConstrction ? if i create it from a seperate method it works. –  Apr 13 '13 at 14:39
  • @user - Give it a shot posting a new question providing code sample that duplicates your problem. – Sertac Akyuz Apr 13 '13 at 22:48