Hi All,

For the life of me I cannot figure out why SvcShutdown() is not being called 
when the OS shuts down. All the other SCM notifications (pause/continue/stop) 
work just fine. I have searched high & low for solutions, but nothing. What 
appears to be a slam-dunk for others completely evades me. I must be missing 
something, so I bought a copy of Programming on Win32, but the Services section 
hasn't shed any more light on the issue, so I humbly ask for enlightenment. :-) 
What the heck am I missing??

Your help would be much appreciated!

Thanks in advance,

Rob

-------------------------

import win32serviceutil
import servicemanager
import win32service
import win32event
import win32api

import datetime

LOGINFO = 0
LOGWARNING = 1
LOGERROR = 2

class MyService(win32serviceutil.ServiceFramework):
_svc_name_ = 'MyService'
_svc_display_name_ = 'MyService service'

def __init__(self, *args):
    win32serviceutil.ServiceFramework.__init__(self, *args)
    # Create events for service stop, pause & continue
    # CreateEvent(securityAttrs, bManualReset, bInitialState, name)
    self.evStop = win32event.CreateEvent(None, 0, 0, None)
    self.evPause = win32event.CreateEvent(None, 0, 0, None)
    self.evContinue = win32event.CreateEvent(None, 0, 0, None)

    # Create event list for WaitForMultipleObjects()
    self.evhandles = self.evStop, self.evPause, self.evContinue
    # sigStatus must be this range for a valid SCM event
    self.validSignals = range(win32event.WAIT_OBJECT_0, 
                              win32event.MAXIMUM_WAIT_OBJECTS)

    # Signal ID returned from WFMO() else None
    self.sigStatus = None
    # Service run state. False means pausing/paused or stopping
    self.runState = True

def logEvent(self, msg, logtype=LOGINFO, logcategory=None):
    import servicemanager

    if logtype == LOGINFO:
        servicemanager.LogInfoMsg(str(msg))
    elif logtype == LOGWARNING:
        servicemanager.LogWarningMsg(str(msg))
    elif logtype == LOGERROR:
        servicemanager.LogErrorMsg(str(msg))

def sleep(self, sec):
    '''A delay method sympathetic to SCM notifications.'''

    while sec > 0:
        # SCM event has taken place?
        if self.notificationFromSCM():
            break
        win32api.Sleep(1000)
        sec -= 1

def notificationFromSCM(self):
    '''Returns True if SCM notification(s) have taken place.

    sigStatus has the value.
    Note: that calls to WaitForMultipleObjects() only returns the event
    status ONCE, after which it's reset (ie. calling it may return
    WAIT_OBJECT_0 and an immediate subsequent call will yield WAIT_TIMEOUT
    or similar.'''

    if self.sigStatus is not None:
        # Still have a live SCM event to process, so exit
        return True

    # WaitForMultipleObjects(handles, bWaitAll, dwMilliseconds)
    self.sigStatus = win32event.WaitForMultipleObjects(self.evhandles, 0, 0)
    if self.sigStatus in self.validSignals:
        return True
    else:
        # Timeout signal or similar, so MUST reset sigStatus
        self.sigStatus = None
        return False

def SvcDoRun(self):
    self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
    self.logEvent('Starting {0} Service...'.format(self._svc_display_name_))
    self.ReportServiceStatus(win32service.SERVICE_RUNNING)
    self.logEvent('{0} Service started.'.format(self._svc_display_name_))

    while True:         
        if self.runState:
            try:
                # Insert service work activity here...
                self.logEvent('Working: {0}'.format(datetime.datetime.now()))
                self.sleep(10)
            except Exception as x:
                self.logEvent('Exception : {0}'.format(x), LOGERROR)
        else:
            self.sleep(30)

        # SCM notification?
        if self.notificationFromSCM():
            if self.sigStatus == self.evhandles.index(self.evStop):
                # STOP event
                self.logEvent('Stopping {0} 
Service...'.format(self._svc_display_name_))
                break
            elif self.sigStatus == self.evhandles.index(self.evPause):
                # PAUSE event
                self.logEvent('Pausing {0} 
Service...'.format(self._svc_display_name_))
                self.runState = False
                # Other cleanup code here...
                self.logEvent('{0} Service 
paused.'.format(self._svc_display_name_))
                self.ReportServiceStatus(win32service.SERVICE_PAUSED)
            elif self.sigStatus == self.evhandles.index(self.evContinue):
                # CONTINUE event
                self.logEvent('Resuming {0} 
service...'.format(self._svc_display_name_))
                self.runState = True
                # Reset pause & continue to non-signaled state
                win32event.ResetEvent(self.evPause)
                win32event.ResetEvent(self.evContinue)
                # Other cleanup code here...
                self.logEvent('{0} Service 
started.'.format(self._svc_display_name_))
                self.ReportServiceStatus(win32service.SERVICE_RUNNING)

            # Clear signal flag
            self.sigStatus = None

    # If we get here, then service has been stopped/shutdown
    self.logEvent('{0} Service stopped.'.format(self._svc_display_name_))
    self.ReportServiceStatus(win32service.SERVICE_STOPPED)

def SvcStop(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    # Signal STOP event
    win32event.SetEvent(self.evStop)

def SvcPause(self):
    self.ReportServiceStatus(win32service.SERVICE_PAUSE_PENDING)
    # Signal PAUSE event
    win32event.SetEvent(self.evPause)

def SvcContinue(self):
    self.ReportServiceStatus(win32service.SERVICE_CONTINUE_PENDING)
    # Signal CONTINUE event
    win32event.SetEvent(self.evContinue)

def SvcShutdown(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    self.logEvent('**SvcShutdown event**')
    # Shutdown code here...
    win32event.SetEvent(self.evStop)


_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to