我使用
With Extended Service Notifications示例代码在python中为Windows XP编写了一个服务。它非常适用于检测用户登录/注销锁定屏幕以及其他事件。问题是它从不执行关闭事件,并在重新启动/关闭时正常地停止服务。它通过登录/注销事件保持活动,并在重新启动后再次启动。任何帮助将不胜感激。
我不想使用RegisterServiceCtrlHandlerEx并处理控制台信号,如果我可以帮助它 – 服务内置这个功能,我只是把它弄坏了。
以下是代码:
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,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,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,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,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)
你试过PRESHUTDOWN吗通常SHUTDOWN太晚了
原文链接:https://www.f2er.com/windows/373043.htmldef 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
然后在SvcOtherEx()中拦截Pre Shutdown事件并请求更多的时间。
if win32service.SERVICE_CONTROL_PRESHUTDOWN: self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING,waitHint=10000) win32event.SetEvent(self.stop_event)