Chris Umbel

Windows Services in Python

Any more it seems that virtually all the code I write on the windows platform ends up being a windows service. It's just the nature of the kind of work I do: the underappreciated guts that sit far beneath the software that users directly interact with. Obviously windows services are typically written in mainstream .Net languages like C# or VB these days but it's also easy if not easier to do in Python.

Requirements

  • A Python Interpreter - this one's pretty obvious. Can't run Python code without a Python interpreter.
  • Python for Windows Extensions - this is a wonderful, easy to install project that exposes the innards of windows to Python.
  • Administrative access - you must be logged in with administrative access in order to install your service.

The Code

Once your Python environment meets the requirements outlined above you're ready to write your service. All you have to do is write an extension of the ServiceFramework class that overrides the SvcDoRun and SvcStop methods. As you can guess SvcDoRun performs the core logic of your service and SvcStop shuts it down.

I've created a sample service below that simply writes some text to a file every five seconds until the service is stopped. Note that this example uses windows signal events to trigger service shutdown via the CreateEvent, WaitForSingleObject and SetEvent windows API calls. Thank you Windows Extensions!

import win32service
import win32serviceutil
import win32event

class PySvc(win32serviceutil.ServiceFramework):
    # you can NET START/STOP the service by the following name
    _svc_name_ = "PySvc"
    # this text shows up as the service name in the Service
    # Control Manager (SCM)
    _svc_display_name_ = "Python Test Service"
    # this text shows up as the description in the SCM
    _svc_description_ = "This service writes stuff to a file"
    
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        # create an event to listen for stop requests on
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
    
    # core logic of the service   
    def SvcDoRun(self):
        import servicemanager
        
        f = open('test.dat', 'w+')
        rc = None
        
        # if the stop event hasn't been fired keep looping
        while rc != win32event.WAIT_OBJECT_0:
            f.write('TEST DATA\n')
            f.flush()
            # block for 5 seconds and listen for a stop event
            rc = win32event.WaitForSingleObject(self.hWaitStop, 5000)
            
        f.write('SHUTTING DOWN\n')
        f.close()
    
    # called when we're being shut down    
    def SvcStop(self):
        # tell the SCM we're shutting down
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        # fire the stop event
        win32event.SetEvent(self.hWaitStop)
        
if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(PySvc)

Service Installation

Now that the service itself is written we can install it as follows:

C:\Dev\Projects\PySvc> python.exe .\PySvc.py install

Service Control

That's it! The service can now be started from the command line by

C:\Dev\Projects\PySvc> NET START PySvc

or from the Service Control Manager

Mon Nov 02 2009 20:11:00 GMT+0000 (UTC)

Follow Chris
RSS Feed
Twitter
Facebook
CodePlex
github
LinkedIn
Google