Problems on Windows Service written in python and py2exe
Question: I've written a service for Windows:

**agentservice.py**

    
    
    import win32serviceutil
    import win32service
    import win32event
    import win32evtlogutil
    import agent
    
    class AgentService(win32serviceutil.ServiceFramework):
        _svc_name_ = "AgentService"
        _svc_display_name_ = "AgentService"
        _svc_deps_ = ["EventLog"]
        def __init__(self, args):
            win32serviceutil.ServiceFramework.__init__(self, args)
            self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
    
        def SvcRun(self):
            import servicemanager
            agent.verify()
            # Write a 'started' event to the event log...
            win32evtlogutil.ReportEvent(self._svc_name_,servicemanager.PYS_SERVICE_STARTED,0,     servicemanager.EVENTLOG_INFORMATION_TYPE,(self._svc_name_, ''))
    
            # wait for beeing stopped...
            win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
    
            # and write a 'stopped' event to the event log.
            win32evtlogutil.ReportEvent(self._svc_name_,servicemanager.PYS_SERVICE_STOPPED,0,
    servicemanager.EVENTLOG_INFORMATION_TYPE,(self._svc_name_, ''))
    
        def SvcStop(self):
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
            win32event.SetEvent(self.hWaitStop)
    
    
    if __name__ == '__main__':
        win32serviceutil.HandleCommandLine(AgentService)
    

then **agent.py**

    
    
    import os
    import socket
    import time
    import json
    import platform
    PLATFORM = platform.system()
    import uuid
    import sys
    
    
    HOST = 'highwe.net'
    PORT = 8302
    USERKEY = None
    
    
    def getHoldHost():
        hold_host = os.environ.get('HOLDHOST')
        if hold_host is None:
            return HOST
        return hold_host
    HOST = getHoldHost()
    
    
    def macAddress():
        return ':'.join(['{:02x}'.format((uuid.getnode() >> i) & 0xff) for i in range(0, 8 * 6, 8)][::-1])
    
    
    def getRelease():
         '''Get OS info'''
        release = ''
        if PLATFORM == 'Windows':
            release = osAction("ver").decode('gbk')
        return release
    
    
    def getExpInfo(just_info=False):
        '''Get Exception'''
        import traceback
        if just_info:
            info = sys.exc_info()
            return info[0].__name__ + ':' + str(info[1])
        else:
            return traceback.format_exc()
    
    
    def osAction(command):
        '''
        run command
        '''
        try:
            p = os.popen(command)
            content = p.read()
            p.close()
        except Exception:
            content = 'djoin_error:' + getExpInfo(True)
        return content
    
    def socketAgent():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((HOST, PORT))
        return sock
    
    def diskMon():
        mon_data = None
        if PLATFORM == 'Windows':
            disk = osAction("wmic logicaldisk get caption, size, freespace, drivetype")
            mon_data = dict(disk=disk)
        else:
            pass
        return mon_data
    
    def send():
        mac = macAddress()
        release = getRelease()
        try:
            sock = socketAgent()
            while True:
                if disk:
                    message = json.dumps(dict(user_key=USERKEY, platform=PLATFORM, mac=mac, release=release, mon_data=disk, type="disk")) + '\u7ed3\u675f'
                    sock.send(message)
                    print '%s send disk' % PLATFORM
                time.sleep(5)
        except socket.error:
            error_info = getExpInfo(True)
            print HOST
            print error_info
            time.sleep(5)
            send()
    
    def verify():
        global USERKEY
        with open('agent.conf', 'r') as f:
            out_data = f.read()
            USERKEY = json.loads(out_data).get('user_key')
        #print 'start...'
        agentPid = os.getpid()
        writePid(agentPid)
        send()
    
    def writePid(pid):
        pid = str(pid)
        with open('pid.config','w') as f:
            f.write("%s\n" % pid)
    
    if __name__ == '__main__':
        pass
    

Note: agent.conf is also in current directory.

**agent.conf** :

    
    
    {"user_key": "cd7eab88-3055-4b1d-95a4-2ad80731d226"}
    

and my **setup.py** is:

    
    
    from distutils.core import setup
    import py2exe
    import sys
    
    sys.argv.append("py2exe")
    
    setup(service = ["agentservice"])
    

after I am run :

    
    
     python setup.py
    

there is a agentservice.exe in ./dist directory. And run:

    
    
    agentservice.exe -install 
    

and everything is fine and the service appears in the Windows service list .it
success installed.

But what confused me is : why my service can't start and stop normally? Is
there any bugs in my code?

Any help would be greatly appreciated.


Answer: > Note: agent.conf is also in current directory.

How? The current directory is the directory you're in when you start the
program. The working directory for a service is usually your System32
directory, the working directory at the time you install is the `dist`
directory under your project, and presumably the working directory for the
client script is the top level of your project. Unless you've created a
hardlink/junction, the file isn't in all three places.

If you want to find a file that's in the _script's_ directory, you have to do
that explicitly. You can change the current directory to the script's
directory at startup, or configure the service to run from the script's
directory instead of the default location—or, better, you can ignore the
current working directory; get the script directory at startup with
`os.path.abspath(os.path.dirname(sys.argv[0]))` and then `os.path.join` that
to the path.

But in your case, you're already using a proper `setup.py`, so what you really
want to do is include the file as a data or extra file in your package and use
[`pkg_resources`](https://pythonhosted.org/setuptools/pkg_resources.html) to
locate it at runtime. (It's possible that `py2exe` has its own variation that
supersedes the `setuptools` stuff. If so, use that instead, of course.)

