4

I created a WindowProc to be notified for system time changes:

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;

This code is running inside a Windows Service. The problem is that it isn't fired when I change the system time!

Why not the broadcast message (WM_TIMECHANGE) isn't delivered to my window? There is another way to do this without a loop?


EDIT

I don't known why, but I hardcoded the PeekMessage to process messages to that window, and everything comes to work fine. The code below solved my problem:

 var 
   msg: TMsg;

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

This workaround is very strange, because I already have others windows processing messages (by generic ProcessMessages), only this one isn't processing its messages.

Beto Neto
  • 3,962
  • 7
  • 47
  • 81
  • Q: by "time changes" you mean when the user changes the system time by clicking on the taskbar clock or when the system time changes automatically? – Bogdan Doicin Feb 14 '13 at 11:00
  • Does your window procedure receive any messages at all? – David Heffernan Feb 14 '13 at 11:03
  • I'd like to see the message loop code for the window - is there one? – mj2008 Feb 14 '13 at 11:12
  • (Bogdan: yes) services can process messages but cannot receive messages from system??? – Beto Neto Feb 14 '13 at 11:39
  • David: yes, I have an internal protocol comunication what uses sendmessage with AllocateHWnd, and they works! The only think what doesn't works is the receiving of the WM_TIMECHANGE from system. – Beto Neto Feb 14 '13 at 11:42
  • What integrity level is your service running at? Is the message blocked by UIPI? Do you need to call `ChangeWindowMessageFilter` to let the message bypass UIPI. – David Heffernan Feb 14 '13 at 11:48
  • Are there multiple threads in your service. Is the time change listener window created in a different thread from the thread that calls `ProcessMessages`? – David Heffernan Feb 14 '13 at 12:55
  • David: yes, the secondary windowproc is allocated in another thread (not in the mainthread). – Beto Neto Feb 14 '13 at 13:12
  • 1
    Nice to see the reopen review queue process works. Now, wouldn't it be nice if the close review queue wasn't full of badge hunters that close anything without understanding what they are doing. – David Heffernan Feb 14 '13 at 14:08

1 Answers1

8

The reason your window was not receiving the WM_TIMECHANGE messages is that your window is created from a secondary thread.

Each thread in a process has its own message queue. Synchronous messages are delivered when you service the message queue, so ever for a non-queued message like WM_TIMECHANGE you do need to service the secondary threads message queue in order for messages to be delivered.

For example, look at the documentation for GetMessage, the most common way to pull messages of the queue:

The function dispatches incoming sent messages until a posted message is available for retrieval.

The same is true for PeekMessage. It dispatches incoming sent messages before peeking the queue.

There are a handful of other ways for sent messages to be dispatched, but these are the primary ones.

Now, I suspect that it may be inconvenient for you to periodically dispatch messages from your secondary thread. If your secondary thread does nothing else then it can simply sit in the traditional GetMessage, TranslateMessage, DispatchMessage loop. And most of the time it will happily block in GetMessage dispatching any incoming sent messages. But if your secondary thread does more work then that's probably not a viable option.

You are already running and servicing a message queue on the main service thread. It may make more sense to make your listener window have affinity with the main service thread. Do that by creating it from code that runs in the main service thread.

Note also that AllocateHWnd is documented not to be thread-safe. You must not call it from any thread other than the main thread of the process. So, if you do wish to remain on a secondary thread, you'll need to use CreateWindow rather than AllocateHWnd. But this is perhaps yet another good reason to move this window onto the main thread.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 2
    I would process the message in the main thread by calling `SetEvent` to notify the secondary thread that is normally blocked by `WaitForMultipleObjects`. – kludg Feb 14 '13 at 13:39