Any way to use:
procedure WMStuff(var Message: TMessage); message WM_Stuff;
when WM_Stuff
is a variable?
Delphi has an absolutely lovely bit of compiler magic to make handling messages so easy. You simply tag your procedure with the message WM_TheMessage
keyword:
procedure WMGrobFrobber(var Message: TMessage); message WM_GrobFrobber;
and your procedure will be called to handle that message. No subclassing. No replacing, storing, and calling base window procedures. Just easy simple magic.
The message works great when the WM_GrobFrobber
is a const
:
const
WM_GrobFrobber = WM_APP + $12A9; //hopefully nobody's used this message before
But the downside of a constant declared like that is:
Windows recommends you use RegisterWindowMessage to ensure you safely have a unique message number:
Defines a new window message that is guaranteed to be unique throughout the system. The message value can be used when sending or posting messages.
The RegisterWindowMessage function is typically used to register messages for communicating between two cooperating applications.
If two different applications register the same message string, the applications return the same message value. The message remains registered until the session ends.
Only use RegisterWindowMessage when more than one application must process the same message. For sending private messages within a window class, an application can use any integer in the range WM_USER through 0x7FFF. (Messages in this range are private to a window class, not to an application. For example, predefined control classes such as BUTTON, EDIT, LISTBOX, and COMBOBOX may use values in this range.)
And that is what i need:
TForm1
vs TForm2
vs TVirtualTreeHintWorkerThread
)So i register my message:
var
WM_GrobFrobber: Cardinal;
initialization
WM_GrobFrobber := RegisterWindowMessage('Contoso.Grobber.GrobFrobber message');
But now i can no longer use the nice syntax:
procedure WMGrobFrobber(var Message: TMessage); message WM_GrobFrobber;
//Constant expression expected
:(
I tried hacking an assignable type constant:
{$J+}
const
WM_GrobFrobber: Cardinal = 0;
initialization
WM_GrobFrobber := RegisterWindowMessage('Contoso.Grobber.GrobFrobber message');
But the message
keyword does not accept *pseudo-*constants either:
procedure WMGrobFrobber(var Message: TMessage); message WM_GrobFrobber;
//Constant expression expected
Is there any way to salvage the lovely, easy message
syntax, and not have to subclass every window that might want to handle a message?
Especially since the message really isn't a constant; but is invented and registered by people who are not me.
As David states in his answer, message ID's in declarative message handlers are required to be constant expressions, so there is no way to implement a handler for a variable message number in this way.
However, you still do not need to sub-class every window to be able to respond to such messages. Or rather, you do not need to perform any further sub-classing than you are already doing by declaring a form or control class.
You can handle your custom, registered message by over-riding the virtual WndProc
method. You won't be able to use a select .. case
statement to handle the message since this similarly requires constant expressions for the matching cases, but you can use a simple if .. then
statement to catch your message, calling inherited
for everything else:
procedure TMyForm.WndProc(var aMessage: TMessage);
begin
if aMessage.Msg = WM_GrobFrobber then
begin
{ Handle the message or pass to a WMGrobFrabber() method
with suitably repacked and typed params, as required/desired }
end
else
inherited WndProc(aMessage);
end;
You could introduce a virtual
WMGrobFrabber
in a form class which you then use consistently as the base class for all forms in your application(s), so that you can simply override that method to handle this message, rather than having to regurgitate the WndProc
conditional handler code every time.
This doesn't solve all your problems. It doesn't provide a way to use the declarative message handler syntax, but it is still quite elegant (imho).
If such messages are used exclusively for responding to broadcast messages (which I believe is the only circumstance in which you need be concerned about message id's conflicting with those used by others) then you could create a non-visual component that implements a message handler specifically to respond to this message by firing an event with a published event handler. Then you don't need to sub-class at all to implement a response to such broadcasts on a form, just drop a handler component on the form and implement a handler for the component's event.
That is obviously more complicated than would be appropriate to deal with in an answer to this question, but might be worth considering.
The message ID associated with a message method must be a constant expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With