Re: Detect button presses by intercepting WM_COMMAND by Stoitcho
Stoitcho
Mon Feb 27 08:51:52 CST 2006
leightonr,
WindowsForms control classes use native windows internally for visualizing
the UI. The Handle property that the control class exposes is the
connection between the native window and the .NET control.
Native windows controls' event system as well as the whole communication
with them is based on sending and receiving windows messages; most of them
starts WM_*. For each native control there is a stucture called WNDCLASS
which describes the common properties and functionality of all native
controls created using the class. One of the characteristics of the class is
the window procedure (winproc) that will handle the windows messages send to
all the windows in this class. The classes have name. There are predefined
classes for native windows for some of the control. One such class is the
BUTTON class. Its winproc is written in a way that it notifies its parent
with WM_COMMAND and BN_CLICKED when the button is considered to be clicked
on. In other words if one creates a native control (see CreateWindow and
CreateWindowEx API calls ) using BUTTON as the name of the class, then this
window will draw itself as a button and behaves as a button. (BTW push
buttons are only one kind of buttons that windows of this class can
represent)
This is all related to native windows and windows API. If WindowsForms
wasn't based on native windows any of this will be valid in the context of
.NET.
The best is to forget about all the native windows stuff when programming
for .NET. All this WndProc and WM_* and alike shouldn't be used. However
apparently this is not possible.
Why System.Windows.Forms.Button class doesn't send this message? Because it
doens't create native window of class BUTTON (this is the WNDCLASS, not the
.NET class) that on the other hand means it doesn't uses native BUTTON
winproc that actually sends this WM_COMMAND. Keep in mind that .NET doesn't
need this windows messages in order to work. It uses them only to make the
link between native windows and the .NET classes. When they provide new
winproc for the button for example they don't need to send this WM_COMMAND
and BN_CLICKED because all the event system used by WindowsForms framework
is implemented in different way (not usinng windows messages).
WM_PARENTNOTIFY is a common message for all windows regardless of their
class (it is send by one winproc called default windows procedure
(DefWindowProc) that's why it still works with .NET buttons.
--
HTH
Stoitcho Goutsev (100)
"leightonr" <leightonr@discussions.microsoft.com> wrote in message
news:6926D83D-5AC5-432C-89D4-24F25A75D5D4@microsoft.com...
> Thanks Stoitcho - capturing WM_PARENTNOTIFY appears to work ok. But I
> don't
> understand the explanation of why my button on the from which is of type
> Windows.Forms.Button does not cause the BN_CLICKED notification code to go
> to
> the parent through the WM_COMMAND message. Could you elaborate on your
> explanation please.
>
> "Stoitcho Goutsev (100)" wrote:
>
>> Oh, you are right. The WindowsForms button doesn't send WM_COMMAND as
>> native
>> buttons does because it is not a native button. This is not a window
>> create
>> using BUTTON WNDCLASS. This is internal implementation and it simply
>> doesn't
>> send this message. However using SPY++ you can see that it sends
>> WM_PARENTNOTIFY; try to use this.
>>
>>
>> --
>>
>> Stoitcho Goutsev (100)
>>
>> "leightonr" <leightonr@discussions.microsoft.com> wrote in message
>> news:C978B263-E177-4790-BAFE-4D8FF0E34862@microsoft.com...
>> > Thanks. that is exactly what I am doing. My form has one control,
>> > which
>> > is a Windoes.Forms.Button. In my form I override WndProc as follows :-
>> > protected override void WndProc(ref Message m)
>> >
>> > and in WndProc I check for a message of type WM_COMMAND. I expected
>> > that
>> > when I clicked the button my form would get a WM_COMMAND message, but
>> > it
>> > doesn't ?
>> >
>> > "Stoitcho Goutsev (100)" wrote:
>> >
>> >> Message filter will work only for messages that comes through the
>> >> thread
>> >> message queue. When child window sends message to its parent because
>> >> they
>> >> are created by the same thread the parents wndproc is called directly
>> >> and
>> >> doesn't go through the message queue.
>> >>
>> >> Buttons send WM_COMMAND to their parent. If you want to intersept them
>> >> you
>> >> need to override their WndProc. If button is placed on a panel you
>> >> need
>> >> to
>> >> derive the panel and override its WndProc. There is no way you can
>> >> intersept
>> >> WM_COMMAND from all the buttons unless you don't use panels or any
>> >> other
>> >> containers and place all the buttons in the same parent.
>> >>
>> >>
>> >> --
>> >> HTH
>> >> Stoitcho Goutsev (100)
>> >>
>> >>
>> >> "leightonr" <leightonr@discussions.microsoft.com> wrote in message
>> >> news:7D4A17BC-9B2A-4952-8141-DFA57EA412A5@microsoft.com...
>> >> >I want to insert a 'general' message filter into a .NET application
>> >> >that
>> >> >will
>> >> > intercept button presses. IMessageFilter cannot be used because it
>> >> > only
>> >> > intercepts posted messages. So I override WndProc and filter on
>> >> > WM_COMMAND
>> >> > messages to detect button presses in the application. However the
>> >> > button
>> >> > presses are not being detected in my app. I have modified the app
>> >> > to
>> >> > have
>> >> > just one button on it and used spy++ to see what messages the button
>> >> > press
>> >> > generates. But nothing ! Any ideas ?
>> >>
>> >>
>> >>
>>
>>
>>