提问人:lequinne 提问时间:4/16/2016 最后编辑:lequinne 更新时间:4/16/2016 访问量:726
无法删除WM_TIMER消息
Can't Remove WM_TIMER message
问:
我的代码有问题,几个小时后,我似乎无法弄清楚......
问题:我正在尝试每十秒尝试连接到服务器一次。当计时器第一次经过时,回调函数被调用得刚刚好,但随后立即再次调用(无需等待十秒钟),并且它不断被反复调用,就好像计时器消息没有从队列中删除一样。谁能帮忙?
计时器设置如下:
SConnect::SConnect()
{
hSimConnect = NULL;
Attempt();
SetTimer(hMainWindow, reinterpret_cast<UINT_PTR>(this), 10000, (TIMERPROC)TimerProc);
}
(唯一的)应用程序消息循环如下:
while (true)
{
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (msg.message == WM_QUIT)
break;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//UPDATES
pSCObj->Update();
manager.Update();
Sleep(50);
}
定时器回调函数在这里:
void CALLBACK SConnect::TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
SConnect *pSC = reinterpret_cast<SConnect *>(idEvent);
MSG wMsg;
if (!pSC->connected)
pSC->Attempt();
else{
pSC->connected = false;
}
}
我真的很感激任何帮助......如果您需要更多信息,请告诉我...
真诚地 法
答:
我认为发生这种情况是因为您正在调用消息循环而不是.PeekMessage()
GetMessage()
PeekMessage()
如果队列中没有消息,将返回。我不知道的实现是什么,但如果队列中没有消息,我可以看到它不理会参数的内容。这意味着当返回时,将包含队列中的上一条消息。 然后盲目地传递给 ,然后 尽职尽责地将其传递给窗口的窗口过程。因此,只要该消息是最后处理的消息,就会调用您的计时器回调,直到将另一条消息添加到队列中。FALSE
PeekMessage()
msg
PeekMessage()
FALSE
msg
msg
DispatchMessage()
WM_TIMER
您可以使用更传统的消息循环来解决此问题:
BOOL bRet;
while( (bRet = GetMessage( &msg, nullptr, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
pSCObj->Update();
manager.Update();
}
(消息循环改编自 GetMessage() 文档中的示例。
由于在队列中有消息之前会阻塞,因此您不需要调用 ,并且您的进程在无事可做时不会使用任何 CPU。GetMessage()
Sleep()
评论
Sleep(50)
问题是没有检查 PeekMessage() 的返回值。在每个循环中,如果没有新消息,PeekMessage 会保持 msg 的内容不变,然后再次调度。
仅当 PeekMessage() 返回 true 时才调度消息可以解决问题:
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if (msg.message == WM_QUIT)
break;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//UPDATES
pSCObj->Update();
manager.Update();
Sleep(50);
}
下一个:强制使用枚举 c++ 的一个别名
评论
KillTimer()
Sleep()
Sleep