Search code examples
winapitimermessage

Does PeekMessage never generate new WM_TIMER messages if there's something in the queue already, regardless of filters?


I understand WM_TIMER messages are generated on the fly by Get & Peek, based on some flag that says "a timer has elapsed, when you're ready post a timer message".

From the docs:

The WM_TIMER message is a low-priority message. The GetMessage and PeekMessage functions post this message only when no other higher-priority messages are in the thread's message queue.

Does this mean that PeekMessage will return False (i.e no messages) if I use it with a filter like:

messageFound = PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE)

if there are any messages of higher priority in the queue; even ones that don't match the filter? So both of these queues would return false because of the presence of a (non-matching) high priority message

WM_NOTIFY                        or        WM_NOTIFY
--Flag to autogenerate timer--             WM_TIMER

Will WM_SYS­TIMER have an impact because it's in the same group as WM_TIMER

Or does it simply mean that if I have no filter then no new auto-generated WM_TIMER messages will be created if other messages are in the queue, but any that are already there (from say a Peek + PM_NOREMOVE) will behave like normal messages? (i.e. Peek now just returns whichever was posted first)


If highPriorityMessagesExist() Then
    Return anyOfThemMatchTheFilter()
Else 
    If !lowPriorityMessagesExist()
        tryGenerateSomeFromFlags()

    If lowPriorityMessagesExist()
        Return anyOfThemMatchTheFilter()
    Else
        Return False

vs

If anyMessagesMatchTheFilter()
    Return True
Else
    tryGenerateSomeFromFlags()
Return anyMessagesMatchTheFilter()

Solution

  • WM_TIMER message generation will not happen if there are messages in the filter range that are high priority. However if there are high priority messages in the queue but they are filtered out by the wMsgFilterMin and wMsgFilterMax parameters of GetMessage or PeekMessage, WM_TIMER messages will still be generated.

    In other words this program will generate debug output:

    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        SetTimer(NULL, 101, 500, NULL);
    
        auto start = GetTickCount();
        while (GetTickCount() - start < 4000) {
            MSG msg;
            PostMessage(NULL, WM_NOTIFY, 0, 0);
            GetMessage(&msg, NULL, WM_TIMER, WM_TIMER);
            if (msg.message == WM_TIMER)
                OutputDebugStringA("WM_TIMER\n");
        }
    
        return 0;
    }
    

    but the following program will not generate debug output, because WM_NOTIFY is now in the filter range:

    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        SetTimer(NULL, 101, 500, NULL);
    
        auto start = GetTickCount();
        while (GetTickCount() - start < 4000) {
            MSG msg;
            PostMessage(NULL, WM_NOTIFY, 0, 0);
            GetMessage(&msg, NULL, WM_NOTIFY, WM_TIMER);
            if (msg.message == WM_TIMER)
                OutputDebugStringA("WM_TIMER\n");
        }
    
        return 0;
    }