从Window系统托盘控制Windows服务 
VB.NET有许多内建的类,可以让我们轻松创建Windows服务程序,但如何轻松控制这些服务呢?一般是到管理工具里面进行控制。本文将描述如何创建一个运行在系统托盘里的程序来轻松控制一个服务程序。至于如何创建服务程序,可以参考.NET SDK或其它创建服务程序的文章,本文的例子利用IIS的W3SVC服务来做例子,来控制IIS的停止与启动。

要开发这样的程序,我们先打开Microsoft Visual Studio.NET,新建一个名为ServiceController的解决方案,然后新建名为WinForm的Visual Basic类型的Windows应用程序,然后把自动创建的Form1.vb删除掉,因为我们创建的应用程序没有用户界面,我们在Sub Main运行程序。

先添加引用-.NET-System.ServiceProcess.dll,新建名为modMain的模块,代码如下:

Imports System.Text
 Imports System.Diagnostics
 Imports System.ServiceProcessPublic Module modMain
  Private WithEvents mobNotifyIcon As NotifyIcon
   Private WithEvents mobContextMenu As ContextMenu
   Private WithEvents mobTimer As Timers.Timer
   Private mobServiceController As ServiceControllerEnd Module

上面的代码首先引用了三个名称空间,然后分别定义了四个变量:mobNotifyIcon将会在系统托盘里显示;ContextMenu显示菜单信息;mobTimer为定时器,原来检查服务的状态,以随时变更菜单和图标的状态;mobServiceController表示Windows服务应用程序并允许连接到正在运行或者已停止的服务、对其进行操作或获取有关它的信息。

由于服务程序是没有用户界面的,因此我们设置三种图标标识服务的状态,这里做了三个简单的图标来标识服务的状态:Running.ico,Paused.ico,Stopped.ico,分别如下:

下面我们就建立定时器SetUpTimer过程,通常,IIS停止或启动的间隔为5秒,我们就用5秒来做定时器的间隔,代码如下:

Private Sub SetUpTimer()
     Try
         mobTimer = New Timers.Timer()
         With mobTimer
             .AutoReset = True
             .Interval = 5000
             .Start()
         End With
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub

下面,创建上下文菜单的过程,并为每个菜单项添加事件处理程序:

Private Sub CreateMenu()
     Try
         mobContextMenu.MenuItems.Add(New MenuItem("停止",New EventHandler(AddressOf StopService)))
         mobContextMenu.MenuItems.Add(New MenuItem("暂停",New EventHandler(AddressOf PauseService)))
         mobContextMenu.MenuItems.Add(New MenuItem("继续",New EventHandler(AddressOf ContinueService)))
         mobContextMenu.MenuItems.Add(New MenuItem("开始",New EventHandler(AddressOf StartService)))
         mobContextMenu.MenuItems.Add("-")
         mobContextMenu.MenuItems.Add(New MenuItem("关于",New EventHandler(AddressOf AboutBox)))
         mobContextMenu.MenuItems.Add(New MenuItem("退出",New EventHandler(AddressOf ExitController)))
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub

当我们改变了服务的运行状态时,我们应当向用户反映这一变化,这里用托盘的图标不同来进行标识。当服务程序启动时,就要先建立服务的状态,首先GetServiceStatus过程调用ServiceController的Refresh方法,它将会刷新的ServiceController所有属性。要准确得到服务程序的状态,这一过程是至关重要的,下面的Select Case语句根据不同的服务程序的状态,建立不同的菜单项和托盘图标。 

Private Sub GetServiceStatus()
     Try
     '//读取状态之前先进行刷新
     mobServiceController.Refresh()
     '//变更菜单项和图标
     Select Case mobServiceController.Status()
           Case ServiceProcess.ServiceControllerStatus.Paused
           mobNotifyIcon.Icon = New Icon("Paused.ico")
           mobContextMenu.MenuItems(0).Enabled = False
           mobContextMenu.MenuItems(1).Enabled = False
           mobContextMenu.MenuItems(2).Enabled = True
           mobContextMenu.MenuItems(3).Enabled = False
           Case ServiceProcess.ServiceControllerStatus.Running
           mobNotifyIcon.Icon = New Icon("Running.ico")
           mobContextMenu.MenuItems(0).Enabled = True
           mobContextMenu.MenuItems(1).Enabled = True
           mobContextMenu.MenuItems(2).Enabled = False
           mobContextMenu.MenuItems(3).Enabled = False
           Case ServiceProcess.ServiceControllerStatus.Stopped
           mobNotifyIcon.Icon = New Icon("Stopped.ico")
           mobContextMenu.MenuItems(0).Enabled = False
           mobContextMenu.MenuItems(1).Enabled = False
           mobContextMenu.MenuItems(2).Enabled = False
           mobContextMenu.MenuItems(3).Enabled = True
           Case _
           ServiceProcess.ServiceControllerStatus.ContinuePending, _
               ServiceProcess.ServiceControllerStatus.PausePending, _
               ServiceProcess.ServiceControllerStatus.StartPending, _
               ServiceProcess.ServiceControllerStatus.StopPending
           mobNotifyIcon.Icon = New Icon("Paused.ico")
           mobContextMenu.MenuItems(0).Enabled = False
           mobContextMenu.MenuItems(1).Enabled = False
           mobContextMenu.MenuItems(2).Enabled = False
           mobContextMenu.MenuItems(3).Enabled = False
     End Select
     '//检查“暂停”和“继续”使用可用
     If mobServiceController.CanPauseAndContinue = False Then
         mobContextMenu.MenuItems(1).Enabled = False
         mobContextMenu.MenuItems(2).Enabled = False
     End If    Catch obEx As Exception
         Throw obEx
     End Try
 End Sub

下面建立菜单项的事件处理程序:

'//停止服务的过程
 Private Sub StopService(ByVal sender As Object, ByVal e As EventArgs)
     Try
         If mobServiceController.Status = ServiceProcess.ServiceControllerStatus.Running Then
             If mobServiceController.CanStop = True Then
                 mobServiceController.Stop()
             End If
         End If
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//暂停服务的过程
 Private Sub PauseService(ByVal sender As Object, ByVal e As EventArgs)
     Try
         If Not mobServiceController.Status = ServiceProcess.ServiceControllerStatus.Paused = True Then
             If mobServiceController.CanPauseAndContinue = True Then
                 mobServiceController.Pause()
             End If
         End If
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//继续服务程序的过程
 Private Sub ContinueService(ByVal sender As Object, ByVal e As EventArgs)
     Try
         If mobServiceController.Status = ServiceProcess.ServiceControllerStatus.Paused = True Then
             If mobServiceController.CanPauseAndContinue = True Then
                 mobServiceController.Continue()
             End If
         End If
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//开始服务程序的过程
 Private Sub StartService(ByVal sender As Object, ByVal e As EventArgs)
         Try
         If mobServiceController.Status = ServiceProcess.ServiceControllerStatus.Stopped Then
             mobServiceController.Start()
         End If
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//“关于”菜单项的过程
 Private Sub AboutBox(ByVal sender As Object, ByVal e As EventArgs)
     Try
         Dim obStringBuilder As New StringBuilder()
         With obStringBuilder
             .Append("Service Controller 使用例子")
             .Append(vbCrLf)
             .Append("CLR 版本:")
             .Append(Environment.Version.ToString)
             MsgBox(.ToString, MsgBoxStyle.Information)
         End With
         obStringBuilder = Nothing
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//退出服务程序的过程
 Private Sub ExitController(ByVal sender As Object, ByVal e As EventArgs)
     Try
         mobTimer.Stop()
         mobTimer.Dispose()
         mobNotifyIcon.Visible = False
         mobNotifyIcon.Dispose()
         mobServiceController.Dispose()
         Application.Exit()
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//定时器停止
 Public Sub mobTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) _
     Handles mobTimer.Elapsed
     Try
         GetServiceStatus()
     Catch obEx As Exception
         Throw obEx
     End Try
 End Sub'//系统托盘图标单击事件
 Public Sub mobNotifyIcon_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
     Handles mobNotifyIcon.Click
     System.Diagnostics.Process.Start("IExplore.exe", "http://xml.sz.luohuedu.net/")
 End Sub

下面就是主程序:

Public Sub Main()
     Try
         '//建立与服务程序的连接
         mobServiceController = New System.ServiceProcess.ServiceController("IISAdmin")
         '//隐藏图标,知道菜单项和图标准备好以后。
         mobNotifyIcon = New NotifyIcon()
         mobNotifyIcon.Visible = False
         mobContextMenu = New ContextMenu()
         CreateMenu()
         mobNotifyIcon.ContextMenu = mobContextMenu
         mobNotifyIcon.Text = "【孟宪会之精彩世界】" + _
             Microsoft.VisualBasic.ChrW(10) + "http://xml.sz.luohuedu.net/"
         SetUpTimer()
         mobNotifyIcon.Visible = True
         Application.Run()
     Catch obEx As Exception
         MsgBox(obEx.Message.ToString, MsgBoxStyle.Critical)
         End
     End Try
 End Sub

运行结果如下:

从Window系统托盘控制Windows服务_sed