[python-win32] Re: Windows service features and Python

Imre András Róbert beast at ludens.elte.hu
Thu Aug 5 21:57:35 CEST 2004


Hello list,

I always forgot attaching what I promise...

Sorry,
  András
  

Thursday, August 5, 2004, 9:48:06 PM, you wrote:

> Hello list,

> I'm transforming some Python code into a Windows
> service. I started with pywin32-202.win32-py2.2.exe,
> and investigated the demo pipeTestService. This
> worked fine, so I started converting my code, with
> no paticular Windows system programming experience.

> After reading through the help, the newsgroups and
> searching on the web, I still have the following questions:

> Q1) How can I make my Python service support pause/
>     continue? Implementing SvcPause() and SvcContinue()
>     seems to be not enough, as I get 'Could not pause
>     ... service on Local Computer. The service did not
>     return an error. ...' dialog despite that the
>     SvcPause() method is executed. After this dialog
>     I found that the service was stopped, ending within
>     SvcDoRun(). Please refer to the attached code.

> Q2) How can I register my own event IDs/categories? I don't
>     know where/how to define my own IDs/cats. The demo seems
>     to support two IDs, servicemanager.PYS_SERVICE_STARTED and
>     servicemanager.PYS_SERVICE_STOPPED.

> Q3) How can I add counters to the Python service? Looking at
>     the files perf_install.ini and perf_install.h, this
>     could be possible, but after install I do not see these
>     counters in PerfMon. I do not see the way these files
>     are connected to the service demo source code... Maybe
>     these are already installed as the readme indicates,
>     but where should I look?

> After all the package is quite useful with the start/stop
> service feature itself, but I would welcome some fancy stuff
> as well...
-------------- next part --------------
import win32serviceutil, win32service
import pywintypes, win32con, winerror
# Use "import *" to keep this looking as much as a "normal" service
# as possible.  Real code shouldn't do this.
from win32event import *
from win32file import *
from win32pipe import *
from win32api import *
from ntsecuritycon import *

import traceback
import thread

def ApplyIgnoreError(fn, args):
    try:
        return apply(fn, args)
    except error: # Ignore win32api errors.
        return None

class PythonTestService(win32serviceutil.ServiceFramework):
    _svc_name_ = "PythonTestService"
    _svc_display_name_ = "Python Test Service"
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = CreateEvent(None, 0, 0, None)
        self.overlapped = pywintypes.OVERLAPPED()
        self.overlapped.hEvent = CreateEvent(None,0,0,None)
#        self.thread_handles = []

    def SvcStop(self):
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                12121,
                (self._svc_name_, 'SvcStop')
                )
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        SetEvent(self.hWaitStop)

    def SvcPause(self):
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                11111,
                (self._svc_name_, 'SvcPause')
                )
        self.ReportServiceStatus(win32service.SERVICE_PAUSE_PENDING)
        SetEvent(self.hWaitStop)
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                11111,
                (self._svc_name_, 'SvcPause end')
                )

    def SvcContinue(self):
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                22222,
                (self._svc_name_, 'SvcContinue')
                )
        self.ReportServiceStatus(win32service.SERVICE_CONTINUE_PENDING)
        SetEvent(self.hWaitStop)

    def SvcInterrogate(self):
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                33333,
                (self._svc_name_, 'SvcInterrogate')
                )
        self.ReportServiceStatus(win32service.SERVICE_INTERROGATE)
        SetEvent(self.hWaitStop)

    def SvcShutdown(self):
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                44444,
                (self._svc_name_, 'SvcShutdown')
                )
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        SetEvent(self.hWaitStop)

    def SvcOther(self, control):
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_WARNING_TYPE,
                55555,
                (self._svc_name_, "SvcOther, code %d" % (control))
                )

    def SvcDoRun(self):
        # Write an event log record - in debug mode we will also
        # see this message printed.
        import servicemanager
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                12345,
                (self._svc_name_, 'SvcDoRun')
                )

        while 1:
            print "."
            rc = WaitForMultipleObjects((self.hWaitStop, self.overlapped.hEvent), 0, INFINITE)
            if rc==WAIT_OBJECT_0:
                # Stop event
                break
            Sleep(500)

        # Sleep to ensure that any new threads are in the list, and then
        # wait for all current threads to finish.
        # What is a better way?
#        Sleep(500)
#        while self.thread_handles:
#            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING, 5000)
#            print "Waiting for %d threads to finish..." % (len(self.thread_handles))
#            WaitForMultipleObjects(self.thread_handles, 1, 3000)
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING, 5000)
        # Write another event log record.
        servicemanager.LogMsg(
                servicemanager.EVENTLOG_INFORMATION_TYPE,
                54321,
                (self._svc_name_, 'SvcDoRun ends')
                )


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


More information about the Python-win32 mailing list