Winapi dispatchmessage函数没有';发送后消息时不执行WM_定时器消息
这些天我在学习win32 并使用PostMessage函数 我发现一件棘手的事情是,当将WM_定时器消息发布到窗口消息队列中时,窗口并没有收到任何消息。 如果只在我将lparam设置为0时接收,否则根本不工作 代码在这里。 我还用sendmessage进行了测试,这两种方法都很好Winapi dispatchmessage函数没有';发送后消息时不执行WM_定时器消息,winapi,message-queue,message,postmessage,Winapi,Message Queue,Message,Postmessage,这些天我在学习win32 并使用PostMessage函数 我发现一件棘手的事情是,当将WM_定时器消息发布到窗口消息队列中时,窗口并没有收到任何消息。 如果只在我将lparam设置为0时接收,否则根本不工作 代码在这里。 我还用sendmessage进行了测试,这两种方法都很好 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) {
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);
}
如果有人能解释为什么会发生这种事,那就太不可思议了。
只希望我缺少一些windows处理系统的基本概念。根据文档:
lParam[in]
指向应用程序定义的回调函数的指针,该回调函数在安装计时器时传递给SetTimer
函数
因此,当您使用PostMessage(hWnd,WM_TIMER,0,0)
时,您将0(作为空指针)传递给lParam
根据文件:
指向超时值过期时要通知的函数的指针。有关该函数的更多信息,请参阅TimerProc如果lpTimerFunc
为NULL
,系统将WM\u定时器消息发布到应用程序队列。消息的MSG
结构的hwnd
成员包含hwnd
参数的值
这意味着当DispatchMessage()
看到WM_TIMER
消息且其lParam
设置为0时,它将按原样将消息传递到hWnd
指定的窗口的窗口消息过程
但是,当您使用PostMessage时(hWnd,WM_TIMER,0,1)相反,您将1作为lParam
传递,因此它被视为指向计时器回调函数的指针。这意味着当DispatchMessage()
看到WM_TIMER
消息且其lParam
设置为非零时,它将不会将消息传递到hWnd
的窗口消息过程,而是尝试实际调用lParam
指向的函数,这在这种情况下显然是非法的。系统无法通过此无效指针调用函数
根据文件:
MSG
结构必须包含有效的消息值。如果lpmsg
参数指向WM\u TIMER
消息,并且WM\u TIMER
消息的lParam
参数不是NULL
,则lParam
指向调用的函数,而不是窗口过程
你为什么要发布WM\u TIMER
消息?您应该调用SetTimer
,系统会将这些消息发布到您的窗口过程中。事实上,DispatchMessage()会以不同的方式对待它,并且不会调用WndProc。注意,在GetMessage()调用之后,您确实在消息循环中看到了此消息。但这就是它的结尾,如果它对无效的函数指针大喊大叫,那就太好了。它没有。@HansPassant——有趣的是,如果您将其更改为sendmages
,它就可以正常工作。只是尝试了一下。根据设计,SendMessage()直接调用WndProc,因此不使用DispatchMessage()。GetMessage()仅检索已发布的消息。WM_TIMER通常都是发布的,从不发送。不清楚您是如何得出结论的,即不可能发布WM_TIMER
消息的。引用的文档并不是这么说的。@I鉴于我的表达式问题,我已经修改了回复,无论如何,我建议使用SetTimer.Great。现在它不再回答被问到的问题了。@I尽管我错了,但我错读了这个问题,我已经修改了我的回答。那没用。它解释了既不理解消息也无法访问源代码的人可能猜到的内容。系统不会看到队列中是否有WM_TIMER
,如果有,则读取其参数,然后决定在哪里传递。为了得出这个结论,你必须忽略大量的事实。