加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

Windows服务用python编写,不检测关机事件并正常停止

发布时间:2020-12-13 21:16:14 所属栏目:Windows 来源:网络整理
导读:我使用 With Extended Service Notifications示例代码在python中为Windows XP编写了一个服务。它非常适用于检测用户登录/注销锁定屏幕以及其他事件。问题是它从不执行关闭事件,并在重新启动/关闭时正常地停止服务。它通过登录/注销事件保持活动,并在重新启
我使用 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 : %sn'%(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=%sn" % (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太晚了
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

然后在SvcOtherEx()中拦截Pre Shutdown事件并请求更多的时间。

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读