劉德軍
[摘要]針對(duì)Windows服務(wù)在運(yùn)行過程中出現(xiàn)的意外停止的情況下實(shí)現(xiàn)無(wú)人值守定時(shí)檢測(cè)服務(wù)狀態(tài),在服務(wù)停止后能自動(dòng)啟動(dòng)服務(wù)。
[關(guān)鍵詞]服務(wù) 意外停止 對(duì)策
中圖分類號(hào):TP3文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1671-7597(2009)0520032-02
一、前言
系統(tǒng)服務(wù),是指執(zhí)行指定系統(tǒng)功能的程序、例程或進(jìn)程,以便支持其他程序,尤其是低層(接近硬件)程序,它是Windows系統(tǒng)的一個(gè)重要組成部分。
我院在做醫(yī)院管理系統(tǒng)與醫(yī)療保險(xiǎn)系統(tǒng)接口過程中使用到一個(gè)外加進(jìn)系統(tǒng)的醫(yī)保服務(wù),但該服務(wù)在實(shí)際使用過程中經(jīng)常出現(xiàn)服務(wù)不定時(shí)的意外停止,該服務(wù)的停止必然導(dǎo)致門診住院醫(yī)保病員的就診不能正常進(jìn)行,也給計(jì)算機(jī)中心的管理帶來了很大的挑戰(zhàn),每次服務(wù)停止后都必須在服務(wù)器上用手工執(zhí)行啟動(dòng)后才能恢復(fù)正常,為恢復(fù)該服務(wù)必須到機(jī)房手工處理,有時(shí)甚至在深夜。針對(duì)這一情況,如何才能在無(wú)人值守的情況下實(shí)現(xiàn)對(duì)該服務(wù)做監(jiān)視和啟動(dòng)處理操作呢?經(jīng)過多次摸索,終于成功地利用VB的API函數(shù)及系統(tǒng)的計(jì)劃任務(wù)配合實(shí)現(xiàn)在無(wú)人值守情況下服務(wù)的
自動(dòng)監(jiān)視和服務(wù)停止后的自動(dòng)啟動(dòng)。
二、方法簡(jiǎn)介
要實(shí)現(xiàn)對(duì)停止的服務(wù)重新啟動(dòng),需要做到以下幾個(gè)功能:
1.定時(shí)處理:利用系統(tǒng)的任務(wù)計(jì)劃指定程序定時(shí)執(zhí)行一次,執(zhí)行處理完成后直接退出程序。
2.檢測(cè)服務(wù)狀態(tài)及重新啟動(dòng)服務(wù):利用API函數(shù)構(gòu)建的類模塊實(shí)現(xiàn)對(duì)系統(tǒng)的服務(wù)狀態(tài)進(jìn)行服務(wù)狀態(tài)的檢測(cè)及停止?fàn)顟B(tài)下的再啟動(dòng)操作。
3.文件的讀寫功能:用API函數(shù)實(shí)現(xiàn)對(duì)配置文件的讀取,用write函數(shù)實(shí)現(xiàn)將啟動(dòng)服務(wù)事件以追加方式寫入到歷史
文件中。
三、程序?qū)崿F(xiàn)
(一)準(zhǔn)備工作
新建一個(gè)標(biāo)準(zhǔn)工程,名稱為[服務(wù)類],在工程中創(chuàng)建一個(gè)窗體,名稱為[frmService];在工程資源管理器中新建一個(gè)模塊,名稱為[mdlService];在工程資源管理器中新建一個(gè)類模塊,名稱為[clsService]。如圖1所示。
(二)程序代碼
1.窗體代碼
Option Explicit
Private Sub Form_Load()
iniPath = App.Path + "service.ini"
Dim mySrv As New clsService
Dim tService As String
'取需處理的服務(wù)
tService = GetFromINI("需監(jiān)控服務(wù)", "名稱", iniPath)
mySrv.Name = tService
'當(dāng)前服務(wù)狀態(tài),如處理停止?fàn)顟B(tài)則做啟動(dòng)處理,否則退出程序
If mySrv.GetServiceStatus = SERVICE_STOPPED Then
'如啟動(dòng)服務(wù)正常,則寫入歷史文件中備查
If mySrv.StartNTService = 0 Then
Open App.Path + "服務(wù)歷史.txt" For Append Shared As #1
Write #1, Format(Now, "yyyy-mm-dd hh:mm:ss") & "-" & tService & "服務(wù)意外停止,已重新執(zhí)行了啟動(dòng)。"
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
'取配置文件參數(shù)
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
'查詢服務(wù)運(yùn)行狀態(tài),4運(yùn)行,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
'開始服務(wù)
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
'服務(wù)名稱
Public Property Let Name(ByVal sSrvName As String)
Service_Name = sSrvName
End Property
(三)文件處理
新建一文本文件,改名為[Service.ini],且[Service.ini]要與[服務(wù)類.exe]文件放在同一個(gè)目錄下,打開[Service.ini]文件在其中輸入如下內(nèi)容(注:此處用Alerter代替):
[需監(jiān)控服務(wù)]
名稱=Alerter
(四)任務(wù)計(jì)劃處理
在“控制面板”中的“任務(wù)計(jì)劃”中添加該可執(zhí)行文件[服務(wù)類.exe]即可,按提示設(shè)定完成后,再在新增的任務(wù)計(jì)劃中選擇“高級(jí)計(jì)劃選項(xiàng)”中選擇“重復(fù)任務(wù)”,指定每隔多長(zhǎng)時(shí)間即運(yùn)行一次即可。若業(yè)務(wù)要求響應(yīng)快,時(shí)間間隔就小一些,否則就長(zhǎng)一些,時(shí)間間隔可根據(jù)需要自定。
四、編程后記
通過上述程序,能自動(dòng)實(shí)現(xiàn)服務(wù)意外停止后的啟動(dòng)功能。該軟件在Windows XP+VB6(SP6)環(huán)境下調(diào)試運(yùn)行通運(yùn)行。