Search code examples
winapimessage-queuemessagepostmessage

dispatchmessage function didn't execute WM_TIMER message when PostMessage


i am learning win32 thesedays and playing with PostMessage function.

tricky thing i found was when posting WM_TIMER message into window message queue, window didn't receive any message. if only receive when i set lparam to 0, otherwise not working at all the code here. and also i tested with sendmessage which is totally fine either ways.

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            //PostMessage(hWnd, WM_TIMER, 0, 0); // receive msg
            PostMessage(hWnd, WM_TIMER, 0, 1); // not receiving
        }
        return 0;
        case WM_TIMER:
        {
            switch (wparam)
            {
                case 0:
                {
                    HDC dc = GetDC(hWnd);

                    Ellipse(dc, 70, 70, 120, 120);
                    ReleaseDC(hWnd, dc);
                }
                break;
            }
            return 0;
        }
    }
    return DefWindowProc(hWnd, msg, wparam, lparam);
}

would be amazing if somebody explain why this is happening. just hope i am missing some basic concept of windows processing system.


Solution

  • According to the WM_TIMER documentation:

    lParam [in]

    A pointer to an application-defined callback function that was passed to the SetTimer function when the timer was installed.

    So, when you use PostMessage(hWnd, WM_TIMER, 0, 0), you pass 0 (as a null pointer) to lParam.

    According to the SetTimer documentation:

    A pointer to the function to be notified when the time-out value elapses. For more information about the function, see TimerProc. If lpTimerFunc is NULL, the system posts a WM_TIMER message to the application queue. The hwnd member of the message's MSG structure contains the value of the hWnd parameter.

    This means when DispatchMessage() sees the WM_TIMER message with its lParam set to 0, it will simply deliver the message as-is to the window message procedure of the window specified by hWnd.

    But, when you use PostMessage(hWnd, WM_TIMER, 0, 1); instead, you are passing 1 as the lParam, so it is treated as a pointer to a timer callback function. This means when DispatchMessage() sees the WM_TIMER message with its lParam set to non-zero, it will not deliver the message to the window message procedure of hWnd, it will instead try to actually call the function pointed to by lParam, which is obviously illegal in this case. The system cannot call a function through this invalid pointer.

    According to the DispatchMessage() documentation:

    The MSG structure must contain valid message values. If the lpmsg parameter points to a WM_TIMER message and the lParam parameter of the WM_TIMER message is not NULL, lParam points to a function that is called instead of the window procedure.