SetTimer vs CWnd::SetTimer

say*_*uri 5 winapi mfc

Background

MFC's CWnd::SetTimer calls WinAPI's SetTimer simply.

_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); }
Run Code Online (Sandbox Code Playgroud)

But SetTimer and CWnd::SetTimer documents are not same.

1. nIDEvent parameter

SetTimer:
If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset.

CWnd::SetTimer:
Specifies a nonzero timer identifier. If the timer identifier is unique, this same value is returned by SetTimer. Otherwise, SetTimer determines a new unique value and returns that. For a window timer (which has a NULL callback function), the value must be unique only for other windows timers that are associated with the current window. For a callback timer, the value must be unique for all timers in all processes. Therefore, when you create a callback timer, it is more likely that the returned value might differ from the value you specify.

SetTimer does not depend on callback parameter and always replaces the existing timer. But CWnd::SetTimer depends on callback parameter, and if callback specified, a new timer ID may be generated because the value must be unique for all timers in all processes.

2. Return value

SetTimer:
If the function succeeds and the hWnd parameter is not NULL, then the return value is a nonzero integer. An application can pass the value of the nIDEvent parameter to the KillTimer function to destroy the timer.

CWnd::SetTimer
函数成功时新定时器的定时器标识符。这个值可能等于也可能不等于通过nIDEvent参数传入的值。应用程序应始终将返回值传递给 KillTimer 成员函数以终止计时器。

SetTimer不生成新的计时器 id 并且不返回计时器 id,因此KillTimer使用nIDEvent参数调用。但是CWnd::SetTimer在某些情况下会生成新的计时器 ID,因此请KillTimer使用返回值进行调用。

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


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

Dan*_*Dan 1

据我所知,MFC 文档不正确。我进行了广泛的测试,只要窗口相同,计时器总是会替换以前的计时器。无论有没有回调都是如此。

通过回调,我运行了以下测试:

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);
Run Code Online (Sandbox Code Playgroud)

结果是(来自 VS 调试器跟踪):

timerID=2
timerID=2
timerID=4
timerID=4
nIDEvent=2, hWnd=0x00000000002d0bb8
nIDEvent=4, hWnd=0x00000000002d0bb8
nIDEvent=4, hWnd=0x0000000000140bd0
Run Code Online (Sandbox Code Playgroud)

最后一次 SetTimer 调用使用了不同的窗口,该窗口给出了相同的事件两次。但每次,返回值都与传递给计时器的值相同。nIDEvent 使用相同的值。

CWnd 文档要么已经过时,要么表现得极其谨慎——我们知道返回值是 ID,所以我们应该始终使用它。

然而,有一个说法显然是错误的:

对于回调计时器,该值对于所有进程中的所有计时器必须是唯一的

我刚刚演示了我可以在同一进程中使用同一 ID 两次,并且仍然接收这两个事件。