用vb編寫NT服務

一、NT服務程序
   
所謂NT服務,實際上就是一個可以在系統啓動時自動在一定身份下啓動的伴隨系統長時間存在的進程。象FTP serverHTTP server、脫機打印等都是採用NT服務的形式提供的。這實際上類似Unixroot daemon進程。NT服務歸納起來,NT服務又以下幾個特徵:

1、可以自啓動,不需要交互啓動。這對於服務器來說是一個重要的特徵。當然,你可以決定服務是否自啓動,甚至可以屏蔽某個服務。
    2
NT服務沒有用戶界面,基本上類似一個DOS 程序,因爲NT服務必須長時間運行,所以不想普通win32進程一樣有自己的界面。但是NT服務可以同用戶有界面交互,這是一類特殊的服務進程。可以通過NT的任務管理器來看到服務進程。
    3
NT服務通過SCMServices Control Manager)接口來管理,安裝、啓動、停止、撤除等都需要SCM的接口功能來進行。控制面板的服務控制器就是利用SCM接口來管理系統中的所有服務的。實際上,還有一些可以控制服務的程序或者命令,有net.exe 、服務器管理器等 SCM.exe等。
    4
、這些進程都以一定的身份運行,以方便進行服務器資源的存取。一般情況下使用域中的LocalSystem賬號運行,此賬號對本機上的大多數資源(除非特別禁止)有完全的存取權限,這樣可以保證服務程序的“強大”。但是,也有些服務採用特別的賬號運行,你也可以特別設定一個服務的帳號。
    5
、由系統自動以線程方式運行,一般情況下不過多佔用系統資源,這同普通的進程有所區別,如果不採用線程方式,一般進程往往消耗整個CPU資源。一般需要時時存在,又不能過多消耗資源的任務以服務來實現最合適。

二、服務控件
   
一般認爲編寫NT服務需要使用C/C++來實現,VC6利用ATL嚮導來提供一個基本的服務框架。具體實現步驟爲:FileàNew…àATL COM AppWizardàserviceàFinish.但是使用VC編寫NT服務需要編寫太多的代碼,這也意味着需要太多的調試、維護。實際上,NT服務不是必須由C/C++纔可以編寫的,實際上可以由任何能夠實現上一節幾個特點的任何語言實現,包括VB

VB編寫服務有那些好處呢,至少可以列出以下幾條:

1、編碼簡單,熟悉Vb語法的任何人理解本文後都可編寫。
    2
、意味着修改服務實現的邏輯簡單,維護簡單。
    3
、可以利用幾乎大多數的Vb中的組件功能,編寫一個強大的服務,譬如ado等,如果用VC來實現,相信任何人都會發怵。
    4
(牽強一點)可以證明VbBill的天空下是多麼強大。
   
那麼,Vb如何實現NT服務編寫呢?據我所至,至少有兩種途徑:

1、  按照C/C++的思路利用WinAPI來實現。

2、  利用組件按照Vb傳統方式實現。

如果利用方法1實際上是照搬C/C++的套路,如果有更好的路子可以實現,相信任何人都不會走這條“絕路”,因爲相對於其他語言來說這種編程完全喪失了Vb自身得特點同時也沒有獲得其他語言的任何優勢。在這裏,想告訴大家的是利用OCX來實現一個服務。如果您在MSDN中搜索Samples/msdn/techart/4920/,您可以看到一個已經編寫好的vc5的工程文件。編譯這個工程實際上會得到一個ntsvc.ocx的。如果您對C/C++不熟悉,可以從http://www.mywebtech.net/download/ntsvc.zip 下載一個ntsvc.ocx,OCX是我從backoffice碟中獲得的,將其拷貝到/winnt/system32/下,利用regsvr32  ntsvc.ocx命令註冊之。這樣,您的Vb就可以從project/components…引出的對話框列表中看到名爲“Microsoft NT Service Control”項。此組件擁有我們創建一個服務的基本的功能,如果要編寫一個NT服務,我們將其拖進我們的窗體,然後設定其屬性,調用其與系統、註冊表、SCM交互的功能就可以實現完成一個服務了。

我們首先了解這個組件的屬性,並向大家解釋這些屬性的用法:
    Account String ,
賬號屬性,即本NT服務在哪一個NT域賬號下運行,缺省是LocalSystem賬號,實際上大多數的NT服務都可以在此賬號下安全圓滿的運行。
    ControlsAccepted Long,
此服務接受那些SCM控制,爲以下值:
    0    
允許Start 以及 Stop .

       2     允許Pause 以及 Continue .

4     允許 shutdown

其他值,用戶自定義的某些事件.
利用這個屬性,您可以自己決定NT服務進程某個(譬如某個不可中斷操作)時刻是否允許SCM停止、暫停、啓動等操作。

    Dependencies String ,
如果您編寫的服務依賴於某個或者某些服務才能正常運行,您必須在註冊服務時指定依賴的服務列表。Dependencies按照依賴順序以chr(0)來分隔多個服務,最後必須以兩個chr(0)結束。(大家可以看到這是一個C/C++的存在痕跡)
    DisplayName String,
顯示名,NT服務以何種名字顯示給察看者。
    Interactive   Boolean ,
是否允許有同桌面用戶有交互的部分。
    LoadOrderGroup String,
Dependencies相關,決定如果本服務啓動之前,那些服務必須啓動,格式也類似,也以chr(0)分割,連續的兩個chr(0)結尾。
    Password String,
服務啓動的口令,如果使用缺省得賬號,就沒有必要設定服務啓動的帳號。
    ServiceName String,
服務名,如果使用net.exe來控制服務,net.exe的指定那一個服務的參數就是此屬性中的字符串。
    StartMode
枚舉型,具體爲:
    vcStartAutomatic     2    
服務可以自己啓動

svcStartManual 3     服務手動啓動

svcStartDisabled       4       服務不能自啓動
   
另外有一個Debug屬性,不做討論。

我們要將一個VB程序當作一個NT服務,必須向系統作一些“申請”,而相應的工作VB是無法很好的完成的。所以,NTSVC.ocx提供了相應的方法留作我們想系統傳遞相關信息。
    Install ,
將當前Vb程序安裝成NT服務,在此之前,您必須至少設置DisplayName, ServiceName, ControlsAccepted以及StartMode等屬性。除此之外您可能還要設置AccountPasswordLoadOrderGroupDependencies等。這些信息的設置正確與否,決定您的服務程序能否正常啓動運行。
    Uninstall,
將當前NTSVC.ocx指定的服務從系統註冊表中刪除。NT服務取決於系統服務註冊表的設定,這是一個衆所周知的祕密。
    StartService
,將指定的服務啓動,如果該服務註冊了。
    StopService
,停止服務,如果服務正在運行。
    LogEvent ,
記錄服務事件。服務運行中,可能發生錯誤以及意料不到的事件,這些可以通過此方法記錄下來,供管理員通過“事件察看器”察看相關的信息,以最優化服務。此方法有三個參數event, id, message. Event指發生的事件類型,可以設爲以下值:
    svcEventError 1    
錯誤事件 
    svcEventWarning     2    
警告事件
.
    svcEventInformation       4      
提供參考信息.

svcEventAuditSuccess      8       審計成功.

svcEventAuditFailure       10       審計失敗
除了以上方法,可能用戶還需要讀寫註冊表,此控件還提供了註冊表的訪問方法:
DeleteSetting  (section[, key])
GetAllSettings(section)
GetSetting(section, key[, default])
SaveSetting(section, key, setting).

 

 

 

 

 

三、編寫服務
   
瞭解以上內容,下面我們開始來設計一個服務,通過例子,讓大家理解如何在VB中編寫服務.
   
在此之前,我們決定寫一個什麼樣的服務。我參考C++Build中的一個例子,寫一個不斷報警的服務進程。該進程啓動後在後臺不斷間隔5秒發出Beep叫,這可以讓大家更深切知道此服務的存在,雖然有些令人討厭。服務的名字爲VBBeepSVC,SCM中顯示爲The VB NT SVC View

  
跟着我一起來吧!
   1
、創建工程,設定相關使用到的控件。
     
所有的Vb的控件必須有一個Form作爲載體,所以,首先我們創建一個標準工程,選擇菜單project—>Components…,然後選取(Microsoft NT Service Control,會在Toolbar中出現NT服務控件。再拖一個Timer控件到Form上。然後保存一下。基本上,創建過程完成。
   2
、設定控件屬性。
     
選中NtSvc.ocx實例,在屬性欄中設定:DisplayName: The VB NT SVC View,ServiceName: VBBeepSVC,StartMode:3(手動啓動服務).其他的就缺省吧。
     
由於我們希望每個5秒就beep一次,所以我們必須依靠一種定時機制來實現,所以我們將timerInterval設定位5000毫秒。
      
以上屬性的設定視您的需要而定,我只是說在我的VBBeepSVC中如此設定足夠了。
   3
、編寫代碼,實現服務邏輯以及服務安裝、撤除。
     
因爲服務程序實際上是一個Exe文件,並且需要自己解決安裝、撤除問題,因此需要在此程序中加入利用NT服務控件來實現安裝、撤除問題。那麼,應當在什麼時候進行了。VB程序啓動時正時Form裝載的時候,所以,我們需要在窗體的Load事件中加入一些代碼:
On Error GoTo Err_Load 
如果出現錯誤就紀錄以供參考
    Dim strDisplayName As String   
    strDisplayName = NTService1.DisplayName
    If Command = "-install" Then 
當啓動時帶上 –install的參數時
        NTService1.Interactive = True
        If NTService1.Install Then
            Call NTService1.SaveSetting("Parameters", "TimerInterval", "1000") ‘
系統參數存儲
            MsgBox strDisplayName & "
安裝成功!"
        Else
            MsgBox strDisplayName & "
安裝失敗
"
        End If
        End ‘
終止安裝

    Else
        If Command = "-uninstall" Then ‘
如果啓動時帶上 撤除參數
           If NTService1.Uninstall Then
              MsgBox strDisplayName & "
撤除成功"
           Else
              MsgBox strDisplayName & "
撤除失敗
"
           End If
           End ‘
終止撤除

        Else
        End If
     End If
    
假若不是安裝或撤除操作,即爲啓動服務
     Timer1.Interval = CInt(NTService1.GetSetting("Parameters", "TimerInterval", "2000"))
    
使用Timer控件來模擬服務的線程特性
     NTService1.ControlsAccepted = svcCtrlPauseContinue ‘
接受暫停、停止操作,意味着需要爲此編碼
     NTService1.StartService ‘
設置好參數後啓動服務
Err_Load:
    Call NTService1.LogEvent(svcMessageError, svcEventError, "[" & Err.Number & "] " & Err.Description) ‘svcMessageError
NT服務控件的錯誤值
    4
、添加控制服務的代碼。
   
儘管服務的連續線程等特性是依賴Timer實現的,但是服務的控制卻是有SCM接口向每一個服務發出的,表現在VB服務程序中爲NT服務控件捕獲到相關的事件發生,我們就應當在這些事件中根據具體的情況響應,決定能不能、如何控制服務邏輯。當然,具體的邏輯在Timer事件中表現,但是通過改變NT服務控件和Timer控件均支持的全局變量,可以實現控制服務的邏輯實現。具體代碼演示:
Private Sub NTService1_Control(ByVal EventID As Long)
   On Error GoTo Err_Control
           
在此加入一些自己的處理邏輯,當然也可以如本例一樣空缺
   Err_Control:
        Call NTService1.LogEvent(svcMessageError, svcEventError, "[" & Err.Number & "] "              & Err.Description) ‘
紀錄
End Sub
Private Sub NTService1_Pause(Success As Boolean)
  On Error GoTo Err_Pause
        Timer1.Enabled = False ‘
禁止Timer事件,因此也停止了服務的發生
        Call NTService1.LogEvent(svcEventError, svcMessageError, "Service paused")
        Success = True  
返回給SCM命令發出者,表示服務成功停止
Err_Pause:
    Call NTService1.LogEvent(svcMessageError, svcEventError, "[" & Err.Number & "] " & Err.Description)
End Sub
Private Sub NTService1_Start(Success As Boolean)
  On Error GoTo Err_Start
    Success = True
    Timer1.Enabled = True ‘
允許服務邏輯進行
  Err_Start:
    Call NTService1.LogEvent(svcMessageError, svcEventError, "[" & Err.Number & "] " & Err.Description)
End Sub
Private Sub NTService1_Stop()
  On Error GoTo Err_Stop
     Unload Me ‘
撤除Form,自然Timer也不存在,服務邏輯停止了

  Err_Stop:
 Call NTService1.LogEvent(svcMessageError, svcEventError, "[" & Err.Number & "] " & Err.Description)
End Sub
    5
、編寫服務邏輯。

   
具體就是在Timer事件中,根據約定寫一些服務細節。本例中就是發出Been,但是考慮到對SCM命令的響應,所以需要編碼爲:
On Error GoTo Err_Timer
    Beep ‘
此處即具體的服務細節
Err_Timer:
    Call NTService1.LogEvent(svcMessageError, svcEventError, "[" & Err.Number & "] " & Err.Description)
End Sub
    6
、編譯安裝、測試
   
如果以上沒有什麼錯誤的話,現在可以編譯程序了。假設我們得到的服務程序的文件名爲:VBBeepSVC.exe,我們需要通過以下命令進行安裝:
    d:/vbprog/>VBBeepSVC –install
   
如果需要撤除已經安裝的服務,則:
    d:/vbprog/>VBBeepSVC –uninstall
   
安裝完後,打開控制面板的“服務”(win2000中在“管理工具”),好了,看到其中的NT服務列表中包含我們加入的服務,顯示爲:“The VB NT SVC View”,我們可以類似啓動其他任何服務一樣啓動、停止、暫停此服務。啓動服務時,我們會聽到服務發出的討厭的beep聲音。我們的測試完成。

四、VB編寫服務的幾個說明:
    1
、首先聲明:VB編寫服務是一種嘗試,技術研究,並非提倡所有服務都要用VB寫纔對頭。同理,也說明了服務非VC寫不可。
    2
VB寫的服務僅適合win32服務,不適合NT底層服務。
    3
VB的優勢在ActiveX控件,NT服務中我們可以使用絕大多數控件來完成我們的服務邏輯,譬如涉及數據庫操作,我們可以使用ADO組件,這方面,同VC相比,VB具有天然的優勢。
    4
、做好服務內部的錯誤事件記載,只有用好這一點,才能夠真正符合服務編寫規範,也方便我們的除錯。
    5
、最後一點,本文僅供參考,如有錯誤以及錯誤引起的後果,本人概不負責.

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script> <script type="text/javascript"></script>

發佈了37 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章