Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

Joel B. dropped some interesting questions for me on an very old post of mine People are confused by ApplicationContext in Windows Forms, but there really isn't any magic happening.  It seems people are also confused about the entire message pump and what it is capable of.  He asks some common questions about the pump that can be answered by delving into Win32, but he brings to light some additional questions that have their roots in the way WinForms extends the messag pump for your usage.  We'll be getting ourselves into two different hooks.  The first hook is a message filter added through the Application class.  The second hook, and the more useful hook, is going to be added by overriding Control.PreProcessMessage.

Starting with IMessageFilter you have to realize what you can do.  You can listen to events and do something, but not consume the event.  This is interesting, since you can implement all forms of debugging filters and figure out where those events are going and maybe why your application is behaving the way it is.  I often use a message filter to find out if my messages are out of order or to discover undocument things like how focus changes within my application.

You can also listen to events and consume them.  If you consume an event it doesn't continue up to the control it is destined for.  If you wanted to easily disable your form without doing a bunch of work, you could trap all messages for a while and simply throw them out.  If you wanted to limit input to only a specific control you could filter on it's handle.  Here is a small application that has a button click handler and a form handler.  I add and remove a message filter to disable the button control by limiting messages to only the form's handle.  Not very neat, but something to demonstrate what you can do.

using System;
using System.Windows.Forms;

public class OnlyAllow : IMessageFilter {
    private IntPtr redirectHandle = IntPtr.Zero;
   
    public OnlyAllow(IntPtr redirectHandle) {
        this.redirectHandle = redirectHandle;
    }
   
    public bool PreFilterMessage(ref Message m) {
        Console.WriteLine("Pre Filter is being called");
        if ( this.redirectHandle == m.HWnd ) {
            return false;
        }
       
        return true;
    }
}

public class MainForm : Form {
    private OnlyAllow oa = null;
    private Button b = new Button();
   
    public MainForm() {
        b.Click += new EventHandler(Button_Click);
        this.Controls.Add(b);
       
        this.Click += new EventHandler(Form_Click);
    }
   
    private void Button_Click(object sender, EventArgs e) {
        Console.WriteLine("Button Clicked");
        if ( oa == null ) {
            oa = new OnlyAllow(this.Handle);
        }
        Application.AddMessageFilter(oa);
    }
   
    private void Form_Click(object sender, EventArgs e) {
        Console.WriteLine("Form Clicked");
        if ( oa != null ) {
            Application.RemoveMessageFilter(oa);
        }
    }
   
    private static void Main(string[] args) {
        Application.Run(new MainForm());
    }
}

It is often misunderstood the filters are more powerful than they really are.  They aren't.  They are a specialized hook placed into the message pump that normally wouldn't exist.  Yes, libraries like MFC do have similar hooks, but you'd have to make filtering logic up yourself if you were working at the Win32 level and handling the message pump yourself.  They also aren't useful if you need to change anything about the message.  You can peek, but not touch.  Any changes you make to the message get lost.  You'd think you could change the message based on the fact the parm is ref, but you can't.  The values you change are to a copy of the message that is created behind scenes, and the values aren't copied back off.

That brings us to PreProcessMessage.  You have a bit more control with this override, however, you only get messages that are destined to your control, not a peek at all messages.  You can be promiscuous again and peek at all the of the messages, but not consume them, definitely good for debugging.  Or you can consume the events, in which case any event handlers or normal processing that would have been done won't get a chance to run.  If you have some garbage you need to throw out then you can do just that.  You can also use PreProcessMessage to trap and consume messages that you wouldn't otherwise get a chance to process.

I did say you'd get more power.  If you change the parameters in the Message structure, they will get copied to the real message this time through.  While you can't change items like HWnd or Msg, you can change WParam and LParam.  That means any rich messages can have their actions changed.  Prime candidates are definitely mouse and keyboard input.  I've used this to turn off scrolling in my listbox while I was rendering the current view (though I came up with a better approach later).

Hopefully this better explains what is available through WinForms and how you can use it.  Unfortunately I don't have a great deal of examples.  You don't often need to use message filters and pre processing unless you are debugging events.  Even the Winforms code only has a couple of classes that use it.  Namely Control, ComboBox, and AxHost.  Hopefully that tells you how much you need to do this.  At the end of the day, you can get the same effects from overriding your WndProc.  Maybe I'll talk about that some other time.

Published Tuesday, May 4, 2004 4:54 AM by Justin Rogers
Filed under: ,

Comments

Tuesday, May 11, 2004 6:11 AM by Joel B

# re: I've done a little experimenting and......

First of all, as you all are aware, I'm very inexperienced. This is a sort of disclaimer...

I wrote a simple Windows Forms application, to test how I could use Application.AddMessageFilter();

1) I went through winuser.h and a few other headers. I built a hashtable where the key is the msg number and the value is a string (WM_xxxxx), so I can easily understand what is going on.

2) I implemented a message filter as described, adding each message to a collection holding msg.HWnd plus the message description if a match is found in the hashtable, otherwise just the message number when the value is unknown (to me)

3) Surprise!
Very few messages have a known value. They fall into just 3 categories: mouse events including button clicks, keyboard events, WM_PAINT (only if not an indirect cause of a mouse movement). Then there are a bunch of events with value 0xc0xx (which are supposed to be private and I have no idea about how to investigate them).
Sometimes there is also a message with value 0x118 (this value falls within the system messages range, however I could not find any reference to it anywhere so I have no idea of what that means -- Anyone has a clue?)

4)I then decided to implement a void WndPro() override.
This time my collection gets all the messages that I expected to catch. It behaves pretty much like I was expecting from using Application.AddMessageFilter()


Any idea about why Application.AddMessageFilter() behaves that way? Could it be still useful in any way?
Tuesday, May 11, 2004 11:11 AM by Justin Rogers

# re: Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

Joel, I'm going to try and get around to a more broad code-path examination of this today with some sample code, since I think that will help you out quite a bit. Stay tuned!
Friday, May 21, 2004 8:26 AM by Joel B.

# re: Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

I know you have been busy, I was just wondering if you had time to look into this matter.
Joel
Tuesday, July 6, 2004 12:23 PM by Steve

# re: Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

in the .net the WndProc has the type:

void WndProc(ref Message m)

While in MFC it has the type:

LRESULT WindowProc(UINT message,WPARAM wParam,LPARAM lParam );

Where did the LRESULT go... has anybody a clue?
Tuesday, August 23, 2011 4:00 AM by quan.huang@yahoo.com.cn

# re: Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

You cannot burn the candle at both ends.

Tuesday, November 22, 2011 9:19 AM by tuttoksdiassy

# re: Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

No truth no life , and howling .

Wednesday, November 23, 2011 3:31 PM by alfuzosin long term side effects

# re: Windows Forms message filters. How they are handy, misunderstood, and when are they not useful.

Sike Priest, sike Offering.