views:

639

answers:

6

Hello all,

Can someone please point me to the easiest way to have a timer in a Win32 service?

I suppose I could create a dummy window for this purpose or have a second thread do tick counts, but what's best? Is there a more elegant way?

Thanks in advance.

+1  A: 

You can use SetTimer to set the timer, then catch the WM_TIMER message in your message loop.

Example:

// Set a timer to expire in 10 seconds

SetTimer(hwnd,IDT_TIMER1, 10000,(TIMERPROC) NULL);

... then in message loop:

switch (wParam)

{ 

    case IDT_TIMER1: 

        // Boom goes the dynamite

You can also decleare a function of type TIMERPROC and have that be called when the timer expires, if you don't want to do the message loop handling.

Steve
+1 for "boom goes the dynamite", but work a bit on your formatting
1800 INFORMATION
Thanks - there's no message loop in my service to catch the message though :)
dennisV
So create one! The message queue is set up by the os once you call ::GetMessage or ::PeekMessage.
Johann Gerell
+1  A: 

You can send your main thread WM_TIMER messages. The lParam for the message is the address of a callback function, or you can leave it NULL and handle it yourself in your message pump.

In this example, we are sending the timer to the thread message pump, there is no requirement to have a window associated with the timer.

UINT timer;

VOID CALLBACK Timer(HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime
)
{
  KillTimer(0, timer);
}

timer=SetTimer(0, // window handle
    0, // id of the timer message, leave 0 in this case
    10000, // millis
    Timer // callback
  );

// pump messages
while (GetMessage) etc...

The Timer callback will be called by DispatchMessage. This question reminded me of the recent ONT.

1800 INFORMATION
Thanks - I don't have a message loop unfortunately :)
dennisV
So create one! The message queue is set up by the os once you call ::GetMessage or ::PeekMessage.
Johann Gerell
+8  A: 

You can use Timer Queues (http://msdn.microsoft.com/en-us/library/ms686796.aspx). They don't require an HWND.

dpp
This sounds interesting, please provide an example
1800 INFORMATION
This works well, thanks!
dennisV
+3  A: 

Instead of using UI timers (even though you can use the NULL window handle as shown by Mr. 1800-INFO) you can use kernel waitable timer objects. See CreateWaitableTimer in the API docs. These can then be waited-on using WaitForSingleObject or WaitForMultipleObjects, etc, which is especially useful if that's already how your service waits for external events.

If it's not clear from that first link, the SetWaitableTimer function can associate a completion routine (user callback) with the timer. Remember to use the ...Ex versions of WaitForMultipleObjects (etc.) so that the thread is in an "alertable" state.

Adam Mitz
That sounds good - I went with the timer queues, but I'll read up on your link as well. Thanks!
dennisV
Thanks, I think TimerQueues may be overkill but it really depends on how the rest of your service is designed. If you want a ThreadPool thread to handle the timer event, TimerQueues would be great. If you already have a loop around WFMO or GetMessage then you could go with the other options.
Adam Mitz
A: 

Are you just trying to "wake up" every now and then to do some work? You can always use Sleep().

Additionally, I typically have a thread that is in a while(1 == 1) loop with a sleep inside. There I can check for the shutdown request and other misc housekeeping. You could use that system to tickle an event or mutex for the worker thread in the app.

John Dyer
No, the service is processing stuff in other threads, I just need to check the status of a few files every second.
dennisV
Probably overkill for you, but... You could use ReadDirectoryChangesW to 'listen' for changes to the files rather than polling them, it would likely be more efficient as you'd only wake up when there were changes to process rather than every 'x'ms... It's harder to set up though.
Len Holgate
+1  A: 

In one of your comments you said that "...the service is processing stuff in other threads, I just need to check the status of a few files every second."

Polling is not an optimal way of checking file status, and will adversely affect system performance. While there are (sometimes) problems doing this over networks, you should check out http://msdn.microsoft.com/en-us/library/aa364417(VS.85).aspx or http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx for how to do it and http://blogs.msdn.com/oldnewthing/archive/2006/01/24/516808.aspx for why you should.

David L Morris
Yes, thank you. I do know about those functions and you're probably right, I should be smarter and use them. Since I have no control over the file, I can only watch the file's size, but to be fair, I don't poll it continuously (only once a second).
dennisV