2012-01-09 24 views
19

With Extended Service Notifications örnek kodunu kullanarak python'da Windows XP + için bir hizmet yazdım. Kullanıcı oturum açma/kapatma kilit ekranı ve diğer olayları algılamak için harika çalışıyor. Sorun, hiçbir zaman kapatma olaylarını yürütmemesi ve yeniden başlatma/kapatma işlemlerinde hizmeti nazikçe durdurmasıdır. Yeniden başlatmadan sonra yeniden başlatmanın yanı sıra oturum açma/oturumu kapatma olaylarıyla da canlı kalır. Herhangi bir yardım takdir edilecektir.Windows Hizmeti python ile yazılmış, kapanma olaylarını algılamıyor ve incelikle durmuyor

RegisterServiceCtrlHandlerEx'ı kullanmak ve yardım edebiliyorsam konsol sinyallerini kullanmak istemiyorum - hizmetler bu işlevselliğe sahip olsalar da, bunu bir şekilde hallettim.

from os.path import splitext, abspath 
from sys import modules 

import win32serviceutil 
import win32service 
import win32event 
import win32api 
import win32security 
import win32ts 

class Service(win32serviceutil.ServiceFramework): 
    _svc_name_ = '_unNamed' 
    _svc_display_name_ = '_Service Template' 

    def __init__(self, *args): 
    win32serviceutil.ServiceFramework.__init__(self, *args) 
    self.log('Initializing Service') 
    self.stop_event = win32event.CreateEvent(None, 0, 0, None) 
    self.server = None 

    def log(self, msg): 
    import servicemanager 
    servicemanager.LogInfoMsg(str(msg)) 
    def logErr(self, msg): 
    import servicemanager 
    servicemanager.LogErrorMsg(str(msg)) 
    def logWarn(self, msg): 
    import servicemanager 
    servicemanager.LogWarningMsg(str(msg)) 

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

    def GetAcceptedControls(self): 
    # Accept SESSION_CHANGE control 
    rc = win32serviceutil.ServiceFramework.GetAcceptedControls(self) 
    rc |= win32service.SERVICE_ACCEPT_SESSIONCHANGE 
    rc |= win32service.SERVICE_ACCEPT_SHUTDOWN 
    return rc 

    def GetUserInfo(self, sess_id): 
    sessions = win32security.LsaEnumerateLogonSessions()[:-5] 
    for sn in sessions: 
     sn_info = win32security.LsaGetLogonSessionData(sn) 
     if sn_info['Session'] == sess_id: 
     return sn_info 

    def getUserSessionInfo(self, sess_id): 
    msg = "" 
    try: 
     for key, val in self.GetUserInfo(sess_id).items(): 
     msg += '%s : %s\n'%(key, val) 
     if key == "UserName": 
      self.server.username = val 
    except Exception, e: 
     msg += '%s'%e 
    return msg 

    # All extra events are sent via SvcOtherEx (SvcOther remains as a 
    # function taking only the first args for backwards compatability) 
    def SvcOtherEx(self, control, event_type, data): 
     # This is only showing a few of the extra events - see the MSDN 
     # docs for "HandlerEx callback" for more info. 
     if control == win32service.SERVICE_CONTROL_SESSIONCHANGE: 
      sess_id = data[0] 
      msg = "" 
      if event_type == 5: # logon 
      msg = "Logon event: type=%s, sessionid=%s\n" % (event_type, sess_id) 
#   user_token = win32ts.WTSQueryUserToken(int(sess_id)) 
      self.server.status = 1 #logon event 
      self.getUserSessionInfo(sess_id) 
      self.sendHeartbeat() 
      self.server.status = 2 #active user 
      elif event_type == 6: # logoff 
      msg = "Logoff event: type=%s, sessionid=%s\n" % (event_type, sess_id) 
      self.server.status = 3 #logoff event 
      self.sendHeartbeat() 
      self.server.username = "" 
      self.server.status = 0 #no user 
      elif event_type == 7: # lock 
      msg = "Lock event: type=%s, sessionid=%s\n" % (event_type, sess_id) 
      self.server.status = 1 #logon event 
      self.getUserSessionInfo(sess_id) 
      self.sendHeartbeat() 
      self.server.status = 2 #active user 
      elif event_type == 8: # unlock 
      self.server.status = 3 #logoff event 
      self.server.username = "" 
      self.sendHeartbeat() 
      self.server.status = 0 #no user 
      else: 
      msg = "Other session event: type=%s, sessionid=%s\n" % (event_type, sess_id) 

#   msg += self.getUserSessionInfo(sess_id) 
      self.log(msg) 
#  elif control == win32service.SERVICE_CONTROL_SHUTDOWN: 
#  msg = "Server being shutdown..." 
#  self.log(msg) 

    def SvcDoRun(self): 
    self.ReportServiceStatus(win32service.SERVICE_START_PENDING) 
    try: 
     self.ReportServiceStatus(win32service.SERVICE_RUNNING) 
     self.log('Starting Service') 
     self.start() 
     self.log('Waiting') 
     win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE) 
     self.log('Done') 
    except Exception, x: 
     self.logErr('Exception : %s' % x) 
     self.SvcStop() 

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

    def sendHeartbeat(self): 
    # 0 = no user, standard beat (format: 0||hostname) 
    # 1 = login event (format: 1|username|hostname) 
    # 2 = active user session 
    # 3 = logout event (format: 2|username|hostname) 
    # 4 = Service exception (format 3||hostname) 
    return self.server.sendHeartbeat(category=self.server.status, username=self.server.username) 

    def start(self): pass 
    # to be overridden 
    def stop(self): pass 
    # to be overridden 

    #reboot/halt makes a different call than 'net stop mytestservice' 
    def SvcShutdown(self): 
    msg = "Server being shutdown..." 
    self.log(msg) 
    self.SvcStop() 


def instart(cls, name, display_name=None, stay_alive=True, exe_name="caedmSAM.exe"): 
    ''' 
     Install and Start (auto) a Service 

      cls : the class (derived from Service) that implement the Service 
      name : Service name 
      display_name : the name displayed in the service manager 
      stay_alive : Service will stop on logout if False 
    ''' 
    cls._svc_name_ = name 
    cls._svc_display_name_ = display_name or name 
    cls._exe_name_ = exe_name 
    cls._svc_description_ = "CAEDM SAM Server registration and montioring service" 
    try: 
     module_path=modules[cls.__module__].__file__ 
    except AttributeError: 
     # maybe py2exe went by 
     from sys import executable 
     module_path=executable 
    module_file=splitext(abspath(module_path))[0] 
    cls._svc_reg_class_ = '%s.%s' % (module_file, cls.__name__) 
    if stay_alive: win32api.SetConsoleCtrlHandler(lambda x: True, True) 
    try: 
     win32serviceutil.InstallService(
       cls._svc_reg_class_, 
       cls._svc_name_, 
       cls._svc_display_name_, 
       startType=win32service.SERVICE_AUTO_START 
       ) 
#  print 'Install: OK' 
     win32serviceutil.StartService(
       cls._svc_name_ 
       ) 
#  print 'Start: OK' 
    except Exception, x: 
     print str(x) 
+1

Normalde bir hizmet sonlandırıldığında bildirilebilir, bu olayı almıyor musunuz? Bu, kullanıcı hizmeti el ile sonlandırıyorsa veya Windows kapatılıyorsa ortaya çıkar. –

cevap

1

Eğer kapatma öncesi denedin mi: İşte

kodu? Genellikle SHUTDOWN çok geç.

def GetAcceptedControls(self): 
    # Accept SESSION_CHANGE control 
    rc = win32serviceutil.ServiceFramework.GetAcceptedControls(self) 
    rc |= win32service.SERVICE_ACCEPT_SESSIONCHANGE 
    rc |= win32service.SERVICE_ACCEPT_SHUTDOWN 
    rc |= win32service.SERVICE_ACCEPT_PRESHUTDOWN 
    return r 

Sonra SvcOtherEx() kesişmesine Öncesi Kapatma olay ve daha süre isteyin.

if win32service.SERVICE_CONTROL_PRESHUTDOWN: 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING, waitHint=10000) 
    win32event.SetEvent(self.stop_event) 
İlgili konular