デベロッパー
デベロッパー
VB.NetでWindowsサービスをリモートから制御/インストール/アンインストールする
Windowsサービスの制御
Windowsサービスにはいくつかの基本的な特性があります。まず、Windowsサービスは特定ユーザーの下で実行するように設定できます。また、Windowsサービスは親あるいは子サービスを持つことができます。親サービスとは、そのサービスが依存するサービスのことで、子サービスとは、そのサービスに依存するサービスのことです。この関係は、サービスの起動/停止の際に重要な意味を持ちます。サービスを正しく起動させるには、そのサービスの親サービスが起動していることを確認する必要があります。サービスを正しく停止させるには、そのサービスの子サービスが停止していることを確認する必要があります。サービスの起動
それでは、実際のコードを見てみましょう。VB.Netでサービスを制御するには、サービスプロセスの名前空間をインポートする必要があります。よって、最初の行は次のようになります。Imports System.ServiceProcess
Dim objWinServ As New ServiceController
objWinServ.ServiceName = sServiceName
objWinServ.MachineName = MachineName
StartService(objWinServ)
Private Sub StartService(ByVal Service As ServiceController)
If Service.Status = ServiceControllerStatus.Stopped Then
Try
Service.Start()
Service.WaitForStatus(ServiceControllerStatus.Running, _
System.TimeSpan.FromSeconds(20))
Catch ex As TimeoutException
Status = "Could not Start " & Service.DisplayName & _
" - TimeOut expired"
Catch e As Exception
Status = "Could not Start " & Service.DisplayName & _
" - " & e.Message
End Try
End If
End Sub
objWinServという名称の新規サービスコントローラを作成します。- サービス名とマシン名を割り当てます(リモートで呼び出しを行うため)。
objWinServオブジェクトをサービス起動ルーチンに提供します。- 起動ルーチンは最初に目的のサービスのステータスをチェックし、サービスが停止しているかを確認します。同じ要領で、一時停止状態や実行中などの確認もできます。
- その後、起動ルーチンはサービスの起動を試みます。この例では、起動の最大待ち時間を20秒に設定しました。サービスが起動しない場合は、タイムアウト例外がスローされます。その他の一般的な例外についての処理も用意してあります。
- 事前に起動している必要がある親サービス
- サービスがサーバ上に存在しているか
Private Sub CheckForParentServices _
(ByVal Service As ServiceController)
Dim objParentService As ServiceController
For Each objParentService In Service.ServicesDependedOn
CheckForParentServices(objParentService)
Next
Call StartService(Service)
End Sub
objWinServオブジェクトをこのプロシージャに渡せば、後は再帰的に処理が行われます。サービスが存在するかチェックするには、サービスの有無に応じてブール値を返す、以下の関数を使用します。
Public Function CheckforService(ByVal ServerName As String, _
ByVal ServiceName As String) As Boolean
Dim Exist As Boolean = False
Dim objWinServ As New ServiceController
Dim ServiceStatus As ServiceControllerStatus
objWinServ.ServiceName = ServiceName
objWinServ.MachineName = ServerName
Try
ServiceStatus = objWinServ.Status
Exist = True
Catch ex As Exception
Finally
objWinServ = Nothing
End Try
Return Exist
End Function
サービスの停止
次はサービスの停止について考えてみましょう。まずは基本の関数です。Private Sub StopService(ByVal Service As ServiceController)
Dim status As String
If Service.Status = ServiceControllerStatus.Running Then
Try
Service.Stop()
Service.WaitForStatus(ServiceControllerStatus.Stopped, _
System.TimeSpan.FromSeconds(20))
Catch ex As TimeoutException
status = "Could not Stop " & Service.DisplayName & _
"Service - TimeOut expired"
Catch e As Exception
status = "Could not Stop " & Service.DisplayName & _
"Service - " & e.Message
End Try
End If
End Sub
objWinServには、起動の場合と同様の例外処理と待ち時間を設定しています。先ほどと同じ関数を使用して、サービスが存在するか事前にチェックできます。ただし、サービスの停止時には、そのサービスが停止すべき子サービスを持っているかを確認する必要があります。この処理を行うプロシージャは次のとおりです。
Private Sub CheckForChildServices(ByVal Service As ServiceController, _
ByVal NextService As String)
Dim objChildService As ServiceController
For Each objChildService In Service.DependentServices
CheckForChildServices(objChildService, NextService)
Next
If NextService = "Stop" Then
Call StopService(Service)
Else
Call ContinueService(Service)
End If
End Sub
NextServiceを追加しました。この属性は、子サービスのチェックルーチンを再利用しやすくするためのものです。ステータスを継続に変更したい場合も、子サービスが存在するかを確認する必要があります。そこで、ステータスとしてStopまたはContinueの値を取る属性情報を追加します。次に示すのは、サービスを継続させるためのプロシージャです。一時停止させるプロシージャも同様に記述できます。
Private Sub ContinueService(ByVal Service As ServiceController)
Dim status As String
If Service.Status = ServiceControllerStatus.Paused Then
Try
Service.Continue()
Service.WaitForStatus(ServiceControllerStatus.Running, _
System.TimeSpan.FromSeconds(20))
Catch ex As TimeoutException
status = "Could not change status from Paused To _
Continue for " & Service.DisplayName " _
" - TimeOut expired"
Catch e As Exception
status = "Could not change status from Paused To _
Continue for " & Service.DisplayName & " - " _
& e.Message
End Try
End If
If Service.Status = ServiceControllerStatus.Stopped Then
Call StopService(Service)
End If
End Sub
Public Function ControlServices(ByVal sServiceName As String, _
ByVal sTask As String, ByVal MachineName As String)
Status = ""
Dim objWinServ As New ServiceController
objWinServ.ServiceName = sServiceName
objWinServ.MachineName = MachineName
Select Case sTask
Case "Reset"
If objWinServ.Status = ServiceControllerStatus.Running Then
'Service is currently running, so you will have to
'stop it before starting it
'First stop all it's child services, then stop the
'service itself
Call CheckForChildServices(objWinServ, "Stop")
End If
If objWinServ.Status = ServiceControllerStatus.Stopped Then
'This is satisfied if the service was running and then
'was stopped by code or if it was already stopped.
'Service is already stopped, so just start it...
'so first start all it's parent services
Call CheckForParentServices(objWinServ)
If Status = "" Then Status = "Successfully Started"
Else
Status = Status '"Could not Start " & _
objWinServ.DisplayName
End If
End If
Case "Start"
If objWinServ.Status = ServiceControllerStatus.Stopped Then
'This is satisfied if the service was running and then
'was stopped by code or if it was already stopped
Call CheckForParentServices(objWinServ)
If Status = "" Then
Status = "Could not Start " & _
objWinServ.DisplayName
Else
Status = "Successfully Started"
End If
End If
Case "Stop"
If objWinServ.Status = ServiceControllerStatus.Running Then
Call CheckForChildServices(objWinServ, "Stop")
Status = "Successfully Stopped"
ElseIf objWinServ.Status = ServiceControllerStatus.Stopped Then
Status = "Successfully Stopped"
Else
Status = "Could not Stop " & objWinServ.DisplayName
End If
End Select
Return Status
End Function
Public Function GetServiceStatus(ByVal sServername As String, _
ByVal sServiceName As String) As String
Dim ServiceStatus As New ServiceController
ServiceStatus.ServiceName = sServiceName
ServiceStatus.MachineName = sServername
Try
If ServiceStatus.Status = ServiceControllerStatus.Running Then
Return "Running"
ElseIf ServiceStatus.Status = _
ServiceControllerStatus.Stopped Then
Return "Stopped"
Else
Return "Intermidiate"
End If
Catch ex As Exception
Return "Stopped"
Finally
ServiceStatus = Nothing
End Try
End Function
Windowsサービスのインストールとアンインストール
次に、インストールとアンインストールについて考えてみます。最初のステップで、下記のとおりグローバル宣言を行います。Private Declare Ansi Function WritePrivateProfileString Lib _
"KERNEL32.DLL" Alias "WritePrivateProfileStringA" _
(ByVal lpSectionName As String, ByVal lpKeyName As String, _
ByVal lpKeyValue As String, ByVal lpFileName As String) As Integer
Private Declare Ansi Function GetPrivateProfileString Lib _
"KERNEL32.DLL" Alias "GetPrivateProfileStringA" _
(ByVal lpSectionName As String, ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString As StringBuilder, _
ByVal nSize As Integer, _
ByVal lpFileName As String) As Integer
Private Sub InstallService(ByVal sServiceName As String)
Try
Console.WriteLine("Running Install Service...")
Dim sUserID As String = sDomainName & "\" & sUserID
Dim sPassword As String = sPassword
If IsServiceInstalled(sServiceName) Then _
UninstallService(sServiceName)
' INSTALL
Dim hSCM As IntPtr = OpenSCManager(Nothing, Nothing, _
ServiceControlManagerEnum.AllAccess)
If hSCM.ToInt32 = 0 Then
Throw New Exception("Could not install service. [1]")
Else
Dim iServiceType As Integer = ServiceTypeEnum.Win32OwnProcess
Dim hService As IntPtr = CreateService(hSCM, sServiceName, _
sServiceName, ServiceControlManagerEnum.AllAccess, _
iServiceType, ServiceTypeEnum.AutoStart, _
ServiceTypeEnum.ErrorNormal, sPath, Nothing, Nothing, _
Nothing, sUserID, sPassword)
If hService.ToInt32 = 0 Then
Throw New Exception("Could not install service. [2]")
Else
CloseServiceHandle(hService)
End If
CloseServiceHandle(hSCM)
Call ControlServices(sServiceName, "Start")
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
Console.ReadLine()
End Try
End Sub
Private Function IsServiceInstalled(ByVal sServiceName As String) _
As Boolean
Dim bResult As Boolean = False
Dim oServiceArray() As ServiceProcess.ServiceController
oServiceArray = ServiceProcess.ServiceController.GetServices
For Each oServiceController _
As ServiceProcess.ServiceController In oServiceArray
If oServiceController.ServiceName.Trim.ToUpper = _
sServiceName.Trim.ToUpper Then
Dim i As New ServiceControllerPermissionAttribute _
(Security.Permissions.SecurityAction.Demand)
Dim d As New ServiceControllerPermission
Try
If d.Any Then
d.ToString()
End If
Catch
End Try
bResult = True
Exit For
End If
Next
Return bResult
End Function
Private Sub UninstallService(ByVal sServiceName As String)
Console.WriteLine("Running Uninstall Service...")
If IsServiceInstalled(sServiceName) Then
' STOP SERVICE
Call ControlServices(sServiceName, "Stop")
Else
Exit Sub
End If
Dim hSCM As IntPtr = OpenSCManager(Nothing, Nothing, _
ServiceControlManagerEnum.AllAccess)
If hSCM.ToInt32 = 0 Then
Throw New Exception("Could not delete service. [1]")
Else
Dim hService As IntPtr = OpenService(hSCM, sServiceName, _
ServiceAccessTypeEnum.AllAccess)
If hService.ToInt32 = 0 Then
' TODO: FAILED
Else
If Not DeleteService(hService) Then
Throw New Exception("Could not delete service. [2]")
End If
CloseServiceHandle(hService)
End If
CloseServiceHandle(hSCM)
End If
End Sub
この記事のダウンロードサンプルには、ここで紹介したすべての関数を含むコンソールアプリケーションの「.sln」ファイルが収録されています。サンプルではアンインストールの関数を呼び出しているだけですが、この記事の内容を参考にすれば、メイン関数に起動/停止などの機能を簡単に追加できるでしょう。
著者紹介
aneezah(aneezah)
VB.NetおよびSQLに関して4年以上の経験を持つ開発者。
New Topics
Special Ad
| “超高速無線 LAN 時代”の幕開け--新規格 11ac(Draft)に対応したバッファロー最新ルーターの潜在能力を試す | |
![]() |
バッファローは次世代無線 LAN 規格 IEEE802.11ac(Draft)通信速度最大 1,300Mbps 対応無線 LAN ルーター「WZR-1750DHP」を3月下旬に販売開始。今回、同機器を入手できたので、使用感や便利な機能についてレポートしたい。⇒詳細記事へ |
Hot Topics
IT Job
今週のIT求人情報
Interviews / Specials
Follow japan.internet.com
Popular
Access Ranking
Partner Sites










