winapi - SetTimer 与 CWnd::SetTimer
问题描述
背景
MFC 对CWnd::SetTimer
WinAPI 的调用很SetTimer
简单。
_AFXWIN_INLINE UINT_PTR CWnd::SetTimer(UINT_PTR nIDEvent, UINT nElapse,
void (CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD))
{ ASSERT(::IsWindow(m_hWnd)); return ::SetTimer(m_hWnd, nIDEvent, nElapse,
lpfnTimer); }
但是SetTimer和CWnd::SetTimer文档并不相同。
1.nIDEvent
参数
SetTimer
:
如果hWnd参数不为NULL并且hWnd指定的窗口已经有一个值为nIDEvent的计时器,那么现有的计时器将被新的计时器替换。当SetTimer替换一个定时器时,定时器被重置。
CWnd::SetTimer
:
指定一个非零定时器标识符。如果计时器标识符是唯一的,则返回相同的值SetTimer
。否则,SetTimer
确定一个新的唯一值并返回它。对于窗口计时器(具有 NULL 回调函数),该值必须仅对于与当前窗口关联的其他窗口计时器是唯一的。对于回调计时器,该值对于所有进程中的所有计时器必须是唯一的。因此,当您创建回调计时器时,返回的值很可能与您指定的值不同。
SetTimer
不依赖回调参数,总是替换现有的定时器。但CWnd::SetTimer
取决于回调参数,如果指定了回调,可能会生成一个新的定时器ID,因为该值对于所有进程中的所有定时器必须是唯一的。
2.返回值
SetTimer
:
如果函数成功并且hWnd参数不是NULL,那么返回值是一个非零整数。应用程序可以将nIDEvent参数的值传递给KillTimer函数以销毁计时器。
CWnd::SetTimer
:
函数成功时新定时器的定时器标识符。这个值可能等于也可能不等于通过nIDEvent
参数传入的值。应用程序应始终将返回值传递给 KillTimer 成员函数以终止计时器。
SetTimer
不会生成新的定时器ID,也不返回定时器ID,所以KillTimer
带nIDEvent
参数调用。但CWnd::SetTimer
在某些情况下会生成新的计时器 id,因此KillTimer
使用返回值调用。
因此,哪个文件是正确的?
我想使用SetTimer
带有回调的 WinAPI,它可以在我的电脑上运行。但是如果某些平台没有替换现有的定时器,我无法接受回调定时器。
解决方案
MFC documentation is incorrect, as far as I can tell. I have tested extensively, and the timers always replace the previous timer, provided the window is the same. This is true with callbacks and without.
With a callback, I ran the following test:
static void CALLBACK MyTimerProc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime) {
KillTimer(hWnd, nIDEvent);
}
...
timerID = SetTimer(2, 1000, MyTimerProc);
timerID = SetTimer(2, 1100, MyTimerProc);
timerID = SetTimer(4, 1200, MyTimerProc);
timerID = GetParentFrame()->SetTimer(4, 1300, MyTimerProc);
Results were (from VS debugger trace):
timerID=2
timerID=2
timerID=4
timerID=4
nIDEvent=2, hWnd=0x00000000002d0bb8
nIDEvent=4, hWnd=0x00000000002d0bb8
nIDEvent=4, hWnd=0x0000000000140bd0
The last SetTimer call used a different window, which gave the same event twice. But every time, the return value is identical to the value passed for the timer. And the same value is used for nIDEvent.
The CWnd documentation is either out of date, or acting out of extreme caution--we know the return value is the ID, so we should always use that.
However, one statement is clearly false:
For a callback timer, the value must be unique for all timers in all processes
I just demonstrated I could use the same ID twice, within the same process, and still receive both events.
推荐阅读
- matlab - 碰撞问题:将圆弧的旋转中心放在一个半圆上并旋转它直到它接触到它所在的半圆
- reactjs - 我们如何在 antd 中根据 jsx 条件和数组索引添加元素
- javascript - 以更短的方式替换下面的 if、else-if、else
- amazon-ecs - 应用程序负载均衡器返回 504Gateway Timeout
- php - 数组没有为 foreach 循环提供正确的输出
- node.js - 除了process.env之外,有没有办法在整个项目中访问节点js中的变量(aws-ssm)?
- flutter - Flutter 项目规模确实很大。如何减少它?
- google-cloud-platform - 当您想继续使用分页检索结果时,在 BigQuery 表中进行分页的最佳方法是什么?
- html - 如何使用 JQuery 默认隐藏可切换文本
- php - 如何将视频后端上传到 Facebook,但要按计划发布