我的代码有问题,几个小时后,我似乎无法弄明白......
问题:我试图每十秒尝试连接一台服务器。当计时器第一次过去时,回调函数被调用就好了,但随后立即再次调用它(不等待十秒),并且一次又一次地反复调用它,好像定时器消息没有从中移除队列。有人可以帮忙吗?
计时器在此处设置:
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;
}
}
我真的很感激任何帮助......如果您需要更多信息,请告诉我......
此致 法利
答案 0 :(得分:2)
我认为这种情况正在发生,因为您在消息循环中调用了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()文档中的示例。)
由于GetMessage()
将阻塞,直到队列中有消息,您不需要调用Sleep()
,并且当没有任何内容时,您的进程将不会使用任何CPU做。
答案 1 :(得分:1)
问题是未检查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);
}