4

I've checked at least a couple of dozen of similar cases to mine and still haven't come up with a solution, I hope someone can shed some light, there's gotta be something I'm missing here.

I'm using Python3.6 to make a Windows service, the service has to run a .exe file if it's not running. Here's the .py:

import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import psutil
import subprocess
import os, sys, string, time
import servicemanager


class SLAAgent (win32serviceutil.ServiceFramework):
    _svc_name_ = "SLAAgent"
    _svc_display_name_ = "SLAAgent"

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

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

    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
        self._logger.info("Service Is Starting")
        main(self)

    def main(self):
        while self.isAlive:
            rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
            # Check to see if self.hWaitStop happened
            if rc == win32event.WAIT_OBJECT_0:
                servicemanager.LogInfoMsg("SLAAService has stopped")  #For Event Log
                break
            else:
                try:
                    s = subprocess.check_output('tasklist', shell=True)
                    if "SLA_Client.exe" in s:
                        pass
                    else:
                        pass
                        #execfile("SLA_Client.exe") #Execute the script
                except:
                    pass

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

I've installed the pywin32 package, added those to the PATH since it was suggested in several solutions, and also copied the .dll from pywin32_system32 to win32

Environment variables Environment variables

Event Viewer Error Event Viewer Error

The Event Viewer prints this error every time I run it be it python service.py, or python service.py start, console also prints this:

python SLA_Agent.py
Traceback (most recent call last):
  File "SLA_Agent.py", line 56, in <module>
    servicemanager.StartServiceCtrlDispatcher()
pywintypes.error: (1063, 'StartServiceCtrlDispatcher', 'The service process 
could not connect to the service controller.')

When trying to start the service from the Services tool this is the error that pop ups. I've seen the other error too, the oneabout the service not responding in time.

Services error when running

I've tried compiling it with pyinstaller and nuitka, the errors are the same. I'm unsure as to how to proceed, I've changed the code to fit examples and solutions I've found using google and SO, and have gained little understanding of the hows and whys.

If anyone has faced these issues before, I'd really appreciate the input, other answers haven't helped me so far.

Late edit: fixed the code indentation

danks
  • 103
  • 1
  • 10
  • I assume the code under `if __name__ == '__main__':` should be indented. – Martin Evans May 29 '18 at 19:11
  • 1
    Create the `.exe` using `pyinstaller` -- Then do `my_service.exe debug` to run the service and see it execute in your console. If that works, then do `my_service.exe install` to install the service. You should see it in list of services. Then `my_service.exe start` to start it (or use services gui). Pretty sure it's not related, but a common thing I've needed to do is specify win32timezone as a hidden import for pyinstaller. – sytech May 29 '18 at 19:15
  • @sytech I'll be trying that and will let you know soon, but that's pretty much what I was doing before MartinEvans it should be indented to the same level of the class class SLAAgent, otherwise PrepareToHostSingle will complain about SLAAgent not being defined. – danks May 29 '18 at 20:30
  • I'm sure you've seen this, since the code looks a lot like it, but I used this http://ryrobes.com/python/running-python-scripts-as-a-windows-service/ pretty much as is to successfully run a service in Windows 7 adn python2. Also, might want to add `pywin32` tag. I'm sure people sometimes search that tag to try answer questions. – Daniel F. May 30 '18 at 04:11
  • @DanielF. yeah, I did find that code and built a bit upon it. I must be doing something wrong, today I'll have the chance to try the service in another computer without Python installed – danks May 30 '18 at 13:41
  • @sytech I was able to start the service that way once in my computer, and then the same error started popping up again. As I mentioned in my last comment, I'll try installing the serivce on another PC later today, since I used pyinstaller --onefile it should work without Python being installed right? – danks May 30 '18 at 13:42
  • @danks When using pyinstaller --onefile (and one directory for that matter) yes, it should work like a stand alone program. No need to install anythig else. – Daniel F. May 30 '18 at 20:53

1 Answers1

5

This ended up working for me, other than the difference in the code I didn't really do anything special, after a few tries I got to compile with pyinstaller and run service.exe install without issues. There are some extra logging lines that people might not need, but they came in handy when debugging and testing.

Thanks a lot to the everyone who left comments, they were extremely helpful and couldn't have done it without you <3

import win32service, win32serviceutil, win32api, win32con, win32event, win32evtlogutil
import psutil
import subprocess
import os, sys, string, time, socket, signal
import servicemanager

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

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self, *args)
        self.log('Service Initialized.')
        self.stop_event = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)


    def log(self, msg):
        servicemanager.LogInfoMsg(str(msg))

    def sleep(self, sec):
        win32api.Sleep(sec*1000, True)

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

    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
        try:
            self.ReportServiceStatus(win32service.SERVICE_RUNNING)
            self.log('Service is starting.')
            self.main()
            win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
            servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
        except Exception as e:
            s = str(e);
            self.log('Exception :'+s)
            self.SvcStop()

    def stop(self):
        self.runflag=False
        try:
            #logic
        except Exception as e:
            self.log(str(e))

    def main(self):
        self.runflag=True
        while self.runflag:
            rc = win32event.WaitForSingleObject(self.stop_event, 24*60*60)
            # Check to see if self.hWaitStop happened
            if rc == win32event.WAIT_OBJECT_0:
                self.log("Service has stopped")
                break
            else:
                try:
                    #logic
                except Exception as e:
                    self.log(str(e))

if __name__ == '__main__':
    if len(sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(Service)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(Service)
danks
  • 103
  • 1
  • 10