前回のコメントでいろいろ言われていますが、無視します(ぉぃ
サービスの再起動ができた、と思いきや。。。実はできていません。
サービスが、単独で動いているなら、これでかまいません。ところが、サービスの詳細には「依存関係」というタブがあります。ここに、「このサービスに依存しているサービス」というものがあります。依存しているサービスがある場合、先に依存しているサービスを止めなければなりません。
残念ながら、ControlService では、依存しているサービスを止めることはできませんし、ここで上げたお題は「再起動」です。再起動である以上、止めたサービスを動かさなければなりません。StartService も、依存しているサービスを起動してくれる、なんてことはしてくれません。
ということは、開発者が、依存しているサービスを止め、止めたサービスを起動しなければならない、ということです。
では、前回書いた実行手順に追加してみましょう。
サービス マネージャにアクセスする。
指定のサービスにアクセスする。
依存しているサービスを含めて停止する。
依存しているサービスを列挙する。
依存しているサービスに対して、この項を適用する。
サービスに停止信号を送る。
停止するまで待つ。
状態を見る。
SERVICE_STOPPED でなければ1秒待つ。
SERVICE_STOPPED なら戻る。
累積で30秒待っていれば、タイムアウトとする。
そうでなければ繰り返す。
依存しているサービスを含めて起動する。
起動する。
起動するまで待つ。
状態を見る。
SERVICE_RUNNING でなければ1秒待つ。
SERVICE_RUNNING なら戻る。
累積で30秒待っていれば、タイムアウトとする。
そうでなければ繰り返す。
停止させたときに、起動していた依存するサービスを起動する。
で、コード上での該当する位置が、次のところになります。
// 指定のサービスを停止させ、停止するまで待つ。
// service : サービスのハンドラ
DWORD StopServiceWithWaiting(SC_HANDLE service)
{
if (service == NULL) { return ERROR_BAD_ARGUMENTS; }
// todo: 依存しているサービスを列挙する
// todo: それらを停止させる
SERVICE_STATUS status;
BOOL ret = ControlService(service, SERVICE_CONTROL_STOP, &status);
DWORD result = GetLastError();
if (ret == TRUE || result == ERROR_SERVICE_NOT_ACTIVE) {
result = WaitServiceUntilStatus(service, SERVICE_STOPPED);
}
return result;
}
// 指定のサービスを起動させ、起動するまで待つ。
// service : サービスのハンドラ
DWORD StartServiceWithWaiting(SC_HANDLE service)
{
if (service == NULL) { return ERROR_BAD_ARGUMENTS; }
BOOL ret = StartService(service, 0, NULL);
DWORD result = GetLastError();
if (ret == TRUE || result == ERROR_SERVICE_ALREADY_RUNNING) {
result = WaitServiceUntilStatus(service, SERVICE_RUNNING);
}
// todo: 停止させるときに依存していたサービスを起動する
return result;
}
依存しているサービスは、EnumDependentServices 関数で取得できます。取得できるのですが、少し考える必要があります。サービスを、停止させるところと起動するところが、別々の関数である、というところです。また、依存しているサービスに、さらに依存しているサービスがあるかもしれません。
サービスの中には、起動タイミングが「手動」になっていて、何かことがあるまで起動しないものがあります。また、「自動」であっても、何らかの都合で停止しているものがあります。こういった、“停止させなかったサービス”については、起動させたくありません。そこで、“停止させたサービス”をどこかで覚えておいて、それらのサービスだけ起動させたいと思います。
また、起動させる順番も、重要です。他のサービスに依存しているサービスは、その“他のサービス”が起動していないと、起動できません。つまり、停止させるときは末端から、起動させるときは根本から、行わなければなりません。
これらのことから、サービスの依存関係をたどりながら停止し、停止したサービスを覚えておき、停止したのと反対の順番で起動しなければなりません。
上のコードに、「依存するサービスで、動作中のものを列挙する処理」、「列挙したものについて、停止する処理」、「停止させたものを記録する処理」と「記録する場所」、「記録の逆順に起動する処理」を追加しなければなりません。
依存関係をたどるのは再帰呼び出しをすることでコーディング量を減らせますが、そうはいっても、手続き型でプログラムを書いていると、結構な修正量になると思いませんか?
こいつを、“オブジェクト指向”でコーディングしていれば、手続き指向と比較してどれくらい“楽な改造”になるかを、考察してみたいと思います。
投稿日時 : 2008年9月3日 21:50