Search code examples
c#winformshotkeyswndproc

Trying to understand what's really happening in a C# WinForms WndProc method when handling hotkey messages


I have been working on a C# WinForms application that registers several hot keys using the well-discussed GlobalAddAtom and RegisterHotKey PInvoke methods. The program starts in minimized mode and runs in the system tray. Each time one of the hot key messages are received, the program captures the data about which key was pressed and hands it off to another object for processing. This has worked relatively well for a while now, but every now and then there is some strange behavior. Things like the same message processed multiple times or some messages missed altogether.

After adding some extensive logging I discovered that if the user held down the hot key combination (Win + C for example) for a little longer than normal, or just plain held it down, then new hot key messages were being received in the message loop before the previous message had finished processing.

Now, the way I see it, a message is received on the UI thread (even though it's hidden) and processed by a blocking call to an instance of a different class. If that's true, then how can another message come into the same function that is currently processing the first message? This is where my lack of Win32 understanding makes me scratch my head.

It seems to me that the second message is received on a different thread. But then if that's true then what instance of my processing class is it calling into?

Any help figuring this out will be greatly appreciated!

Here's a simplified example. This code...

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case MultipleClipboardsDialog.WM_HOTKEY:
            HotKey hotKey = new HotKey(m.LParam);
            Log.Debug("About to process hot key " + hotKey.ToString());
            this.Processor.ProcessHotKey(hotKey);
            Log.Debug("Finished processing hot key " + hotKey.ToString());
            break;

        default:
            base.WndProc(ref m);
            break;
    }
}

...produces output like this.

About to process hot key Win + C
About to process hot key Win + C
About to process hot key Win + C
Finished processing hot key Win + C

Solution

  • The message you are looking for is only generated when the button is released. The way messages are setup in Windows are such that up to three messages are generated for every key-press. Fire up Spy++, and take a look at Notepad. You should be able to see the messages that are generated during normal Windows operations.

    You end up with KeyDown, KeyPressed, and KeyUp messages (or something the equivalent thereof). You're probably intercepting one or two of those messages (normal operations, and you code around that). You might want to look at Ascii and Virtual Keys as well.