How do I call SetTimer with a timer ID that is guaranteed not to conflict with any other timer ID?


Suppose you want to create a timer for a window, but you don't know what timers that window already has running. You don't want your timer to overwrite any existing timer, so you need to find a unique ID for your timer. If this were for a window message, you could use Register­Window­Message, but there is no corresponding Register­Timer­Id function. How do you generate a unique timer ID?

Every window gets to decide how to assign its own timer IDs, which are 32-bit integers on 32-bit Windows or 64-bit integers on 64-bit Windows. If you are an outsider, then you will have to negotiate with the window for a timer ID. There is no standard for this, so you will have to talk to whoever wrote the code for the window and come to some sort of agreement. "Okay, Bob, I'll let you have timers in the range 1000 to 1999."

But what if you don't personally know the person who wrote the code for the window, and the documentation for the window class does not specify how to negotiate a timer ID?

If you don't have a way to negotiate a timer ID for a window, then just create your own window and put your timer there. Since you created your own window, you control the window class, and you can set the rules for how timer IDs are assigned for that window class.

It's hardly a coincidence that the timer ID space is the same size as the address space. You can allocate some memory to track the timer (you probably have already done this), and use the address of that memory as the timer ID. Another common design is to use the handle to the object associated with the timer as the timer ID.

Comments (8)
  1. Joshua says:

    And then you get to interact with my code. If I only placed 1 timer on my Window (the usual case), WM_TIMER isn't going to look at TimerId at all.

  2. Ben Voigt says:

    @Joshua: Not an issue, your code never sees their timer callback.  Either they used a timer procedure, or subclassed your window procedure and didn't forward it to you.

    If your code sees it, it means it didn't reach the code meant to handle it.

  3. Someone says:

    @Ben Voigt: Actually it can be an issue, I came across it once (had to debug it to figure out what went wrong). Some third party control created a global refresh timer without checking the timer ID and ended up reacting to unrelated timers. Can't remember how exactly the timers were configured though. There may have been global hooks involved in the controls implementation, it was an onscreen keyboard control. We ended up not buying that control ;)

    [Strange, because both of the standard ways of doing this avoid letting the original window procedure see the unknown timer message. You can register your timer with a TIMERPROC, in which the message is handled inside Dispatch­Message and never reaches the window procedure; or you subclass the window and pick off the timer without forwarding to the original window procedure. If they installed a global hook, then they will see all sorts of timers they didn't create, so that can't be it either. Unless they also assumed that there were no other windows on their thread? -Raymond]
  4. Ben Voigt says:

    @Someone: Ahh, well that's not your code seeing their timer, it is their code seeing your timer.  The subclass procedure definitely needs to be written to forward timers it doesn't own to the original window procedure.

  5. parkrrrr says:

    My guess: they handled WM_TIMER inside the message loop for some (probably bad) reason, rather than calling DispatchMessage and handling it in the window proc. Hope they never create any modal dialogs.

  6. boogaloo says:

    @parkrrrr: They might have done it on purpose so that the timer didn't do anything when a modal dialogue was up. Quite a few programmers don't expect their timers to fire when a message box is up for instance, it's quite funny when they put up a message box from the timer and their screen gets filled with them.

  7. Someone says:

    @Raymond: They probably tested their onscreen keyboard mostly as a standalone process or in simple test programs, never in a real application, even though usage as embedded control was a supported and advertised configuration (and the one we were looking for at that time). That's the only way I can imagine someone coming up with something that broken. We sent them a bugreport but never heared back from them.

  8. Cowardly Anon Moose says:

    > It's hardly a coincidence that the timer ID space is the same size as the address space.

    So someone intentionally designed it this way?

Comments are closed.

Skip to main content