-1

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.

Andy
  • 10,110
  • 3
  • 28
  • 47
KIM CHANGJUN
  • 107
  • 9
  • Why are you posting `WM_TIMER` messages at all? You should be calling `SetTimer` and the system will post those messages to your window procedure. – Andy Aug 17 '20 at 04:03
  • 2
    It is [documented behavior](https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-timer), DispatchMessage() treats it differently and won't call WndProc. Note that you *do* see this message in the message loop, after the GetMessage() call. But that's where it ends, would be nice if it screamed bloody murder about the invalid function pointer. It doesn't. – Hans Passant Aug 17 '20 at 07:31
  • @HansPassant -- What's interesting is if you change it to `SendMessage`, it works fine. Just tried it out. – Andy Aug 17 '20 at 16:02
  • 1
    By design, SendMessage() directly calls WndProc so DispatchMessage() is not used. GetMessage() only retrieves posted messages. WM_TIMER is normally always posted, never sent. – Hans Passant Aug 17 '20 at 16:05

1 Answers1

0

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.

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
Song Zhu
  • 3,265
  • 3
  • 5
  • 15
  • It's unclear how you arrived at the conclusion that it were impossible to post `WM_TIMER` messages. That's not what the quoted documentation says. – IInspectable Aug 17 '20 at 07:10
  • @IInspectable For my expression problem, I have modified the reply, anyway, I recommend using SetTimer. – Song Zhu Aug 17 '20 at 07:14
  • Great. Now it doesn't answer the question that was asked anymore. – IInspectable Aug 17 '20 at 07:16
  • @IInspectable My mistakes for me wrongly read the question, I have revised my reply. – Song Zhu Aug 17 '20 at 07:38
  • That's useless. It explains what someone that neither understands the message nor has access to the source code might guess. It's not like the system would see whether there is `WM_TIMER` in the queue, and if so read its arguments, and then decide where it gets delivered. You're going to have to ignore boatloads of facts to arrive at this conclusion. – IInspectable Aug 17 '20 at 09:04
  • `The system cannot handle the timer's timeout function through this pointer, so the WM_TIMER cannot be triggered.` [*citation needed*] – Andy Aug 17 '20 at 15:47
  • @Andy A non-null value in the lParam that isn't a function pointer fails to meet the API requirements and therefore triggers undefined behavior. – Raymond Chen Aug 18 '20 at 20:28