win32service (wxpython) -- i cannot install service

K

kkt49

# vim: et sw=4 ts=8 sts

from wxPython.wx import *
import sys, os, time
import pywintypes
import win32serviceutil
import win32service
import win32event
import win32process

ID_ABOUT = 101
ID_EXIT = 102

# the max seconds we're allowed to spend backing off
BACKOFF_MAX = 300
# if the process runs successfully for more than BACKOFF_CLEAR_TIME
# seconds, we reset the backoff stats to their initial values
BACKOFF_CLEAR_TIME = 30
# the initial backoff interval (the amount of time we wait to restart
# a dead process)
BACKOFF_INITIAL_INTERVAL = 5

class Service(win32serviceutil.ServiceFramework):
""" A class representing a Windows NT service that can manage an
instance-home-based Zope/ZEO/ZRS processes """

# The comment below is mostly irrelevant if you're running a
standalone
# SchoolBell server, I think. -TEH

# The PythonService model requires that an actual on-disk class
declaration
# represent a single service. Thus, the below definition of
start_cmd,
# must be overridden in a subclass in a file within the instance
home for
# each instance. The below-defined start_cmd (and
_svc_display_name_
# and _svc_name_) are just examples.

# To use this script with SchoolTool, just replace "SchoolBell"
# with "SchoolTool" in the variables below.
# You'll also need to change 'Python24' to 'Python23' if that's
# what you've got. -TEH

#cmd_str = os.environ["moin_service"]

#_svc_name_ = r'moin_service'
#_svc_display_name_ = r'moin_service'
#start_cmd = r"c:\mmde\moin.exe"
info = ['', '', '']

def __init__(self):
self._svc_name = info[0]
self._svc_display_name_ = info[1]
self.start_cmd = info[2]

win32serviceutil.ServiceFramework.__init__(self)

# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.redirectOutput()

def __init__(self, args):
self._svc_name = info[0]
self._svc_display_name_ = info[1]
self.start_cmd = info[2]

win32serviceutil.ServiceFramework.__init__(self, args)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.redirectOutput()

def redirectOutput(self):
#pass
sys.stdout.close()
sys.stderr.close()
sys.stdout = NullOutput()
sys.stderr = NullOutput()

def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop
process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

# TODO: This TerminateProcess call doesn't make much sense:
it's
# doing a hard kill _first_, never giving the process a chance
to
# shut down cleanly. Compare to current Zope2 service code,
which
# uses Windows events to give the process a chance to shut down
# cleanly, doing a hard kill only if that doesn't succeed.

# stop the process if necessary
try:
win32process.TerminateProcess(self.hZope, 0)
except pywintypes.error:
# the process may already have been terminated
pass
# And set my event.
win32event.SetEvent(self.hWaitStop)

# SvcStop only gets triggered when the user explictly stops (or
restarts)
# the service. To shut the service down cleanly when Windows is
shutting
# down, we also need to hook SvcShutdown.
SvcShutdown = SvcStop

def createProcess(self, cmd):
return win32process.CreateProcess(
None, cmd, None, None, 0, 0, None, None,
win32process.STARTUPINFO())

def SvcDoRun(self):
# indicate to Zope that the process is daemon managed
(restartable)
# os.environ['ZMANAGED'] = '1'

# daemon behavior: we want to to restart the process if it
# dies, but if it dies too many times, we need to give up.

# we use a simple backoff algorithm to determine whether
# we should try to restart a dead process: for each
# time the process dies unexpectedly, we wait some number of
# seconds to restart it, as determined by the backoff interval,
# which doubles each time the process dies. if we exceed
# BACKOFF_MAX seconds in cumulative backoff time, we give up.
# at any time if we successfully run the process for more thab
# BACKOFF_CLEAR_TIME seconds, the backoff stats are reset.

# the initial number of seconds between process start attempts
backoff_interval = BACKOFF_INITIAL_INTERVAL
# the cumulative backoff seconds counter
backoff_cumulative = 0

import servicemanager

# log a service started message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ' (%s)' % self._svc_display_name_))

while 1:
start_time = time.time()
info = self.createProcess(self.start_cmd)
self.hZope = info[0] # the pid
if backoff_interval > BACKOFF_INITIAL_INTERVAL:
# if we're in a backoff state, log a message about
# starting a new process
servicemanager.LogInfoMsg(
'%s (%s): recovering from died process, new process
'
'started' % (self._svc_name_,
self._svc_display_name_)
)
rc = win32event.WaitForMultipleObjects(
(self.hWaitStop, self.hZope), 0, win32event.INFINITE)
if rc == win32event.WAIT_OBJECT_0:
# user sent a stop service request
self.SvcStop()
break
else:
# user did not send a service stop request, but
# the process died; this may be an error condition
status = win32process.GetExitCodeProcess(self.hZope)
if status == 0:
# the user shut the process down from the web
# interface (or it otherwise exited cleanly)
break
else:
# this was an abormal shutdown. if we can, we want
to
# restart the process but if it seems hopeless,
# don't restart an infinite number of times.
if backoff_cumulative > BACKOFF_MAX:
# it's hopeless
servicemanager.LogErrorMsg(
'%s (%s): process could not be restarted due
to max '
'restart attempts exceeded' % (
self._svc_display_name_, self._svc_name_
))
self.SvcStop()
break
servicemanager.LogWarningMsg(
'%s (%s): process died unexpectedly. Will
attempt '
'restart after %s seconds.' % (
self._svc_name_, self._svc_display_name_,
backoff_interval
)
)
# if BACKOFF_CLEAR_TIME seconds have elapsed since
we last
# started the process, reset the backoff interval
# and the cumulative backoff time to their original
# states
if time.time() - start_time > BACKOFF_CLEAR_TIME:
backoff_interval = BACKOFF_INITIAL_INTERVAL
backoff_cumulative = 0
# we sleep for the backoff interval. since this is
async
# code, it would be better done by sending and
# catching a timed event (a service
# stop request will need to wait for us to stop
sleeping),
# but this works well enough for me.
time.sleep(backoff_interval)
# update backoff_cumulative with the time we spent
# backing off.
backoff_cumulative = backoff_cumulative +
backoff_interval
# bump the backoff interval up by 2* the last
interval
backoff_interval = backoff_interval * 2

# loop and try to restart the process

# log a service stopped message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ' (%s) ' % self._svc_display_name_))

class NullOutput:
"""A stdout / stderr replacement that discards everything."""

def noop(self, *args, **kw):
pass

write = writelines = close = seek = flush = truncate = noop

def __iter__(self):
return self

def next(self):
raise StopIteration

def isatty(self):
return False

def tell(self):
return 0

def read(self, *args, **kw):
return ''

readline = read

def readlines(self, *args, **kw):
return []


class MyFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title, wxDefaultPosition,
wxSize(200, 150))
self.CreateStatusBar()
self.SetStatusText("This is the statusbar")

menu = wxMenu()
menu.Append(ID_ABOUT, "&About", "More information about this
program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")

menuBar = wxMenuBar()
menuBar.Append(menu, "&File");

self.SetMenuBar(menuBar)

# 서비스명
servicenameText = wxStaticText(self, -1, "Service Name")
self.servicenameCtrl = wxTextCtrl(self, -1, size=(200, -1))
# 서비스로 실행할 명령
cmdText = wxStaticText(self, -1, "Service command")
self.cmdCtrl = wxTextCtrl(self, -1, size=(200, -1))
# 실행 버튼
installButton = wxButton(self, -1, label="Install", size=(80,
-1))
removeButton = wxButton(self, -1, label="Remove", size=(80,
-1))
startButton = wxButton(self, -1, label="Start", size=(80, -1))
stopButton = wxButton(self, -1, label="Stop", size=(80, -1))
installButton.Bind(EVT_BUTTON, self.onInstallButtonClick)
removeButton.Bind(EVT_BUTTON, self.onRemoveButtonClick)
startButton.Bind(EVT_BUTTON, self.onStartButtonClick)
stopButton.Bind(EVT_BUTTON, self.onStopButtonClick)

# Sizer 구성
sizer = wxFlexGridSizer(rows=2, cols=2, hgap=10, vgap=5)
sizer.Add(servicenameText) # (0, 0)
sizer.Add(self.servicenameCtrl) # (0, 1)
sizer.Add(cmdText) # (1, 0)
sizer.Add(self.cmdCtrl) # (1, 1)
sizer.Add(installButton) # (2, 0)
sizer.Add(removeButton) # (2, 1)
sizer.Add(startButton) # (3, 0)
sizer.Add(stopButton) # (3, 1)

border = wxBoxSizer()
border.Add(sizer, 0, wxALL, 10)
self.SetSizerAndFit(border)
self.Fit()

def onInstallButtonClick(self, event):
Service.info[0] = self.servicenameCtrl.GetValue()
Service.info[1] = self.servicenameCtrl.GetValue()
Service.info[2] = self.cmdCtrl.GetValue()

#Service._svc_name_ = self.servicenameCtrl.GetValue()
#Service._svc_display_name_ = self.servicenameCtrl.GetValue()
#Service.start_cmd = self.cmdCtrl.GetValue()

#win32serviceutil.HandleCommandLine(Service)
win32serviceutil.InstallService(
win32serviceutil.GetServiceClassString(Service),
self.servicenameCtrl.GetValue(),
self.servicenameCtrl.GetValue()
)


def onRemoveButtonClick(self, event):
win32serviceutil.RemoveService(self.servicenameCtrl.GetValue())

def onStartButtonClick(self, event):
win32serviceutil.StartService(self.servicenameCtrl.GetValue())

def onStopButtonClick(self, event):
win32serviceutil.StopService(self.servicenameCtrl.GetValue())

#def onOkButtonClick(self, event):
# Service._svc_name_ = self.servicenameCtrl.GetValue()
# Service._svc_display_name_ = self.servicenameCtrl.GetValue()
# Service.start_cmd = (self.cmdCtrl.GetValue())
# sys.argv.append(self.argsCtrl.GetValue())
# win32serviceutil.HandleCommandLine(Service)


class MyApp(wxApp):
def OnInit(self):
frame = MyFrame(NULL, -1, "Hello from wxPython")
frame.servicenameCtrl.SetValue(r"moin_service")
frame.cmdCtrl.SetValue(r"c:\mmde\moin.exe")
#frame.argsCtrl.SetValue("stop")
Service.info[0] =
frame.servicenameCtrl.SetValue(r"moin_service")
Service.info[1] =
frame.servicenameCtrl.SetValue(r"moin_service")
Service.info[2] = frame.cmdCtrl.SetValue(r"c:\mmde\moin.exe")


frame.Show(true)
self.SetTopWindow(frame)
return true

if __name__ == '__main__':
app = MyApp(0)
app.MainLoop()
 
L

Larry Bates

I believe you misunderstand services. They don't
have user interfaces (UIs) like other programs.
They run without any UI as background processes that
are in basically in an infinite loop but with a way
to break out of the loop (stop service). If you wish
to have a background service that has some sort of
control UI, you need to write it as two parts. The
service and a UI that communicates with the service
either through a shared file, pipe, or socket server/
client interface.

You should pick up a copy of Python Programming on
Win32 which is an excellent reference book for writing
Windows services.

-Larry Bates
 
K

kkt49

under code service install => ok

_svc_name_ = r'moin_service'
_svc_display_name_ = r'moin_service'
start_cmd = r"c:\mmde\moin.exe"
#info = ['', '', '']

def __init__(self):
#self._svc_name = info[0]
#self._svc_display_name_ = info[1]
#self.start_cmd = info[2]

but, i want dynamic _svc_name_ and start_cmd


Larry Bates 작성:
 
L

Larry Bates

kkt49 said:
under code service install => ok

_svc_name_ = r'moin_service'
_svc_display_name_ = r'moin_service'
start_cmd = r"c:\mmde\moin.exe"
#info = ['', '', '']

def __init__(self):
#self._svc_name = info[0]
#self._svc_display_name_ = info[1]
#self.start_cmd = info[2]

but, i want dynamic _svc_name_ and start_cmd

Services aren't dynamic in nature. They are static, are
given names (that are used to start, stop, etc.) and get
installed into servicemanager on Windows workstation or
server. Their behavior could be dynamic, that is you could
change what they do by communicating with them via external
means.

I think you better back up and tell us what you are trying
to do at a higher level. Perhaps we can help more.

-Larry
 
L

Larry Bates

Larry said:
kkt49 said:
under code service install => ok

_svc_name_ = r'moin_service'
_svc_display_name_ = r'moin_service'
start_cmd = r"c:\mmde\moin.exe"
#info = ['', '', '']

def __init__(self):
#self._svc_name = info[0]
#self._svc_display_name_ = info[1]
#self.start_cmd = info[2]

but, i want dynamic _svc_name_ and start_cmd

Services aren't dynamic in nature. They are static, are
given names (that are used to start, stop, etc.) and get
installed into servicemanager on Windows workstation or
server. Their behavior could be dynamic, that is you could
change what they do by communicating with them via external
means.

I think you better back up and tell us what you are trying
to do at a higher level. Perhaps we can help more.

-Larry

Sorry, after I clicked send I "think" I understand what you
want. You can't make a .EXE program run as a service by
starting it as a service. If thats not what you are trying
to do, give us some more high-level info about what it is
that you are trying to accomplish.

-Larry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top