4

我创建了一个 WindowProc 来通知系统时间更改:

constructor TJJWScheduler.Create;
begin 
  fTimeChangeWnd := Classes.AllocateHWnd(TimeChangeWndProc);
end;

procedure TJJWScheduler.TimeChangeWndProc(var msg: TMessage);
var
  i: integer;
begin
  case msg.Msg of
    WM_TIMECHANGE:
      begin
        // my things
      end;
  end;
end;

此代码在 Windows 服务中运行。问题是当我更改系统时间时它没有被触发!

为什么广播消息 (WM_TIMECHANGE) 没有传递到我的窗口?还有另一种没有循环的方法吗?


编辑

我不知道为什么,但是我硬编码了 PeekMessage 来处理该窗口的消息,并且一切正常。下面的代码解决了我的问题:

 var 
   msg: TMsg;

 if PeekMessage(msg, fTimeChangeWnd, WM_TIMECHANGE, WM_TIMECHANGE, PM_REMOVE) then
 begin
   TranslateMessage(msg);
   DispatchMessage(msg);
 end;

这种解决方法很奇怪,因为我已经有其他窗口处理消息(通过通用 ProcessMessages),只有这个不处理它的消息。

4

1 回答 1

8

您的窗口没有收到WM_TIMECHANGE消息的原因是您的窗口是从辅助线程创建的。

进程中的每个线程都有自己的消息队列。当您为消息队列提供服务时,同步消息会被传递,因此对于像您这样的非排队消息,WM_TIMECHANGE您需要为辅助线程消息队列提供服务才能传递消息。

例如,查看文档GetMessage,这是提取队列消息的最常见方法:

该函数分派传入的已发送消息,直到发布的消息可用于检索。

对于PeekMessage. 它在查看队列之前调度传入的已发送消息。

发送消息还有其他几种发送方式,但这些是主要方式。

现在,我怀疑您定期从辅助线程发送消息可能不方便。如果您的辅助线程什么都不做,那么它可以简单地位于传统的GetMessage, TranslateMessage,DispatchMessage循环中。大多数情况下,它会愉快地阻止GetMessage发送任何传入的已发送消息。但是,如果您的辅助线程做更多的工作,那么这可能不是一个可行的选择。

您已经在主服务线程上运行和服务一个消息队列。使您的侦听器窗口与主服务线程具有亲和力可能更有意义。通过从在主服务线程中运行的代码创建它来做到这一点。

另请注意,这AllocateHWnd不是线程安全的。您不能从进程的主线程以外的任何线程调用它。因此,如果您确实希望保留在辅助线程上,则需要使用CreateWindow而不是AllocateHWnd. 但这也许是将这个窗口移到主线程上的另一个很好的理由。

于 2013-02-14T13:22:16.513 回答