我创建了一个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),只有这个没有处理它的消息。
答案 0 :(得分:8)
您的窗口未收到WM_TIMECHANGE
消息的原因是您的窗口是从辅助线程创建的。
进程中的每个线程都有自己的消息队列。在为消息队列提供服务时会传递同步消息,因此,对于像WM_TIMECHANGE
这样的非排队消息,您需要为辅助线程消息队列提供服务,以便传递消息。
例如,查看GetMessage
的文档,这是拉取队列消息的最常用方法:
该函数调度传入的已发送消息,直到发布的消息可供检索。
PeekMessage
也是如此。它在查看队列之前调度传入的已发送消息。
还有一些其他方式可以发送已发送的消息,但这些是主要的方式。
现在,我怀疑您定期从辅助线程发送消息可能不方便。如果您的辅助线程没有做任何其他操作,那么它可以简单地放在传统的GetMessage
,TranslateMessage
,DispatchMessage
循环中。大多数情况下,它会愉快地阻止GetMessage
调度任何传入的已发送消息。但是如果你的辅助线程做得更多,那么这可能不是一个可行的选择。
您已在主服务线程上运行并为消息队列提供服务。使侦听器窗口与主服务线程具有亲缘关系可能更有意义。通过从主服务线程中运行的代码创建它来做到这一点。
另请注意,AllocateHWnd
记录为不是线程安全的。您不能从进程主线程以外的任何线程调用它。因此,如果您确实希望继续使用辅助线程,则需要使用CreateWindow
而不是AllocateHWnd
。但这也许是将此窗口移到主线程上的另一个好理由。