Link to home
Start Free TrialLog in
Avatar of wzhxxj
wzhxxj

asked on

Stopping a service thats in a timed loop

I have coded an NT service whose function is to send a data string to a network device on a timed interval.  The timed interval is typically set to 30 seconds or more.  My problem is that if an NT service takes longer than 3 seconds to shutdown, the Service Control Manager thinks that the service has stopped responding.  I am using the sleep() function to wait for the specified interval.  If I stop my service from the Services applet in Control Panel while the service is in the sleep state, it typically takes longer than 3 seconds and I get the message, "Service not responding to the control function".  I also tried to use SetWaitableTimer( compiled and linked ok ) but the damn thing would not trigger my function to execute.(??) It seems I have to change my program design a bit but what's the best way to do it.  Should I be using SetWaitableTimer - I've never used it before so anyone with experience, your input is appreciated?
ASKER CERTIFIED SOLUTION
Avatar of xyu
xyu

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of WDB
WDB

Use SetTimer() with your specified interval. This will cause no problems and will work every time. Also, your service will shut down correctly whenever it's told to. I have written a service just like yours and I use SetTimer() to control my exporting of data. It works great! This way you won't need to worry about having separate threads. Hope this helps!
WDB... SetTimer???? in NT Service???? i like to see that :)
WDBm have You ever wrote NT service????
I've written many NT services. Many of which are "Back Channel" type "FTP" data transferers. They use SetTimer() extensively. Whats the big secret xyu?????? xyu have You ever written an NT service??????
To WDB.  Excuse me sir, but how You wold like to receive WM_TIMER notification in windowless process?
I wrote as minimum 3 NT services for RealTime Automated Factory Control.
To XYU. Who says I need to receive any WM_TIMER messages?? The timers I use have callback methods. And who says that an NT service has to be windowless?? In fact, I've written at least 2 NT services that interact with the desktop and they both have windows (The topmost level is hidden of course) and icons placed in the system tray!
To allow Your NT service interact with Desktop You have to always run it under SYSTEM account and give permission to interract with desktop... more than that Microsoft recomends that You will make such a services only if You really need it to interact with desktop... !!!! NT Service is windowless by definition... (or recommendation) :)
about WM_TIMER message ok... You can call SetTimer and specify TimeProc callback... but!!!! if Your application doesn't have any message loops i'm not sure You will receive control to that callback... :) as minimum i tried it on console application and never received it :( ...

meanwhile...NT Service it is something that You control via Control Panel/Services ... and with is registered at \\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services and this something survives logout of the user unlike usual application... etc.
I wrote it just to clear definition of NT Service between us :)
To XYU.
1. I agree that if you don't have windows or message loops then using a timer is impossible. However, if you are using windows and messaging loops than there is absolutely nothing wrong with using timers to handle certain tasks.

2. When a service interacts with the desktop it will be available for regular users. This is the reason that I had it interact with the desktop. Most of the time when a regular user is logged on to NT they will NOT have access to the service control manager. I needed to write a service that would be accessable to a regular user (To make supporting our software easier). This service needed to have the ability to be stopped and/or restarted by a regular user in the form of menus and dialog boxes etc.. that would be accessable from the service's icon in the system tray. This would make troubleshooting any problems that might occur with it much easier.

3. I don't agree that a Windows NT Service is windowless by definition, however I do agree that it is so by recommendation. I can tell you that I've gone against Microsoft recommendations in the past and I'm sure I will in the future and I know that I'm not alone in this matter.

4. Back to the original question from wzhxxj. If his service uses message loops and/or windows then, in my opinion, SetTimer() would be the best solution. If he doesn't then the 2 thread approach would be the only other solution. I hope you agree with this xyu :)

To XYU.
1. I agree that if you don't have windows or message loops then using a timer is impossible. However, if you are using windows and messaging loops than there is absolutely nothing wrong with using timers to handle certain tasks.

2. When a service interacts with the desktop it will be available for regular users. This is the reason that I had it interact with the desktop. Most of the time when a regular user is logged on to NT they will NOT have access to the service control manager. I needed to write a service that would be accessable to a regular user (To make supporting our software easier). This service needed to have the ability to be stopped and/or restarted by a regular user in the form of menus and dialog boxes etc.. that would be accessable from the service's icon in the system tray. This would make troubleshooting any problems that might occur with it much easier.

3. I don't agree that a Windows NT Service is windowless by definition, however I do agree that it is so by recommendation. I can tell you that I've gone against Microsoft recommendations in the past and I'm sure I will in the future and I know that I'm not alone in this matter.

4. Back to the original question from wzhxxj. If his service uses message loops and/or windows then, in my opinion, SetTimer() would be the best solution. If he doesn't then the 2 thread approach would be the only other solution. I hope you agree with this xyu :)

I think, that if You need to give user interaction with the service.. You have to give him client application...
What happend if one user forgot to close the service dialog while logging out... and than another user logged in???
will he be able to see the dialog from the previous user?
User interaction will be rare but it needs to be there. The user interaction consists of stopping the service, restarting the service and viewing an error log. The only dialog that could remain visible would be the error log dialog. As you can see, the situation that you stated, or any other situation for that matter, will never cause a problem with this service. The services I've created have been running for over a year and they have been practically flawless. There have only been 2 or 3 cases where the user interface needed to be used and we have hundreds of users using the service 1000's of times a day. Managing a service is a heck of a lot easier than having to worry about a client app. The ability to have windows etc.. in a service is there for a reason!!
Avatar of wzhxxj

ASKER

Xyu, if I set ServiceStatus.dwWaitHint to 30 seconds or more, then I am sure that after this interval, my service probably would have exited the sleep() function and stopped without an error from the SCM.  

I found a better way.  I used the WaitForSingleObject() with a timeout of 30 and supplied it the handle of my service stop event object, which I created.  My service thread consumes very little processor time while waiting for the event object state to become signaled or the time-out interval to become elapsed. When running, the WaitForSingleObject()function would continually timeout, giving me my 30 second timer.  When I stopped my service, I signaled the service stop event object with SetEvent() which causes my WaitForSingleObject() function to return, thereby terminating my timer immediately.  This allowed me to shut my service down without putting any delays in it.  Works beautifully and I didn't need multi-threads.

The comments I received from xyu and wdb were great.  Both of you guys obviously have a lot of experience with coding services.
ps: I also tried using SetTimer with a callback function but that didnt't work - probably because my app is windowless and doesn't use message queues.(?)