刘德军
[摘要]针对Windows服务在运行过程中出现的意外停止的情况下实现无人值守定时检测服务状态,在服务停止后能自动启动服务。
[关键词]服务 意外停止 对策
中图分类号:TP3文献标识码:A文章编号:1671-7597(2009)0520032-02
一、前言
系统服务,是指执行指定系统功能的程序、例程或进程,以便支持其他程序,尤其是低层(接近硬件)程序,它是Windows系统的一个重要组成部分。
我院在做医院管理系统与医疗保险系统接口过程中使用到一个外加进系统的医保服务,但该服务在实际使用过程中经常出现服务不定时的意外停止,该服务的停止必然导致门诊住院医保病员的就诊不能正常进行,也给计算机中心的管理带来了很大的挑战,每次服务停止后都必须在服务器上用手工执行启动后才能恢复正常,为恢复该服务必须到机房手工处理,有时甚至在深夜。针对这一情况,如何才能在无人值守的情况下实现对该服务做监视和启动处理操作呢?经过多次摸索,终于成功地利用VB的API函数及系统的计划任务配合实现在无人值守情况下服务的
自动监视和服务停止后的自动启动。
二、方法简介
要实现对停止的服务重新启动,需要做到以下几个功能:
1.定时处理:利用系统的任务计划指定程序定时执行一次,执行处理完成后直接退出程序。
2.检测服务状态及重新启动服务:利用API函数构建的类模块实现对系统的服务状态进行服务状态的检测及停止状态下的再启动操作。
3.文件的读写功能:用API函数实现对配置文件的读取,用write函数实现将启动服务事件以追加方式写入到历史
文件中。
三、程序实现
(一)准备工作
新建一个标准工程,名称为[服务类],在工程中创建一个窗体,名称为[frmService];在工程资源管理器中新建一个模块,名称为[mdlService];在工程资源管理器中新建一个类模块,名称为[clsService]。如图1所示。
(二)程序代码
1.窗体代码
Option Explicit
Private Sub Form_Load()
iniPath = App.Path + "service.ini"
Dim mySrv As New clsService
Dim tService As String
'取需处理的服务
tService = GetFromINI("需监控服务", "名称", iniPath)
mySrv.Name = tService
'当前服务状态,如处理停止状态则做启动处理,否则退出程序
If mySrv.GetServiceStatus = SERVICE_STOPPED Then
'如启动服务正常,则写入历史文件中备查
If mySrv.StartNTService = 0 Then
Open App.Path + "服务历史.txt" For Append Shared As #1
Write #1, Format(Now, "yyyy-mm-dd hh:mm:ss") & "-" & tService & "服务意外停止,已重新执行了启动。"
Close #1
End If
End If
End
End Sub
2.模块代码
Option Explicit
Public iniPath As String
Public ServiceName As String
Public Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, lpKeyName As Any, ByVal lpDefault As String, ByVal lpRetunedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
Public Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
'取配置文件参数
Public Function GetFromINI(AppName As String, KeyName As String, FileName As String) As String
Dim RetStr As String
RetStr = String(255, Chr(0))
GetFromINI = Left(RetStr, GetPrivateProfileString(AppName, ByVal KeyName, "", RetStr, Len(RetStr), FileName))
End Function
3.类模块代码
Option Explicit
Private Const SC_MANAGER_CONNECT = &H1&
Private Const SERVICE_QUERY_STATUS = &H4&
Private Const SERVICE_START = &H10&
Public Enum SERVICE_START_TYPE
SERVICE_AUTO_START = 2&
SERVICE_DEMAND_START = 3&
SERVICE_DISABLED = &H4
End Enum
Public Enum SERVICE_STATE
SERVICE_STOPPED = &H1
SERVICE_START_PENDING = &H2
SERVICE_STOP_PENDING = &H3
SERVICE_RUNNING = &H4
SERVICE_CONTINUE_PENDING = &H5
SERVICE_PAUSE_PENDING = &H6
SERVICE_PAUSED = &H7
End Enum
Private Type SERVICE_STATUS
dwServiceType As Long
dwCurrentState As Long
dwControlsAccepted As Long
dwWin32ExitCode As Long
dwServiceSpecificExitCode As Long
dwCheckPoint As Long
dwWaitHint As Long
End Type
Private Declare Function OpenSCManager Lib "advapi32" Alias "OpenSCManagerW" _
(ByVal lpMachineName As Long, ByVal lpDatabaseName As Long, _
ByVal dwDesiredAccess As Long) As Long
Private Declare Function OpenService Lib "advapi32" Alias "OpenServiceW" _
(ByVal hSCManager As Long, ByVal lpServiceName As Long, _
ByVal dwDesiredAccess As Long) As Long
Private Declare Function QueryServiceStatus Lib "advapi32" (ByVal hService _
As Long, lpServiceStatus As SERVICE_STATUS) As Long
Private Declare Function CloseServiceHandle Lib "advapi32" _
(ByVal hSCObject As Long) As Long
Private Declare Function StartService Lib "advapi32" Alias "StartServiceW" _
(ByVal hService As Long, ByVal dwNumServiceArgs As Long, _
ByVal lpServiceArgVectors As Long) As Long
Private Service_Name As String
'查询服务运行状态,4运行,1停止
Public Function GetServiceStatus() As SERVICE_STATE
Dim hSCManager As Long, hService As Long, Status As SERVICE_STATUS
hSCManager = OpenSCManager(0&, 0&, SC_MANAGER_CONNECT)
If hSCManager Then
hService = OpenService(hSCManager, StrPtr(Service_Name), SERVICE_QUERY_STATUS)
If hService Then
If QueryServiceStatus(hService, Status) Then
GetServiceStatus = Status.dwCurrentState
End If
CloseServiceHandle hService
End If
CloseServiceHandle hSCManager
End If
End Function
'开始服务
Public Function StartNTService() As Long
Dim hSCManager As Long, hService As Long
hSCManager = OpenSCManager(0&, 0&, SC_MANAGER_CONNECT)
If hSCManager Then
hService = OpenService(hSCManager, StrPtr(Service_Name), SERVICE_START)
If hService Then
If StartService(hService, 0, 0) = 0 Then
StartNTService = Err.LastDllError
End If
CloseServiceHandle hService
Else
StartNTService = Err.LastDllError
End If
CloseServiceHandle hSCManager
Else
StartNTService = Err.LastDllError
End If
End Function
'服务名称
Public Property Let Name(ByVal sSrvName As String)
Service_Name = sSrvName
End Property
(三)文件处理
新建一文本文件,改名为[Service.ini],且[Service.ini]要与[服务类.exe]文件放在同一个目录下,打开[Service.ini]文件在其中输入如下内容(注:此处用Alerter代替):
[需监控服务]
名称=Alerter
(四)任务计划处理
在“控制面板”中的“任务计划”中添加该可执行文件[服务类.exe]即可,按提示设定完成后,再在新增的任务计划中选择“高级计划选项”中选择“重复任务”,指定每隔多长时间即运行一次即可。若业务要求响应快,时间间隔就小一些,否则就长一些,时间间隔可根据需要自定。
四、编程后记
通过上述程序,能自动实现服务意外停止后的启动功能。该软件在Windows XP+VB6(SP6)环境下调试运行通运行。