#############################################################################
#
# $Id: BasicNTService.py,v 1.6 2005/02/12 00:28:50 irmen Exp $
# An NT service that runs the Pyro Name Server
# Author: Syver Enstad; syver-en@online.no
# Bugfix for recent win32 builds: David Rushby; woodsplitter@rocketmail.com
#
# This is part of "Pyro" - Python Remote Objects
# Which is (c) Irmen de Jong - irmen@users.sourceforge.net
#
#############################################################################
import sys
import win32serviceutil
import threading
import win32service
import win32api
import win32con
class BasicNTService(win32serviceutil.ServiceFramework, object):
""" Abstract base to help out with building NT services
in Python with the win32all(by Mark Hammond) support for
python nt services.
Remember to set the two following class attributes
to something sensible in your subclass
_svc_name_ = 'PyroNS'
_svc_display_name_ = 'Pyro Naming Service NT service'
The following are optional
_svc_deps_: This should be set to the list of service names
That need to be started before this one.
_exe_name_: This should be set to a service .EXE if you're not
going to use PythonService.exe
_svc_description_ : This is the descriptive string that you find
in the services applet
To register the service with the SCM the easiest way is to include the
following at the bottom of the file where your subclass is defined.
if __name__ == '__main__':
TheClassYouDerivedFromBasicNTService.HandleCommandLine()
"""
def __init__(self, args):
_redirectSystemStreamsIfNecessary()
win32serviceutil.ServiceFramework.__init__(self, args)
self._stopEvent = threading.Event()
def SvcStop(self):
""" Template method from win32serviceutil.ServiceFramework"""
# first tell SCM that we have started the stopping process
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self._stopEvent.set()
def _shouldStop(self):
return self._stopEvent.isSet()
def _doRun(self):
raise NotImplementedError
def _doStop(self):
raise NotImplementedError
def SvcDoRun(self):
""" part of Template method SvcRun
from win32serviceutil.ServiceFramework"""
self.logStarted()
self._doRun()
self._stopEvent.wait()
self._doStop()
self.logTermination()
return 0
def logTermination(self):
import servicemanager
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ""))
def logStarted(self):
import servicemanager
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
def CustomOptionHandler(cls, opts):
#out=open("c:\\log.txt","w")
print "Installing the Pyro %s" % cls._svc_name_
args = raw_input("Enter command line arguments for %s: " % cls._svc_name_)
try:
createRegistryParameters(cls._svc_name_, args.strip())
except Exception,x:
print "Error occured when setting command line args in the registry: ",x
try:
cls._svc_description_
except LookupError:
return
key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\%s" % cls._svc_name_)
try:
win32api.RegSetValueEx(key, "Description", 0, win32con.REG_SZ, cls._svc_description_);
finally:
win32api.RegCloseKey(key)
CustomOptionHandler = classmethod(CustomOptionHandler)
def HandleCommandLine(cls):
if win32serviceutil.HandleCommandLine(cls, customOptionHandler=cls.CustomOptionHandler) != 0:
return # some error occured
if sys.argv[1] in ("install", "update"):
print "\nYou can configure the command line arguments in the Registry."
print "The key is: HKLM\\System\\CurrentControlSet\\Services\\%s" % cls._svc_name_
print "The value under that key is: ", pyroArgsRegkeyName
args=getRegistryParameters(cls._svc_name_)
if args:
print "(it is currently set to: '%s')" % args
else:
print "(it is currently not set)"
print
HandleCommandLine = classmethod(HandleCommandLine)
pyroArgsRegkeyName = "PyroServiceArguments"
def getRegistryParameters(servicename):
key=win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\"+servicename)
try:
try:
(commandLine, regtype) = win32api.RegQueryValueEx(key,pyroArgsRegkeyName)
return commandLine
except:
pass
finally:
key.Close()
createRegistryParameters(servicename, pyroArgsRegkeyName)
return ""
def createRegistryParameters(servicename, parameters):
newkey=win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\"+servicename,0,win32con.KEY_ALL_ACCESS)
try:
win32api.RegSetValueEx(newkey, pyroArgsRegkeyName, 0, win32con.REG_SZ, parameters)
finally:
newkey.Close()
def _redirectSystemStreamsIfNecessary():
# Python programs running as Windows NT services must not send output to
# the default sys.stdout or sys.stderr streams, because those streams are
# not fully functional in the NT service execution environment. Sending
# output to them will eventually (but not immediately) cause an IOError
# ("Bad file descriptor"), which can be quite mystifying to the
# uninitiated. This problem can be overcome by replacing the default
# system streams with a stream that discards any data passed to it (like
# redirection to /dev/null on Unix).
#
# However, the pywin32 service framework supports a debug mode, under which
# the streams are fully functional and should not be redirected.
shouldRedirect = True
try:
import servicemanager
except ImportError:
# If we can't even 'import servicemanager', we're obviously not running
# as a service, so the streams shouldn't be redirected.
shouldRedirect = False
else:
# Unlike previous builds, pywin32 builds >= 200 allow the
# servicemanager module to be imported even in a program that isn't
# running as a service. In such a situation, it would not be desirable
# to redirect the system streams.
#
# However, it was not until pywin32 build 203 that a 'RunningAsService'
# predicate was added to allow client code to determine whether it's
# running as a service.
#
# This program logic redirects only when necessary if using any build
# of pywin32 except 200-202. With 200-202, the redirection is a bit
# more conservative than is strictly necessary.
if (
servicemanager.Debugging()
or (
hasattr(servicemanager, 'RunningAsService')
and not servicemanager.RunningAsService()
)
):
shouldRedirect = False
if shouldRedirect:
sys.stdout = sys.stderr = open('nul', 'w')
return shouldRedirect
|