Problem Statement
Creating a Windows service in Python is a common task, often facilitated by numerous code examples available online and tools like Chart GPT. However, a significant challenge arises when attempting to access or start Windows processes within the context of a Windows service. The primary complication stems from the fact that services run under the Local System authority, introducing permission constraints that can hinder the seamless execution of certain tasks.
Introduction
Windows services provide a powerful mechanism for running background tasks that do not require user interaction. In Python, the win32serviceutil module, part of the pywin32 library, allows developers to create and manage Windows services seamlessly. In this article, we'll explore a Python script that utilizes win32serviceutil to create a simple Windows service.
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import os
import time
class MyService(win32serviceutil.ServiceFramework):
    _svc_name_ = 'MyService'
    _svc_display_name_ = 'My Service'
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(120)
        self.is_alive = True
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.is_alive = False
    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_, ''))
        self.main()
    def main(self):
        # Main service logic goes here
        while self.is_alive:
            # Perform your service tasks here
            time.sleep(5)  # Example: Sleep for 5 seconds
if __name__ == '__main__':
    if len(os.sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(MyService)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(MyService)
Understanding the Python Script:
Let's break down the provided Python script, which serves as the foundation for our Windows service.
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import os
import time
These import statements include essential modules such as win32serviceutil, win32service, win32event, servicemanager, socket, os, and time. These modules collectively provide the necessary tools for creating and managing Windows services.
class MyService(win32serviceutil.ServiceFramework):
    _svc_name_ = 'MyService'
    _svc_display_name_ = 'My Service'
Here, a class named MyService is defined, inheriting from win32serviceutil.ServiceFramework. This class represents our custom Windows service. The _svc_name_ attribute defines the service name, and _svc_display_name_ sets the display name visible in the Windows Services manager.
def __init__(self, args):
    win32serviceutil.ServiceFramework.__init__(self, args)
    self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
    socket.setdefaulttimeout(120)
    self.is_alive = True
The __init__ method initializes the service. It creates an event (hWaitStop) that signals the service to stop when set. The socket.setdefaulttimeout(120) line sets the default timeout for socket operations, and self.is_alive tracks whether the service is running.
def SvcStop(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    win32event.SetEvent(self.hWaitStop)
    self.is_alive = False
The SvcStop method is called when the service is stopped. It reports the stop status and signals the hWaitStop event.
def SvcDoRun(self):
    servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                          servicemanager.PYS_SERVICE_STARTED,
                          (self._svc_name_, ''))
    self.main()
The SvcDoRun method is the main entry point for the service. It logs a service start message and calls the main method.
def main(self):
    # Main service logic goes here
    while self.is_alive:
        # Perform your service tasks here
        time.sleep(5)  # Example: Sleep for 5 seconds
The main method contains the core logic of your service. In this example, it includes a loop simulating a service that performs tasks every 5 seconds.
if __name__ == '__main__':
    if len(os.sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(MyService)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(MyService)
Finally, the script checks whether it's being run as a standalone application or imported as a module. If run standalone, it initializes and starts the service using servicemanager.
Conclusion:
This script provides a template for building Windows services in Python using win32serviceutil. Customize the main method to implement your service's specific functionality. In subsequent articles, we'll explore service installation, execution, and management.
Stay tuned for more on mastering Windows services with Python Part II
 

 
    
Top comments (6)
"Finally, the script checks whether it's being run as a standalone application or imported as a module". Really? Isn't it just checking if it is being called with or without a parameter ?
Why is the init needed at all? Doesnt't the base class already do that?
When I started implementing a windows service using pywin32, this is the boilerplate code you could get easily with a google search. The main intricacies lies in setting up the service to run correctly with dependencies, etc.
Hi. Help please.
I got error code: pywintypes.error: 1063, 'StartServiceCtrlDispatcher'
How are you Starting your window service please, are you using the below command
python servioce.py install?
python servioce.py start
Very good. Where can I read Part II?