【问题标题】:SetTimer vs CWnd::SetTimerSetTimer 与 CWnd::SetTimer
【发布时间】:2018-06-24 14:13:10
【问题描述】:

背景

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); }

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

那么,哪个文件是正确的?


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

【问题讨论】:

  • 我依赖SetTimer() 的记录行为,它似乎像宣传的那样工作。如果你真的想知道,你应该运行一些简单的测试。
  • 当MFC和WinAPI文档有区别的时候,我一般都是靠后者。毕竟它是信息的主要来源。
  • 尤其是在这种情况下,MFC 只是转发到 API。据我所知,MFC 文档在编写时是正确的,但 API 发生了变化,MFC 从未更新以匹配。
  • MFC 是否可以追溯到 16 位 Windows?在现代世界中,对“所有进程”的限制没有多大意义。
  • @MarkRansom,是的:MFC 于 1992 年与 Microsoft 的 C/C++ 7.0 编译器一起推出,用于 ​​16 位版本的 Windows,作为 Windows API 的极薄的面向对象的 C++ 包装器(维基百科) .

标签: winapi mfc


【解决方案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);

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

timerID=2
timerID=2
timerID=4
timerID=4
nIDEvent=2, hWnd=0x00000000002d0bb8
nIDEvent=4, hWnd=0x00000000002d0bb8
nIDEvent=4, hWnd=0x0000000000140bd0

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多