初めて作る.NET WindowsサービスVisual Studio Magazine(5/7 ページ)

» 2005年02月01日 18時49分 公開
[Doug Thews,FTPOnline]

サービスのラッパークラスを作る

 さてサービスを作成してインストールしたところで、デスクトップクライアントアプリケーションがAppMonitorサービスとやり取りできるようにする方法を考えていこう。

 これを実現するもっとも簡単な方法は、サービスにOnCustomCommandイベントを実装しておき、それぞれのアプリケーションがモニタリングのコマンドをサービスに向けて送信できるようにする方法だ(これについてはすぐ後に述べる)。Windowsサービスは整数値だけを受け取ることができ、戻り値を返すことはできない。

 ユーザーサービスコマンドの規約に関する不十分なドキュメントによれば、サービスのカスタムユーザーコマンドは、128〜255の範囲でなければならないことになっている。128より小さな値は、システムレベルのコマンドとしてWindowsによって予約されているためだ。もし、この範囲外のカスタムサービスコマンドを送ると、次のような分かりづらいWin32例外を受け取ることになってしまう。

Cannot control service
<service_name> on machine ?.?

 AppMonitorサービスとのインタフェースを実装するもっとも簡単な方法は、すべてのデスクトップアプリケーションから利用できるラッパークラスを作成することだ。

 ラッパークラスの目的は、どこでどのようにモニタリングサービスが実装されているのかという詳細を隠すことだ。ラッパークラスを利用することで、クライアントアプリケーションにいっさい影響を与えることなく、モニタリングサービスを容易に設計変更できるようにもなる。

 さまざまなモニタリングコマンドのコードをエミュレートするMonitorWrapperクラスを作ろう。このクラスには、外部アプリケーションがモニタリングコマンドを送信できるひとつのメソッド(MonitorThis)を実装しておく(リスト2)。

リスト2■MonitorWrapperクラスを作る(VB.NET)。ラッパークラスを実装することで、Windowsサービスでどのようにモニタリングが実装されているのかという詳細を隠せる。これによりクライアントアプリケーションに影響を与えることなく、あとでサービスを変更できるようになる
Imports System.ServiceProcess
Public Class MonitorWrapper
Private Shared _strMachineName As String = "."
Private Shared _strMonitorServiceName As String _
= "AppMonitor"
Public Enum MonitorCode
MON_GATE_A_OPEN = 128
MON_GATE_B_OPEN = 129
MON_FIREALARM_A = 130
MON_SPRINKLER_A = 131
End Enum
Public Enum MonitorRC
RC_SUCCESS = 0
RC_NOSERVICE = -1
RC_SERVICESTOPPED = -2
RC_SERVICECOMMANDFAIL
End Enum

Public Shared Function MonitorThis(ByVal iCode _
As MonitorCode)
Dim objSvcHandle As _
ServiceProcess.ServiceController

' AppMonitorサービスのハンドルを開く
objSvcHandle = New _
ServiceController(_strMonitorServiceName, _
_strMachineName)
' ハンドルが作られたかを確認する
'(サービスがインストールされていないかもしれない)
If (objSvcHandle Is Nothing) Then
Return MonitorRC.RC_NOSERVICE
End If
' AppMonitorサービスが開始しているかを確認する
If (objSvcHandle.Status <> _
ServiceControllerStatus.Running) Then
Return MonitorRC.RC_SERVICESTOPPED
End If
Try
' コマンドを実行する
objSvcHandle.ExecuteCommand(iCode)
Return MonitorRC.RC_SUCCESS
Catch ex As Exception
Return MonitorRC.RC_SERVICECOMMANDFAIL
End Try
End Function

End Class

 Windowsサービスのクラス群を利用するには、ServiceProcess名前空間を参照する必要があるという点に注意しよう。

Imports System.ServiceProcess

 そしてServiceProcess.dllコンポーネントを参照設定するため、ソリューションエクスプローラの[参照設定]フォルダの下で[参照の追加]を選ぶ(画面3)。

画面3■ServiceProcess.dllへの参照を追加する。System.ServiceProcess名前空間を利用するプロジェクトでは、Windowsサービスクラスのオブジェクトやプロパティとやりとりするために、ServiceProcess.dllコンポーネントを明示的に参照設定しなければならない

 ServiceProcessコンポーネントを参照設定することで、Windowsサービスに関する中心的な機能を担うServiceControllerクラスを利用できるようになる。ServiceControllerオブジェクトを使うことで、サービスに問い合わせを出したり、サービスの制御、ほかサービスに関するほぼすべてのプロパティを設定することができる。

 MonitorThisメソッドの実装から分かるように、最初にすべきことは、AppMonitorサービスに関連付けられたServiceContollerオブジェクトのインスタンスを得ることだ。インスタンスが存在したら、ExecuteCommandメソッドを使ってサービスにコマンドを送信する前に、サービスが開始されているかどうかを確認する。

 さてMonitorWrapperクラスを書いたところで、ほかのデスクトップアプリケーションから使えるような配置を考えなければならない。一般にはクラスをGACに配置することになるが、本稿では話を簡単にするため、サンプルのデスクトップアプリケーション(SecurityController)において、MonitorWrapperクラスをプロジェクトの参照設定することにする。

© Copyright 2001-2005 Fawcette Technical Publications

注目のテーマ