首页 > 解决方案 > SetTimer 与 CWnd::SetTimer

问题描述

背景

MFC 对CWnd::SetTimerWinAPI 的调用很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); }

但是SetTimerCWnd::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,所以KillTimernIDEvent参数调用。但CWnd::SetTimer在某些情况下会生成新的计时器 id,因此KillTimer使用返回值调用。

因此,哪个文件是正确的?


我想使用SetTimer带有回调的 WinAPI,它可以在我的电脑上运行。但是如果某些平台没有替换现有的定时器,我无法接受回调定时器。

标签: winapimfc

解决方案


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.


推荐阅读