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)
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. –