Mason Wheeler
Mason Wheeler

Reputation: 84550

Filtering the Windows message queue

I've got a routine that looks something like this, in pseudocode:

while PeekMessage(Message, 0, 0, 0, PM_REMOVE)
  HandleMessageAppropriately(Message)

Basically, it goes through and pulls all messages out of the queue and dispatches them. I can't change this routine.

I've got a scenario in which this routine, if it's being called under certain conditions and there's a message in the queue representing the user having hit ESC at exactly the wrong moment, it can cause the program to crash. (Gotta love race conditions.)

I can't change the routine above, but I can change the code that calls it. Is there any way that I can do something immediately before this is run that will say "go through the message queue and remove all keyboard input messages where the user hit ESC, without affecting the rest of the items in the queue or changing their order"?

Upvotes: 0

Views: 1491

Answers (3)

Hans Passant
Hans Passant

Reputation: 941705

This is the exact equivalent to the infamous DoEvents call that got so many VB6 programmers in trouble. Because surely the ESC keypress is closing a window, leaving code running in a loop without a user interface anymore. The outcome is invariably poor.

You don't mess around with this, you call EnableWindow(hWnd, FALSE) before you enter this loop to disable input on the window that shouldn't be closed. Now you don't care anymore what's in the message queue. The exact same thing that dialogs do.

Don't paper over a modal loop. Make it modal, make it obvious to the user too.

Upvotes: 3

David Heffernan
David Heffernan

Reputation: 613053

You may be best to hook the call to PeekMessages and replace it with a version that does what you need.

You could use madshi's hooking routines but it's not hard - I've published a simple hook routine here on Stack Overflow.

If the code was running in an executable module that you compile then you could compile a customised version of Windows.pas that replaced PeekMessage. Of course I'm guessing that you code is Delphi.

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308216

You can use the range parameters in PeekMessage to restrict to the WM_CHAR message only, and PM_NOREMOVE to leave the message queue intact if the character isn't ESC; if the message needs to be removed, repeat the process with the PM_REMOVE flag. Unfortunately there's no way to look past the first WM_CHAR in the queue.

Upvotes: 3

Related Questions