2

I first posted an answer in this post, but it didn't conform to the forum standards. I hope this time te answer fits the forum standards. This code should be more clear and easy to read.

In Python 3+ I have the following class that I use to build a Windows Service (it does nothing, just writes a log file):

#MyWindowsService.py
import win32serviceutil
import servicemanager
import win32service
import win32event
import sys
import logging
import win32api


class MyWindowsService(win32serviceutil.ServiceFramework):
    _svc_name_          = 'ServiceName'
    _svc_display_name_  = 'Service Display Name'
    _svc_description_   = 'Service Full Description'
    logging.basicConfig(
        filename    = 'c:\\Temp\\{}.log'.format(_svc_name_),
        level       = logging.DEBUG,
        format      = '%(levelname)-7.7s @ %(asctime)s: %(message)s'
    )

    def __init__(self, *args):
        self.log('Initializing service {}'.format(self._svc_name_))
        win32serviceutil.ServiceFramework.__init__(self, *args)
        self.stop_event = win32event.CreateEvent(None, 0, 0, None)

    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
        try:
            self.log('START: Service start')
            self.ReportServiceStatus(win32service.SERVICE_RUNNING)
            self.start()
            win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
        except Exception as e:
            self.log('Exception: {}'.format(e))
            self.SvcStop()

    def SvcStop(self):
        self.log('STOP: Service stopping...')
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        self.stop()
        win32event.SetEvent(self.stop_event)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)

    def log(self, msg):
        servicemanager.LogInfoMsg(str(msg))  #system log
        logging.info(str(msg))               #text log

    def start(self):
        self.runflag = True
        while self.runflag:
            win32api.Sleep((2*1000), True)
            self.log('Service alive')
    def stop(self): 
        self.runflag = False
        self.log('Stop received')




if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(MyWindowsService)

In the script I use a log file to check if it's working properly. I'm running python3.6 (also tried with python3.4) on Windows 7 and I'm experiencing the following problem. When I run python MyWindowsService.py install the prompt says that the service has been installed (but nothing is written in the log file). If I try to start the service, I get Service Error: 1 - More info NET HELPMSG 3547 which doesn't say much about the error. If I run python MyWindowsService.py debug, the program runs just fine (the log file is written), but still I don't have any control over the service: if I open another prompt and try to stop/start the service I still got the same results as stated above.

I also tryed to insert some debug code inside the init function, and when I run python MyWindowsService.py install it seems it doesn't get called. Is it possible?

I've checked for multiple solution and workarounds around the net, but I didn't find anything suitable. What am I missing?

Cœur
  • 32,421
  • 21
  • 173
  • 232
jekbau
  • 41
  • 8
  • Try starting the service using `sc start ServiceName`. That may provide more information. Also, query the configuration with the command `sc qc ServiceName`. This should show the fully-qualified path to "PythonService.exe". Check whether you can run it in the command prompt. If not, make sure that "python36.dll", "vcruntime140.dll", and "pywintypes36.dll" are either symlink'd to the directory that has PythonService.exe; or symlink'd to the System32 directory; or that the directories with these DLLs are in the system (not user) `Path`. – Eryk Sun Mar 04 '17 at 20:06
  • Hi eryksun, thanks for your interest. – jekbau Mar 04 '17 at 21:26
  • I checked for the dlls you mentioned and added their directory to the system path - nothing changed. `sc start ServiceName` returns `STATUS 2 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)` I also added "PythonService.exe" path to System Path - just in case, but again, nothing happened. – jekbau Mar 04 '17 at 21:34
  • That's normal. Follow up with `sc query ServiceName` to see the current status. Then stop it with `sc stop ServiceName`. – Eryk Sun Mar 04 '17 at 23:30
  • `sc query ServiceName` returned `STATUS: 1 STOPPED`, `WIN32_EXIT_CODE : 1066` `sc stop ServiceName` returned `FAILED 1062: Service not started` – jekbau Mar 04 '17 at 23:39
  • 1066 is `ERROR_SERVICE_SPECIFIC_ERROR`. What's the value of `SERVICE_EXIT_CODE` in this case? – Eryk Sun Mar 04 '17 at 23:51
  • The value is: 1 (0x1) – jekbau Mar 05 '17 at 00:02
  • That's just a generic failure code. Is it able to write anything into "C:\Temp\ServiceName.log" when run as a service? – Eryk Sun Mar 05 '17 at 00:30
  • Just to clarify in case you suspect there's a problem with the script, it works fine for me using Python 3.6 in Windows 10. I can start and stop the service without error. – Eryk Sun Mar 05 '17 at 00:32
  • Thank you, I imagined that this has to be with my configuration because I checked the code multiple times and simplyfied that and also taken some hints from others working code. When i run `python MyWindowsService.py install` it just creates the C:\Temp\ServiceName.log file, but nothing is written on it. Every other operation does nothing on the file. – jekbau Mar 05 '17 at 00:39
  • We know PythonService.exe isn't immediately failing, else the service controller would report `ERROR_SERVICE_REQUEST_TIMEOUT`. Try deleting the log file and then run `sc start ServiceName`. Does the log file get created in this case? If not, PythonService.exe doesn't appear to be running MyWindowsService.py at all. Check the service registry key. Run `reg query HKLM\System\CurrentControlSet\Services\ServiceName /s` to print it to the command prompt. What's the default value for the `PythonClass` subkey? It should be something like `path\to\mywindowsservice.MyWindowsService`. – Eryk Sun Mar 05 '17 at 01:05
  • After deleting the log file and running `sc start ServiceName`, nothing happens. This is the register: `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\ServiceName Type REG_DWORD 0x10 Start REG_DWORD 0x3 ErrorControl REG_DWORD 0x1 ImagePath REG_EXPAND_SZ "C:\Users\jek\AppData\Local\Programs\Python\Python36\lib\site-packages\win32\PythonService.exe" DisplayName REG_SZ Service Display Name ObjectName REG_SZ LocalSystem Description REG_SZ Service Full Description` – jekbau Mar 05 '17 at 01:53
  • And... `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\ServiceName\PythonClass (Predefinito) REG_SZ F:\python\allegati\ctrl\MyWindowsService.MyWindowsService` – jekbau Mar 05 '17 at 01:53
  • Is drive "F:" a physical drive or a mapped UNC path? If it's the latter the problem is probably that mapped drives are created for a user's logon session. The service is running as SYSTEM, which doesn't have a mapped drive named "F:". In this case, run `sc delete ServiceName` and reinstall by running the script using the UNC path, e.g. `python \\Server\share\python\allegati\ctrl\MyWindowsService.py install`. This may fail too if accessing the UNC share requires credentials that are cached in your user's logon session. It would be simpler to copy the script to a local drive. – Eryk Sun Mar 05 '17 at 02:07
  • Game, set and match. You really made my day. One day I will clean all the mess I've done in 48 hours of changing all the settings in Path variables and so on. Really interesting I didn't find any mention of this issue before. As soon as possible I will update the post with the solution. Thank you eryksun, you made my day and my week. – jekbau Mar 05 '17 at 02:35

1 Answers1

2

As pointed out by eriksun in the comment to the first post, the problem came from the location of the python script, that was in a drive mapped with an UNC path - I'm working with a virtual machine. Moving the python script in the same drive as the python installation did the job. To sum it up for future uses, if the service fails to start and you're pretty sure about your code, these are helpful actions to try and solve your issues:

  • use sc start ServiceName, sc query ServiceName and sc stop ServiceName to get info about the service.
  • check if your file is in a physical drive or in a UNC-mapped drive. If the latter try to run the script using the UNC path (for example python \\Server\share\python\your-folder\script.py) or move your script in the same drive as the python installation
  • make sure that "python36.dll", "vcruntime140.dll", and "pywintypes36.dll" are either symlink'd to the directory that has PythonService.exe; or symlink'd to the System32 directory; or that the directories with these DLLs are in the system (not user) Path
  • Check the system register with command reg query HKLM\System\CurrentControlSet\Services\your_service_name /s to get more information about the script

PLease, feel free to complete, change, modify the last so that it can be usefull for anyone that like me encounder this issue.

EDIT: One more thing... My project was thought to work actually with network folders (and UNC-mapped drive) and it failed when I tried to make it run as service. One very useful (day-saving) resource that I used to make it work is the SysinternalsSuite by Mark Russinovich that I found in this post. Hope this helps.

Community
  • 1
  • 1
jekbau
  • 41
  • 8