さてサービスを作成してインストールしたところで、デスクトップクライアントアプリケーションが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)。
ServiceProcessコンポーネントを参照設定することで、Windowsサービスに関する中心的な機能を担うServiceControllerクラスを利用できるようになる。ServiceControllerオブジェクトを使うことで、サービスに問い合わせを出したり、サービスの制御、ほかサービスに関するほぼすべてのプロパティを設定することができる。
MonitorThisメソッドの実装から分かるように、最初にすべきことは、AppMonitorサービスに関連付けられたServiceContollerオブジェクトのインスタンスを得ることだ。インスタンスが存在したら、ExecuteCommandメソッドを使ってサービスにコマンドを送信する前に、サービスが開始されているかどうかを確認する。
さてMonitorWrapperクラスを書いたところで、ほかのデスクトップアプリケーションから使えるような配置を考えなければならない。一般にはクラスをGACに配置することになるが、本稿では話を簡単にするため、サンプルのデスクトップアプリケーション(SecurityController)において、MonitorWrapperクラスをプロジェクトの参照設定することにする。
© Copyright 2001-2005 Fawcette Technical Publications