Creating and managing a Windows service (part 3)

This third part shows the code needed to start/stop and set the startup type for the service. Actually, most of the necessary code sits in a ActiveState python-cookbook recipe, found here.

So, the code, using the recipe is simple (well, except that it's presented as a wxwidgets windows):

#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-
# generated by wxGlade 0.4.1cvs on Mon Aug 21 19:12:22 2006

import wx
from dlgControlerMainFrame import dlgControlerMainFrame

from service_utils import WService
from traceback_format import hook
import sys

class Alert:
def __init__ (self, parent, msg, style=wx.OK | wx.ICON_EXCLAMATION):
self.msgDlg = wx.MessageDialog(parent, msg, style=style)

def __call__(self):
res = self.msgDlg.ShowModal()
return res

STARTUP_TYPES = [ "boot", "system", "automatic", "manual", "disabled" ]

class MyApp(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
MainFrame = dlgControlerMainFrame(None, -1, "")
self.SetTopWindow(MainFrame)
MainFrame.Show()
self.dlg = MainFrame

def conf_hook(tb_type, tb_value, tb):
msg = hook(tb_type, tb_value, tb)
Alert(self.dlg, msg)()
sys.excepthook = conf_hook

self.extra_init()
return 1

def extra_init(self):
self.service = WService('Epaca')
self.dlg.button_3.Bind(wx.EVT_BUTTON, self.clickStart)
self.dlg.button_4.Bind(wx.EVT_BUTTON, self.clickStop)
self.dlg.button_2.Bind(wx.EVT_BUTTON, self.clickStatus)
self.dlg.combo_box_1.Bind(wx.EVT_COMBOBOX, self.comboClick)
self.reload()

def reload(self):
status = self.service.status(0)
self.dlg.MainFrame_statusbar.SetStatusText("The Epaca service is " + status)

start_type = self.service.infostartup()
ix = STARTUP_TYPES.index(start_type)
self.dlg.combo_box_1.SetSelection(ix)

def clickStart(self, event):
self.service.start()
self.service.fetchstatus('RUNNING')
self.reload()

def clickStop(self, event):
self.service.stop()
self.service.fetchstatus('STOPPED')
self.reload()

def clickStatus(self, event):
self.reload()

def comboClick(self, event):
val = self.dlg.combo_box_1.GetValue().strip().lower()
self.service.setstartup(val)
self.dlg.MainFrame_statusbar.SetStatusText('Service startup was changed')

# end of class MyApp

if __name__ == "__main__":
service_controler = MyApp(0)
service_controler.MainLoop()

The dialog window is generated with wxGlade in dlgControlerMainFrame.py , and has the following source code:

# -*- coding: ISO-8859-1 -*-
# generated by wxGlade 0.4.1cvs on Mon Aug 21 19:10:50 2006

import wx

# begin wxGlade: dependencies
# end wxGlade

class dlgControlerMainFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: dlgControlerMainFrame.__init__
kwds["style"] = wx.CAPTION|wx.CLOSE_BOX|wx.SYSTEM_MENU
wx.Frame.__init__(self, *args, **kwds)
self.panel_2 = wx.Panel(self, -1)
self.panel_1 = wx.Panel(self, -1)
self.MainFrame_statusbar = self.CreateStatusBar(1, 0)
self.button_3 = wx.Button(self.panel_1, -1, "Start")
self.button_4 = wx.Button(self.panel_1, -1, "Stop")
self.button_2 = wx.Button(self.panel_1, -1, "Refresh")
self.label_1 = wx.StaticText(self.panel_1, -1, "Set startup type:")
self.combo_box_1 = wx.ComboBox(self.panel_1, -1, choices=["Boot", "System", "Automatic", "Manual", "Disabled"], style=wx.CB_DROPDOWN|wx.CB_READONLY)
self.label_2 = wx.StaticText(self.panel_2, -1, "STARTUP TYPES:\n\nAutomatic: start at boot time\n\nManual: use the Epaca Service Controler \nto start the service\n\nDisabled: the service will not start", style=wx.ALIGN_RIGHT)

self.__set_properties()
self.__do_layout()
# end wxGlade

def __set_properties(self):
# begin wxGlade: dlgControlerMainFrame.__set_properties
self.SetTitle("Configure the Epaca Service")
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
self.MainFrame_statusbar.SetStatusWidths([-1])
# statusbar fields
MainFrame_statusbar_fields = ["MainFrame_statusbar"]
for i in range(len(MainFrame_statusbar_fields)):
self.MainFrame_statusbar.SetStatusText(MainFrame_statusbar_fields[i], i)
self.combo_box_1.SetSelection(-1)
# end wxGlade

def __do_layout(self):
# begin wxGlade: dlgControlerMainFrame.__do_layout
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(self.button_3, 0, wx.ALL|wx.ADJUST_MINSIZE, 6)
sizer_2.Add(self.button_4, 0, wx.ALL|wx.ADJUST_MINSIZE, 6)
sizer_2.Add(self.button_2, 0, wx.ALL|wx.ADJUST_MINSIZE, 6)
sizer_2.Add(self.label_1, 0, wx.TOP|wx.ADJUST_MINSIZE, 10)
sizer_2.Add(self.combo_box_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 6)
self.panel_1.SetAutoLayout(True)
self.panel_1.SetSizer(sizer_2)
sizer_2.Fit(self.panel_1)
sizer_2.SetSizeHints(self.panel_1)
sizer_1.Add(self.panel_1, 0, wx.ALL|wx.EXPAND, 6)
sizer_3.Add(self.label_2, 1, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 6)
self.panel_2.SetAutoLayout(True)
self.panel_2.SetSizer(sizer_3)
sizer_3.Fit(self.panel_2)
sizer_3.SetSizeHints(self.panel_2)
sizer_1.Add(self.panel_2, 1, wx.EXPAND, 0)
self.SetAutoLayout(True)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
sizer_1.SetSizeHints(self)
self.Layout()
self.Centre()
# end wxGlade

# end of class dlgControlerMainFrame

Next part, the setup.py script that will create the exe files.

Comments