TTimer 实际上是如何在内部工作的?

How TTimer actually works internally?

间隔设置为 1 秒的 TTimer 每 1 秒发送一条消息。此消息在应用程序的消息循环中处理,从而触发 OnTimer 事件。
如果应用程序很忙,没有时间处理消息循环,则跳过 OnTimer 事件。

我知道 TTimer 在内部使用 SetTimer

我的问题是:

  1. TTimer 是否使用 internal/separate 线程(通过 SetTimer)?
  2. 如果模态 MessageDlg 是 "blocking" 表单,为什么保存计时器(甚至它的 OnTimer)的表单仍然可以执行某些操作? (见下面的代码)
  3. 文档说 SetTimer 至少需要 Win2000。 TTimer 在 Win98 中是如何实现的?

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
 Caption = i;
 i++;
 MessageDlg(stuff);      <----- we "block" application here but form's caption is still updated.
}

WM_TIMER 消息永远不会放在消息队列中。它们在队列为空且设置了指示计时器已过期的标志时生成。因此,队列中一次永远不会有超过一条 WM_TIMER 条消息,如果您的应用程序太忙而无法处理队列,您不会收到很多 WM_TIMER 条消息等待处理。

WM_PAINT 消息的工作方式相同。

If the application is busy and doesn't have time to process the message loop, the OnTimer event is skipped.

这实际上是正确的。 This and this MSDN 上的博客文章提供了一些内部实现细节,特别是他们提到过期计时器会导致设置消息队列状态的 QS_TIMER 标志。没有进一步的时间流逝将导致队列状态标志被设置得更多。当设置此标志并且 [Peek|Get]Message 无法选择任何更高优先级的消息时,将生成一个计时器消息。

尽管计时器消息不会堆积在队列中,但有可能在前一个事件处理程序正在执行时再次触发计时器。当处理程序中的代码执行时间比计时器间隔长并且允许重新进入时,这是可能的。如果计时器处理程序导致应用程序处理排队的消息,则可能会清除任何挂起的队列状态标志并再次发布消息,这可能会导致计时器在处理程序完成执行之前触发。

Does TTimer use an internal/separate thread (via SetTimer)?

没有。实用程序 window 在主线程中创建,它将接收计时器消息。收到计时器消息后,如果分配了一个,则此 window 调用事件处理程序。

How come that the form that holds the timer (and its OnTimer even) can still do stuff if a modal MessageDlg is "blocking" the form?

模态循环继续处理队列,它在调用 ProcessMessage 的循环中调用应用程序的 HandleMessage。因此定时器消息仍然被处理。

这是上述重新进入的潜在原因。您可以使用标志或 disable/enable 计时器来防止这种情况发生。或者完全排除处理程序中的任何消息处理。

The documentations says that SetTimer requires Win2000 minimum. How was TTimer implemented in Win98

同理。文档不断变化,有时 MSDN 会从最低要求中删除不受支持的 OS 版本——相当不一致。我的 XE2 API 文档指出:

Minimum operating systems Windows 95, Windows NT 3.1

对于 WM_TIMER 消息。