C++ Can';t删除WM_定时器消息
我的代码有问题,几个小时后,我似乎无法理解 问题:我正在尝试每10秒连接一个服务器。当计时器第一次过期时,回调函数会被很好地调用,但随后会立即再次调用它(无需等待10秒),并且它会被一次又一次地重复调用,就好像计时器消息没有从队列中删除一样。有人能帮忙吗 计时器在此处设置:C++ Can';t删除WM_定时器消息,c++,windows,winapi,timer,C++,Windows,Winapi,Timer,我的代码有问题,几个小时后,我似乎无法理解 问题:我正在尝试每10秒连接一个服务器。当计时器第一次过期时,回调函数会被很好地调用,但随后会立即再次调用它(无需等待10秒),并且它会被一次又一次地重复调用,就好像计时器消息没有从队列中删除一样。有人能帮忙吗 计时器在此处设置: SConnect::SConnect() { hSimConnect = NULL; Attempt(); SetTimer(hMainWindow, reinterpret_cast<UINT
SConnect::SConnect()
{
hSimConnect = NULL;
Attempt();
SetTimer(hMainWindow, reinterpret_cast<UINT_PTR>(this), 10000, (TIMERPROC)TimerProc);
}
计时器回调函数如下所示:
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;
}
}
void CALLBACK SConnect::TimerProc(HWND HWND、UINT uMsg、UINT_PTR idEvent、DWORD dwTime){
SCONECT*pSC=重新解释铸件(idEvent);
MSG-wMsg;
如果(!pSC->已连接)
pSC->trunt();
否则{
pSC->connected=false;
}
}
我真的很感激任何帮助。。。请让我知道如果你需要更多的信息
真诚地,
Farley我认为这是因为您在消息循环中调用的是
peek message()
,而不是GetMessage()
如果队列中没有消息,peek message()
将返回FALSE
。我不知道peek message()
的实现是什么,但是如果队列中没有消息,我可以看到它将msg
参数的内容单独保留。这意味着当peek message()
返回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()
将一直阻塞,直到队列中有消息,因此您不需要调用Sleep()
,并且当没有什么事情可做时,您的进程将不会使用任何CPU。我认为发生这种情况是因为您正在消息循环中调用peek message()
,而不是GetMessage()
如果队列中没有消息,peek message()
将返回FALSE
。我不知道peek message()
的实现是什么,但是如果队列中没有消息,我可以看到它将msg
参数的内容单独保留。这意味着当peek message()
返回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()
将一直阻塞,直到队列中有消息为止,因此您不需要调用Sleep()
,并且当没有任何事情可做时,您的进程将不会使用任何CPU。问题是没有检查peek message()的返回值。在每个循环中,如果没有新消息,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);
}
问题是没有检查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);
}
这些计时器是周期性的。你必须打电话给KillTimer()让他们停止。哦,对不起,我的问题不清楚。我的意思是回调会立即一次又一次地被调用(不是每十秒钟一次)。请提供一个,从而避免任何混淆的范围。如果消息循环中存在大量错误,它不会检查PeekMessage()的返回值。因此,您得到的第一个WM_计时器将工作。然后PeekMessage()返回FALSE,这是您看不到的,您将一次又一次地发送消息。Sleep(50)调用也是非常邪恶的。顺便说一句,
Sleep()
意味着您的程序每秒最多处理20条消息。这也意味着对任何新消息的响应都需要50毫秒。您不应该在UI线程上睡眠。如果你想每50ms更新一次,那么创建另一个计时器来触发更新。这些计时器是周期性的。你必须打电话给KillTimer()让他们停止。哦,对不起,我的问题不清楚。我的意思是回调会立即一次又一次地被调用(不是每十秒钟一次)。请提供一个,从而避免任何混淆的范围。如果消息循环中存在大量错误,它不会检查PeekMessage()的返回值。因此,您得到的第一个WM_计时器将工作。然后PeekMessage()返回FALSE,这是您看不到的,您将一次又一次地发送消息。Sleep(50)调用也是非常邪恶的。顺便说一句,Sleep()
意味着您的程序每秒最多处理20条消息。这也意味着对任何新消息的响应都需要50毫秒。您不应该在UI线程上睡眠。如果你想每50毫秒更新一次,那么再创建一个计时器来触发更新。我在所有程序中都使用相同的消息循环,所以我不再关注它:)不过Sleep(50)
应该是一个很好的警告+1要记住这不是一个函数替换,Update()方法的调用远远不够