WM_TIMECHANGE broadcast strangeness...

| 3 Comments

I'm currently writing and testing a simple class that watches for system time changes. This is to allow an app to adjust some timers that it sets for absolute times in the future if the system time changes.

The code's fairly simple. The system automatically broadcasts a WM_TIMECHANGE message to all top level windows whenever something adjusts the system time or the time zone so all you need to do is write code that creates a hidden window and deals with the message.

Testing this was proving somewhat tricky. On my Vista development box I found that trying to broadcast my own WM_TIMECHANGE message didn't work. I tried various methods along the lines of: SendMessage(HWND_BROADCAST, WM_TIMECHANGE, 0, 0); and none of them resulted in my window getting the message. I did some googling and tried SendNotifyMessage(), PostMessage(), and using HWND_TOPMOST rather than HWND_BROADCAST as various web sources suggested and none of them worked on this platform. Actually changing the time, by calling SetSystemTime() did cause a WM_TIMECHANGE to be broadcast but my test process needed to run with the SE_SYSTEMTIME_NAME privilege enabled which was a pain and even then it just seems wrong to actually have to call SetSystemTime() (even if it was being called with the result of a call to GetSystemTime()).

Well, it seems that you CAN broadcast a WM_TIMECHANGE message if you do the broadcasting yourself using EnumWindows() where your enumProc simply calls SendMessage(hwnd, WM_TIMECHANGE, 0, 0); for each enumerated top-level window... This is actually a better solution as I don't really want to broadcast the message to all processes I just want to send it to all top-level windows in my process and I can do that by using GetWindowThreadProcessId() to filter the hWnds that I actually send to.

I get the feeling that this may stop working in the future though as I can't see any reason why broadcasting the 'proper' way is blocked and manually broadcasting would be allowed. Therefore I assume that, perhaps, my manual broadcast method has been missed and broadcasting of this message should actually be forbidden entirely... Unfortunately I can't find any docs which explain why my original attempts to broadcast the message don't work...

3 Comments

Hi Len,

You may want to watch out for daylight saving transitions, where a number of WM_TIMECHANGE are sent, sometimes up to 7, if I recall correctly.

I think there's supposed to be one to tell apps that the local time has changed, and one to tell them that the DST state has changed, or something, but it's not entirely clear.

We had some issues with this, but our situation was probably less clean than yours.

We ended up with a Nagle-like algorithm, where we waited up to 200 ms before processing the event, and swallowing any duplicates in the meantime. It was a mess.

Thanks for that Kim, I expect I'll need to do something similar as otherwise I'll end up setting and resetting timers multiple times.

I've yet to actually integrate the WM_TIMECHANGE watcher into the main code that needs it...

Kim, thanks again for that warning. I've added a configurable 'accumulation delay' and a WM_TIMER handler to allow for compressing multiple WM_TIMERCHANGE messages into one notification callback. This should deal with situations where multiple WM_TIMERCHANGE messages arrive in quick succession.

Leave a comment