home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activepython / ActivePython-2.1.1.msi / Python21_win32_Lib_win32serviceutil.py < prev    next >
Encoding:
Python Source  |  2001-07-26  |  21.9 KB  |  609 lines

  1. # General purpose service utilities, both for standard Python scripts,
  2. # and for for Python programs which run as services...
  3. #
  4. # Note that most utility functions here will raise win32api.error's
  5. # (which is == win32service.error, pywintypes.error, etc)
  6. # when things go wrong - eg, not enough permissions to hit the
  7. # registry etc.
  8.  
  9. import win32service, win32api, win32con, winerror
  10. import sys, string, pywintypes, os
  11.  
  12. error = "Python Service Utility Error"
  13.  
  14. def LocatePythonServiceExe(exeName = None):
  15.     # Try and find the specified EXE somewhere.  If specifically registered,
  16.     # use it.  Otherwise look down sys.path, and the global PATH environment.
  17.     if exeName is None: exeName = "PythonService.exe"
  18.     # See if it exists as specified
  19.     if os.path.isfile(exeName): return win32api.GetFullPathName(exeName)
  20.     baseName = os.path.splitext(os.path.basename(exeName))[0]
  21.     try:
  22.         return win32api.RegQueryValue(win32con.HKEY_LOCAL_MACHINE, "Software\\Python\\%s\\%s" % (baseName, sys.winver))
  23.     except win32api.error:
  24.         # OK - not there - lets go a-searchin'
  25.         for path in sys.path:
  26.             look = os.path.join(path, exeName)
  27.             if os.path.isfile(look):
  28.                 return win32api.GetFullPathName(look)
  29.         # Try the global Path.
  30.         try:
  31.             return win32api.SearchPath(None, exeName)
  32.         except win32api.error:
  33.             msg = "%s is not correctly registered\nPlease locate and run %s.exe, and it will self-register\nThen run this service registration process again." % (exeName, exeName)
  34.             raise error, msg
  35.  
  36. def LocateSpecificServiceExe(serviceName):
  37.     # Given the name of a specific service, return the .EXE name _it_ uses
  38.     # (which may or may not be the Python Service EXE
  39.     hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\%s" % (serviceName), 0, win32con.KEY_ALL_ACCESS)
  40.     try:
  41.         return win32api.RegQueryValueEx(hkey, "ImagePath")[0]
  42.     finally:
  43.         hkey.Close()
  44.     
  45. def InstallPerfmonForService(serviceName, iniName, dllName = None):
  46.     # If no DLL name, look it up in the INI file name
  47.     if not dllName: # May be empty string!
  48.         dllName = win32api.GetProfileVal("Python", "dll", "", iniName)
  49.     # Still not found - look for the standard one in the same dir as win32service.pyd
  50.     if not dllName:
  51.         try:
  52.             tryName = os.path.join(os.path.split(win32service.__file__)[0], "perfmondata.dll")
  53.             if os.path.isfile(tryName):
  54.                 dllName = tryName
  55.         except AttributeError:
  56.             # Frozen app? - anyway, can't find it!
  57.             pass
  58.     if not dllName:
  59.         raise ValueError, "The name of the performance DLL must be available"
  60.     dllName = win32api.GetFullPathName(dllName)
  61.     # Now setup all the required "Performance" entries.
  62.     hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\%s" % (serviceName), 0, win32con.KEY_ALL_ACCESS)
  63.     try:
  64.         subKey = win32api.RegCreateKey(hkey, "Performance")
  65.         try:
  66.             win32api.RegSetValueEx(subKey, "Library", 0, win32con.REG_SZ, dllName)
  67.             win32api.RegSetValueEx(subKey, "Open", 0, win32con.REG_SZ, "OpenPerformanceData")
  68.             win32api.RegSetValueEx(subKey, "Close", 0, win32con.REG_SZ, "ClosePerformanceData")
  69.             win32api.RegSetValueEx(subKey, "Collect", 0, win32con.REG_SZ, "CollectPerformanceData")
  70.         finally:
  71.             win32api.RegCloseKey(subKey)
  72.     finally:
  73.         win32api.RegCloseKey(hkey)
  74.     # Now do the "Lodctr" thang...
  75.  
  76.     try:
  77.         import perfmon
  78.         path, fname = os.path.split(iniName)
  79.         oldPath = os.getcwd()
  80.         if path:
  81.             os.chdir(path)
  82.         try:
  83.             perfmon.LoadPerfCounterTextStrings("python.exe " + fname)
  84.         finally:
  85.             os.chdir(oldPath)
  86.     except win32api.error, details:
  87.         print "The service was installed OK, but the performance monitor"
  88.         print "data could not be loaded.", details
  89.  
  90. def InstallService(pythonClassString, serviceName, displayName, startType = None, errorControl = None, bRunInteractive = 0, serviceDeps = None, userName = None, password = None, exeName = None, perfMonIni = None, perfMonDll = None):
  91.     # Handle the default arguments.
  92.     if startType is None:
  93.         startType = win32service.SERVICE_DEMAND_START
  94.         if bRunInteractive:
  95.             startType = startType | win32service.SERVICE_INTERACTIVE_PROCESS
  96.     if errorControl is None:
  97.         errorControl = win32service.SERVICE_ERROR_NORMAL
  98.  
  99.     exeName = '"%s"' % LocatePythonServiceExe(exeName) # None here means use default PythonService.exe
  100.     hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
  101.     try:
  102.         hs = win32service.CreateService(hscm,
  103.                     serviceName,
  104.                     displayName,
  105.                     win32service.SERVICE_ALL_ACCESS,         # desired access
  106.                     win32service.SERVICE_WIN32_OWN_PROCESS,  # service type
  107.                     startType,
  108.                     errorControl,       # error control type
  109.                     exeName,
  110.                     None,
  111.                     0,
  112.                     serviceDeps,
  113.                     userName,
  114.                     password)
  115.         win32service.CloseServiceHandle(hs)
  116.     finally:
  117.         win32service.CloseServiceHandle(hscm)
  118.     InstallPythonClassString(pythonClassString, serviceName)
  119.     # If I have performance monitor info to install, do that.
  120.     if perfMonIni is not None:
  121.         InstallPerfmonForService(serviceName, perfMonIni, perfMonDll)
  122.  
  123. def ChangeServiceConfig(pythonClassString, serviceName, startType = None, errorControl = None, serviceDeps = None, userName = None, password = None, exeName = None, displayName = None, perfMonIni = None, perfMonDll = None):
  124.     # Before doing anything, remove any perfmon counters.
  125.     try:
  126.         import perfmon
  127.         perfmon.UnloadPerfCounterTextStrings("python.exe "+serviceName)
  128.     except (ImportError, win32api.error):
  129.         pass
  130.  
  131.     # The EXE location may have changed
  132.     exeName = '"%s"' % LocatePythonServiceExe(exeName)
  133.     
  134.     # Handle the default arguments.
  135.     if startType is None: startType = win32service.SERVICE_NO_CHANGE
  136.     if errorControl is None: errorControl = win32service.SERVICE_NO_CHANGE
  137.  
  138.     hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
  139.     try:
  140.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  141.         try:
  142.  
  143.             win32service.ChangeServiceConfig(hs,
  144.                     win32service.SERVICE_NO_CHANGE,  # service type
  145.                     startType,
  146.                     errorControl,       # error control type
  147.                     exeName,
  148.                     None,
  149.                     0,
  150.                     serviceDeps,
  151.                     userName,
  152.                     password,
  153.                 displayName)
  154.         finally:
  155.             win32service.CloseServiceHandle(hs)
  156.     finally:
  157.         win32service.CloseServiceHandle(hscm)
  158.     InstallPythonClassString(pythonClassString, serviceName)
  159.     # If I have performance monitor info to install, do that.
  160.     if perfMonIni is not None:
  161.         InstallPerfmonForService(serviceName, perfMonIni, perfMonDll)
  162.  
  163. def InstallPythonClassString(pythonClassString, serviceName):
  164.     # Now setup our Python specific entries.
  165.     key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\PythonClass" % serviceName)
  166.     try:
  167.         win32api.RegSetValue(key, None, win32con.REG_SZ, pythonClassString);
  168.     finally:
  169.         win32api.RegCloseKey(key)
  170.  
  171. # Utility functions for Services, to allow persistant properties.
  172. def SetServiceCustomOption(serviceName, option, value):
  173.     try:
  174.         serviceName = serviceName._svc_name_
  175.     except AttributeError:
  176.         pass
  177.     key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\Parameters" % serviceName)
  178.     try:
  179.         if type(value)==type(0):
  180.             win32api.RegSetValueEx(key, option, 0, win32con.REG_DWORD, value);
  181.         else:
  182.             win32api.RegSetValueEx(key, option, 0, win32con.REG_SZ, value);
  183.     finally:
  184.         win32api.RegCloseKey(key)
  185.  
  186. def GetServiceCustomOption(serviceName, option, defaultValue = None):
  187.     # First param may also be a service class/instance.
  188.     # This allows services to pass "self"
  189.     try:
  190.         serviceName = serviceName._svc_name_
  191.     except AttributeError:
  192.         pass
  193.     key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\Parameters" % serviceName)
  194.     try:
  195.         try:
  196.             return win32api.RegQueryValueEx(key, option)[0]
  197.         except win32api.error:    # No value.
  198.             return defaultValue
  199.     finally:
  200.         win32api.RegCloseKey(key)
  201.  
  202.  
  203. def RemoveService(serviceName):
  204.     try:
  205.         import perfmon
  206.         perfmon.UnloadPerfCounterTextStrings("python.exe "+serviceName)
  207.     except (ImportError, win32api.error):
  208.         pass
  209.  
  210.     hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
  211.     try:
  212.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  213.         win32service.DeleteService(hs)
  214.         win32service.CloseServiceHandle(hs)
  215.     finally:
  216.         win32service.CloseServiceHandle(hscm)
  217.  
  218. def ControlService(serviceName, code, machine = None):
  219.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS)
  220.     try:
  221.  
  222.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  223.         try:
  224.             status = win32service.ControlService(hs, code)
  225.         finally:
  226.             win32service.CloseServiceHandle(hs)
  227.     finally:
  228.         win32service.CloseServiceHandle(hscm)
  229.     return status
  230.  
  231. def __FindSvcDeps(findName):
  232.     if type(findName) is pywintypes.UnicodeType: findName = str(findName)
  233.     dict = {}
  234.     k = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services")
  235.     num = 0
  236.     while 1:
  237.         try:
  238.             svc = win32api.RegEnumKey(k, num)
  239.         except win32api.error:
  240.             break
  241.         num = num + 1
  242.         sk = win32api.RegOpenKey(k, svc)
  243.         try:
  244.             deps, typ = win32api.RegQueryValueEx(sk, "DependOnService")
  245.         except win32api.error:
  246.             deps = ()
  247.         for dep in deps:
  248.             dep = string.lower(dep)
  249.             dep_on = dict.get(dep, [])
  250.             dep_on.append(svc)
  251.             dict[dep]=dep_on
  252.  
  253.     return __ResolveDeps(findName, dict)
  254.  
  255.  
  256. def __ResolveDeps(findName, dict):
  257.     items = dict.get(string.lower(findName), [])
  258.     retList = []
  259.     for svc in items:
  260.         retList.insert(0, svc)
  261.         retList = __ResolveDeps(svc, dict) + retList
  262.     return retList
  263.  
  264. def __StopServiceWithTimeout(hs, waitSecs = 30):
  265.     try:
  266.         status = win32service.ControlService(hs, win32service.SERVICE_CONTROL_STOP)
  267.     except pywintypes.error, (hr, name, msg):
  268.         if hr!=winerror.ERROR_SERVICE_NOT_ACTIVE:
  269.             raise win32service.error, (hr, name, msg)
  270.     for i in range(waitSecs):
  271.         status = win32service.QueryServiceStatus(hs)
  272.         if status[1] == win32service.SERVICE_STOPPED:
  273.             break
  274.         win32api.Sleep(1000)
  275.     else:
  276.         raise pywintypes.error, (winerror.ERROR_SERVICE_REQUEST_TIMEOUT, "ControlService", win32api.FormatMessage(winerror.ERROR_SERVICE_REQUEST_TIMEOUT)[:-2])
  277.  
  278.  
  279. def StopServiceWithDeps(serviceName, machine = None, waitSecs = 30):
  280.     # Stop a service recursively looking for dependant services
  281.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS)
  282.     try:
  283.         deps = __FindSvcDeps(serviceName)
  284.         for dep in deps:
  285.             hs = win32service.OpenService(hscm, dep, win32service.SERVICE_ALL_ACCESS)
  286.             try:
  287.                 __StopServiceWithTimeout(hs, waitSecs)
  288.             finally:
  289.                 win32service.CloseServiceHandle(hs)
  290.         # Now my service!
  291.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  292.         try:
  293.             __StopServiceWithTimeout(hs, waitSecs)
  294.         finally:
  295.             win32service.CloseServiceHandle(hs)
  296.         
  297.     finally:
  298.         win32service.CloseServiceHandle(hscm)
  299.  
  300.  
  301. def StopService(serviceName, machine = None):
  302.     return ControlService(serviceName, win32service.SERVICE_CONTROL_STOP, machine)
  303.  
  304. def StartService(serviceName, args = None, machine = None):
  305.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS)
  306.     try:
  307.  
  308.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  309.         try:
  310.             win32service.StartService(hs, args)
  311.         finally:
  312.             win32service.CloseServiceHandle(hs)
  313.     finally:
  314.         win32service.CloseServiceHandle(hscm)
  315.  
  316. def RestartService(serviceName, args = None, waitSeconds = 30, machine = None):
  317.     "Stop the service, and then start it again (with some tolerance for allowing it to stop.)"
  318.     try:
  319.         StopService(serviceName, machine)
  320.     except pywintypes.error, (hr, name, msg):
  321.         # Allow only "service not running" error
  322.         if hr!=winerror.ERROR_SERVICE_NOT_ACTIVE:
  323.             raise win32service.error, (hr, name, msg)
  324.     # Give it a few goes, as the service may take time to stop
  325.     for i in range(waitSeconds):
  326.         try:
  327.             StartService(serviceName, args, machine)
  328.             break
  329.         except pywintypes.error, (hr, name, msg):
  330.             if hr!=winerror.ERROR_SERVICE_ALREADY_RUNNING:
  331.                 raise
  332.             win32api.Sleep(1000)
  333.     else:
  334.         print "Gave up waiting for the old service to stop!"
  335.         
  336.  
  337. def GetServiceClassString(cls, argv = None):
  338.         if argv is None:
  339.             argv = sys.argv
  340.         import pickle, os
  341.         modName = pickle.whichmodule(cls, cls.__name__)
  342.         if modName == '__main__':
  343.             try:
  344.                 fname = win32api.GetFullPathName(argv[0])
  345.                 path = os.path.split(fname)[0]
  346.                 # Eaaaahhhh - sometimes this will be a short filename, which causes 
  347.                 # problems with 1.5.1 and the silly filename case rule.
  348.                 # Get the long name
  349.                 fname = os.path.join(path, win32api.FindFiles(fname)[0][8])
  350.             except win32api.error:
  351.                 raise error, "Could not resolve the path name '%s' to a full path" % (argv[0])
  352.             modName = os.path.splitext(fname)[0]
  353.         return modName + "." + cls.__name__
  354.  
  355. def QueryServiceStatus(serviceName, machine=None):
  356.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_CONNECT)
  357.     try:
  358.  
  359.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_QUERY_STATUS)
  360.         try:
  361.             status = win32service.QueryServiceStatus(hs)
  362.         finally:
  363.             win32service.CloseServiceHandle(hs)
  364.     finally:
  365.         win32service.CloseServiceHandle(hscm)
  366.     return status
  367.  
  368. def usage():
  369.     try:
  370.         fname = os.path.split(sys.argv[0])[1]
  371.     except:
  372.         fname = sys.argv[0]
  373.     print "Usage: '%s [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'" % fname
  374.     print "Options for 'install' and 'update' commands only:"
  375.     print " --username domain\username : The Username the service is to run under"
  376.     print " --password password : The password for the username"
  377.     print " --startup [manual|auto|disabled] : How the service starts, default = manual"
  378.     sys.exit(1)
  379.  
  380. def HandleCommandLine(cls, serviceClassString = None, argv = None, customInstallOptions = "", customOptionHandler = None):
  381.     """Utility function allowing services to process the command line.
  382.     
  383.     Allows standard commands such as 'start', 'stop', 'debug', 'install' etc.
  384.     
  385.     Install supports 'standard' command line options prefixed with '--', such as
  386.     --username, --password, etc.  In addition,
  387.     the function allows custom command line options to be handled by the calling function.
  388.     """
  389.     err = 0
  390.     
  391.     if argv is None: argv = sys.argv
  392.  
  393.     if len(argv)<=1:
  394.         usage()
  395.  
  396.     serviceName = cls._svc_name_
  397.     serviceDisplayName = cls._svc_display_name_
  398.     if serviceClassString is None:
  399.         serviceClassString = GetServiceClassString(cls)
  400.  
  401.     # First we process all arguments which require access to the
  402.     # arg list directly
  403.     if argv[1]=="start":
  404.         print "Starting service %s" % (serviceName)
  405.         try:        
  406.             StartService(serviceName, argv[2:])
  407.         except win32service.error, (hr, fn, msg):
  408.             print "Error starting service: %s" % msg
  409.  
  410.     elif argv[1]=="restart":
  411.         print "Restarting service %s" % (serviceName)
  412.         RestartService(serviceName, argv[2:])
  413.     
  414.     elif argv[1]=="debug":
  415.         svcArgs = string.join(sys.argv[2:])
  416.         exeName = LocateSpecificServiceExe(serviceName)
  417.         try:
  418.             os.system("%s -debug %s %s" % (exeName, serviceName, svcArgs))
  419.         # ^C is used to kill the debug service.  Sometimes Python also gets
  420.         # interrupted - ignore it...
  421.         except KeyboardInterrupt:
  422.             pass
  423.     else:
  424.         # Pull apart the command line
  425.         import getopt
  426.         try:
  427.             opts, args = getopt.getopt(argv[1:], customInstallOptions,["password=","username=","startup=","perfmonini=", "perfmondll="])
  428.         except getopt.error, details:
  429.             print details
  430.             usage()
  431.         userName = None
  432.         password = None
  433.         perfMonIni = perfMonDll = None
  434.         startup = None
  435.         for opt, val in opts:
  436.             if opt=='--username':
  437.                 userName = val
  438.             elif opt=='--password':
  439.                 password = val
  440.             elif opt=='--perfmonini':
  441.                 perfMonIni = val
  442.             elif opt=='--perfmondll':
  443.                 perfMonDll = val
  444.             elif opt=='--startup':
  445.                 map = {"manual": win32service.SERVICE_DEMAND_START, "auto" : win32service.SERVICE_AUTO_START, "disabled": win32service.SERVICE_DISABLED}
  446.                 try:
  447.                     startup = map[string.lower(val)]
  448.                 except KeyError:
  449.                     print "'%s' is not a valid startup option" % val
  450.         if len(args)<>1:
  451.             usage()
  452.         arg=args[0]
  453.         knownArg = 0
  454.         if arg=="install":
  455.             knownArg = 1
  456.             try:
  457.                 serviceDeps = cls._svc_deps_
  458.             except AttributeError:
  459.                 serviceDeps = None
  460.             try:
  461.                 exeName = cls._exe_name_
  462.             except AttributeError:
  463.                 exeName = None # Default to PythonService.exe
  464.             print "Installing service %s to Python class %s" % (serviceName,serviceClassString)
  465.             # Note that we install the service before calling the custom option
  466.             # handler, so if the custom handler fails, we have an installed service (from NT's POV)
  467.             # but is unlikely to work, as the Python code controlling it failed.  Therefore
  468.             # we remove the service if the first bit works, but the second doesnt!
  469.             try:
  470.                 InstallService(serviceClassString, serviceName, serviceDisplayName, serviceDeps = serviceDeps, startType=startup, userName=userName,password=password, exeName=exeName, perfMonIni=perfMonIni,perfMonDll=perfMonDll)
  471.                 if customOptionHandler:
  472.                     apply( customOptionHandler, (opts,) )
  473.                 print "Service installed"
  474.             except win32service.error, (hr, fn, msg):
  475.                 if hr==winerror.ERROR_SERVICE_EXISTS:
  476.                     arg = "update" # Fall through to the "update" param!
  477.                 else:
  478.                     print "Error installing service: %s (%d)" % (msg, hr)
  479.                     err = hr
  480.             except ValueError, msg: # Can be raised by custom option handler.
  481.                 print "Error installing service: %s" % str(msg)
  482.                 err = -1
  483.                 # xxx - maybe I should remove after _any_ failed install - however,
  484.                 # xxx - it may be useful to help debug to leave the service as it failed.
  485.                 # xxx - We really _must_ remove as per the comments above...
  486.                 # As we failed here, remove the service, so the next installation
  487.                 # attempt works.
  488.                 try:
  489.                     RemoveService(serviceName)
  490.                 except win32api.error:
  491.                     print "Warning - could not remove the partially installed service."
  492.  
  493.         if arg == "update":
  494.             knownArg = 1
  495.             try:
  496.                 serviceDeps = cls._svc_deps_
  497.             except AttributeError:
  498.                 serviceDeps = None
  499.             try:
  500.                 exeName = cls._exe_name_
  501.             except AttributeError:
  502.                 exeName = None # Default to PythonService.exe
  503.             print "Changing service configuration"
  504.             try:
  505.                 ChangeServiceConfig(serviceClassString, serviceName, serviceDeps = serviceDeps, startType=startup, userName=userName,password=password, exeName=exeName, displayName = serviceDisplayName, perfMonIni=perfMonIni,perfMonDll=perfMonDll)
  506.                 print "Service updated"
  507.             except win32service.error, (hr, fn, msg):
  508.                 print "Error changing service configuration: %s (%d)" % (msg,hr)
  509.                 err = hr
  510.  
  511.         elif arg=="remove":
  512.             knownArg = 1
  513.             print "Removing service %s" % (serviceName)
  514.             try:
  515.                 RemoveService(serviceName)
  516.                 print "Service removed"
  517.             except win32service.error, (hr, fn, msg):
  518.                 print "Error removing service: %s (%d)" % (msg,hr)
  519.                 err = hr
  520.         elif arg=="stop":
  521.             knownArg = 1
  522.             print "Stopping service %s" % (serviceName)
  523.             try:
  524.                 StopService(serviceName)
  525.             except win32service.error, (hr, fn, msg):
  526.                 print "Error stopping service: %s (%d)" % (msg,hr)
  527.                 err = hr
  528.         if not knownArg:
  529.             err = -1
  530.             print "Unknown command - '%s'" % arg
  531.             usage()
  532.     return err
  533.  
  534. #
  535. # Useful base class to build services from.
  536. #
  537. class ServiceFramework:
  538.     # _svc_name = The service name
  539.     # _svc_display_name = The service display name
  540.     def __init__(self, args):
  541.         import servicemanager
  542.         self.ssh = servicemanager.RegisterServiceCtrlHandler(args[0], self.ServiceCtrlHandler)
  543.         self.checkPoint = 0
  544.  
  545.     def GetAcceptedControls(self):
  546.         # Setup the service controls we accept based on our attributes
  547.         accepted = 0
  548.         if hasattr(self, "SvcStop"): accepted = accepted | win32service.SERVICE_ACCEPT_STOP
  549.         if hasattr(self, "SvcPause") and hasattr(self, "SvcContinue"):
  550.             accepted = accepted | win32service.SERVICE_ACCEPT_PAUSE_CONTINUE
  551.         if hasattr(self, "SvcShutdown"): accepted = accepted | win32service.SERVICE_ACCEPT_SHUTDOWN
  552.         return accepted
  553.             
  554.     def ReportServiceStatus(self, serviceStatus, waitHint = 5000, win32ExitCode = 0, svcExitCode = 0):
  555.         if self.ssh is None: # Debugging!
  556.             return
  557.         if serviceStatus == win32service.SERVICE_START_PENDING:
  558.             accepted = 0
  559.         else:
  560.             accepted = self.GetAcceptedControls()
  561.  
  562.         if serviceStatus in [win32service.SERVICE_RUNNING,  win32service.SERVICE_STOPPED]:
  563.             checkPoint = 0
  564.         else:
  565.             self.checkPoint = self.checkPoint + 1
  566.             checkPoint = self.checkPoint
  567.  
  568.         # Now report the status to the control manager
  569.         status = (win32service.SERVICE_WIN32_OWN_PROCESS,
  570.                  serviceStatus,
  571.                  accepted, # dwControlsAccepted,
  572.                  win32ExitCode, # dwWin32ExitCode; 
  573.                  svcExitCode, # dwServiceSpecificExitCode; 
  574.                  checkPoint, # dwCheckPoint; 
  575.                  waitHint)
  576.         win32service.SetServiceStatus( self.ssh, status)
  577.  
  578.     def SvcInterrogate(self):
  579.         # Assume we are running, and everyone is happy.
  580.         self.ReportServiceStatus(win32service.SERVICE_RUNNING)
  581.  
  582.     def SvcOther(self, control):
  583.         print "Unknown control status - %d" % control
  584.  
  585.     def ServiceCtrlHandler(self, control):
  586.         if control==win32service.SERVICE_CONTROL_STOP:
  587.             self.SvcStop()
  588.         elif control==win32service.SERVICE_CONTROL_PAUSE:
  589.             self.SvcPause()
  590.         elif control==win32service.SERVICE_CONTROL_CONTINUE:
  591.             self.SvcContinue()
  592.         elif control==win32service.SERVICE_CONTROL_INTERROGATE:
  593.             self.SvcInterrogate()
  594.         elif control==win32service.SERVICE_CONTROL_SHUTDOWN:
  595.             self.SvcShutdown()
  596.         else:
  597.             self.SvcOther(control)
  598.  
  599.     def SvcRun(self):
  600.         self.ReportServiceStatus(win32service.SERVICE_RUNNING)
  601.         self.SvcDoRun()
  602.         # Once SvcDoRun terminates, the service has stopped.
  603.         # We tell the SCM the service is still stopping - the C framework
  604.         # will automatically tell the SCM it has stopped when this returns.
  605.         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
  606.  
  607.  
  608.  
  609.