Python 3 executable as windows service

11,930

Solution 1

tldr Python 3.5 Windows Service build with pyinstaller : gist

Here a simple Windows Service with python :

WindowsService.py

import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil


class TestService(win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            with open('C:\\TestService.log', 'a') as f:
                f.write('test service running...\n')
            rc = win32event.WaitForSingleObject(self.hWaitStop, 5000)


if __name__ == '__main__':
    if len(sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(TestService)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(TestService)

Create an exe with pyinstaller (pip install pyinstaller) and python 3.5 :

(env)$ python -V
Python 3.5.2

(env)$ pip freeze
PyInstaller==3.2

(env)$ pyinstaller -F --hidden-import=win32timezone WindowsService.py

Install and run the service

(env) dist\WindowsService.exe install
Installing service TestService
Service installed

(env) dist\WindowsService.exe start
Starting service TestService

Check C:\\TestService.log file.

Stop and clean

(env) dist\WindowsService.exe stop
(env) dist\WindowsService.exe remove

Solution 2

I've edited the Win32Service.c in the cx_freeze src for python3 support

Edited it with some preprocessor commands, for python2 support too (but not tested for python2 yet)

  1. download sources of cx_freeze from pypi and extract it
  2. download cx_logging and extract it to the cx_freeze-4.3.4 directory
  3. replace the Win32Service.c file in cx_Freeze-4.3.4\source\bases with my edited version
  4. edit line 170 in setup.py from if moduleInfo is not None and sys.version_info[:2] < (3, 0): to if moduleInfo is not None:
  5. run python setup.py build in cx_freeze-4.3.4 directory (you must have MSC installed to compile the C source files)
  6. copy cx_Freeze-4.3.4\build\lib.win32-3.4\cx_Freeze\bases\Win32Service.exe to C:\Python34\Lib\site-packages\cx_Freeze\bases (or the path where your python3 is installed)
  7. now you can create frozen exe with the Win32Service base (no more the cx_Freeze.freezer.ConfigError: no base named Win32Service error)

Solution 3

It appears Win32Service was updated with Python 3.x support within the cx_Freeze project as a result of this thread. This user originally had the same issue you reported, so I'm assuming this will also resolve your issue.

Based on the error reported, it's caused when _GetBaseFileName() within Freezer.py fails to find the compiled Win32Service.exe. This executable should be built when cx_Freeze gets built/installed.

If it's not too much to ask, can search the installed cx_Freeze installation directory for "Win32Service.exe" and confirm that it exists. Hopefully this gets you one step closer.

Share:
11,930

Related videos on Youtube

AmitE
Author by

AmitE

Updated on June 04, 2022

Comments

  • AmitE
    AmitE almost 2 years

    I'm trying to write a windows Service in python, but the tricky part is i want to deploy it on a machine that doesn't have python. I've successfully created a service like this, and it works if i run from my machine. the problem starts when i try to convert it to an exe and then try to install it. first i tried to use cx_freeze service example, (seen here), the setup.py look like this :

    from cx_Freeze import setup, Executable
    
    options = {'build_exe': {'includes': ['ServiceHandler']}}
    
    executables = [Executable('Config.py', base='Win32Service', targetName='gsr.exe')]
    
    setup(name='GSR',
        version='0.1',
        description='GSR SERVICE',
        executables=executables,
        options=options
        )
    

    and config.py is:

    NAME = 'GSR_%s'
    DISPLAY_NAME = 'GSR TEST - %s'
    MODULE_NAME = 'ServiceHandler'
    CLASS_NAME = 'Handler'
    DESCRIPTION = 'Sample service description'
    AUTO_START = True
    SESSION_CHANGES = False
    

    but when i try to build it (python setup.py build) i get an error: "cx_Freeze.freezer.ConfigError: no base named Win32Service"

    Second, i tried using a regular cx_freeze setup, the exe i get installs the service fine but once i try to start it i get an error: "Error 1053: The service did not respond to the start or control request in a timely fashion"

    setup.py - python 3.3 regualr exe, installs the service but when trying to start it sends an error:

    from cx_Freeze import setup, Executable
    
    packages = ['win32serviceutil','win32service','win32event','servicemanager','socket','win32timezone','cx_Logging','ServiceHandler']
    build_exe_options = {"packages": packages}
    executable = [Executable("ServiceHandler.py")]
    
    
    setup(  name = "GSR_test",
            version = "1.0",
            description = "GSR test service",
            options = {"build_exe": build_exe_options},
            executables = executable)
    

    finally, I managed to get it to work in python 2.7 using py2exe, but py2exe isn't available for python 3.3 and I my code is in 3.3

    i guess the problem is in the configuration of the setup.py im using with cx_freeze. any ideas ??

    my ServiceHandler:

    import pythoncom
    import win32serviceutil
    import win32service
    import win32event
    import servicemanager
    import socket
    from test import test
    import threading
    
    class AppServerSvc (win32serviceutil.ServiceFramework):
        _svc_name_ = "GSR_test"
        _svc_display_name_ = "GSR test Service"
    
        def __init__(self,args):
            win32serviceutil.ServiceFramework.__init__(self,args)
            self.hWaitStop = win32event.CreateEvent(None,0,0,None)
            socket.setdefaulttimeout(60)
            self.app = test()
            self.flag = threading.Event()
    
        def SvcStop(self):
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
            win32event.SetEvent(self.hWaitStop)
            self.flag.set()
    
        def SvcDoRun(self):
            servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                  servicemanager.PYS_SERVICE_STARTED,
                                  (self._svc_name_,''))
            self.main()
    
        def main(self):
            t = threading.Thread(target=self.app.run)
            t.start()
            self.flag.wait()
            raise SystemExit
    
    if __name__ == '__main__':
        win32serviceutil.HandleCommandLine(AppServerSvc)
    

    Setup.py , python 2.7 using py2exe that works: (taken from here)

    from distutils.core import setup
    import py2exe
    
    setup(  service = ["ServiceHandler"],
            description = "SERVICE TEST",
            modules = ["GSR_test"],
            cmdline_style='pywin32', ) 
    

    Thanks, Amit

    • Thomas K
      Thomas K about 10 years
      The Win32service base only supports Python 2 at the moment. It's waiting for someone to add Python 3 support.
  • AmitE
    AmitE over 8 years
    While the base file seems to be updated if i try to freeze a service (using the provided example from cx_freeze) i'm still getting an error - cx_Freeze.freezer.ConfigError: no base named Win32Service. and indeed if I go and look at the bases folder (with the exe not the c file) it's still missing (no win32Service.exe).. maybe it just need to be compiled and someone fortgot. Using cx_freeze v4.3.4
  • ZachM
    ZachM over 6 years
    FYI a regular pip install of cx_Freeze won't have the cx_Logging folder in the folder above it, so the Win32Service base will not be compiled. If you download the source to both (to /tmp/cx_Freeze/ and /tmp/cx_Logging) then run python setup.py install on cx_Logging THEN cx_Freeze, you'll end up with the Win32Service base.
  • tulsluper
    tulsluper over 6 years
    It really works! Thank you! (Python 3.6.3, PyInstaller==3.3)
  • shasan
    shasan almost 5 years
    How is TestService linked to the main application script?