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

1

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?

Disorder answered 6/6, 2012 at 12:10 Comment(3)
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)Strand
@Strand 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?Disorder
@Ken No problem with WM_USER here.Straitlaced
P
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;
Philistine answered 6/6, 2012 at 12:36 Comment(10)
Does AllocateHwnd create a window that receives broadcasts? For something like this I'd be looking for a message only window, HWND_MESSAGE.Straitlaced
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?Disorder
@David - Sure, but using AllocateHWnd is so much easier. My system is full of 'TPUtilWindow's at any given time.Philistine
TObject.DefaultHandler will do the routing I guess but it's overkill unless you have a lot of messages.Straitlaced
No, I remembered wrong, Dispatch does the routing. @Sertac Why not call Dispatch always? Why the case? Pick up unhandled messages in DefaultHandler.Straitlaced
@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.Philistine
Hmm, if this class encapsulates a single window, then I can't see any objection to calling Dispatch for all messages.Straitlaced
@David - Yes. I was thinking of wincontrols as an objection reason.Philistine
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.Declare
@user - Give it a shot posting a new question providing code sample that duplicates your problem.Philistine

© 2022 - 2024 — McMap. All rights reserved.