何となく Blog by Jitta
Microsoft .NET 考

目次

Blog 利用状況
  • 投稿数 - 585
  • 記事 - 18
  • コメント - 2121
  • トラックバック - 181
ニュース
  • 検索エンジンで来られた方へ:
    お望みの情報は見つかりましたか? よろしければ、コメント欄にどのような情報を探していたのか、ご記入ください。
It's ME!
  • はなおか じった
  • 世界遺産の近くに住んでます。
  • Microsoft MVP for Visual Developer ASP/ASP.NET 10, 2004 - 9, 2009
サイト内検索
広告

記事カテゴリ

書庫

日記カテゴリ

ギャラリ

その他

わんくま同盟

同郷

 

前回のコメントでいろいろ言われていますが、無視します(ぉぃ

サービスの再起動ができた、と思いきや。。。実はできていません。

サービスが、単独で動いているなら、これでかまいません。ところが、サービスの詳細には「依存関係」というタブがあります。ここに、「このサービスに依存しているサービス」というものがあります。依存しているサービスがある場合、先に依存しているサービスを止めなければなりません。

残念ながら、ControlService では、依存しているサービスを止めることはできませんし、ここで上げたお題は「再起動」です。再起動である以上、止めたサービスを動かさなければなりません。StartService も、依存しているサービスを起動してくれる、なんてことはしてくれません。

ということは、開発者が、依存しているサービスを止め、止めたサービスを起動しなければならない、ということです。

では、前回書いた実行手順に追加してみましょう。

  1. サービス マネージャにアクセスする。

  2. 指定のサービスにアクセスする。

  3. 依存しているサービスを含めて停止する。

    1. 依存しているサービスを列挙する。

    2. 依存しているサービスに対して、この項を適用する。

    3. サービスに停止信号を送る。

    4. 停止するまで待つ。

      1. 状態を見る。

      2. SERVICE_STOPPED でなければ1秒待つ。
        SERVICE_STOPPED なら戻る。

      3. 累積で30秒待っていれば、タイムアウトとする。
        そうでなければ繰り返す。

  4. 依存しているサービスを含めて起動する。

    1. 起動する。

    2. 起動するまで待つ。

      1. 状態を見る。

      2. SERVICE_RUNNING でなければ1秒待つ。
        SERVICE_RUNNING なら戻る。

      3. 累積で30秒待っていれば、タイムアウトとする。
        そうでなければ繰り返す。

    3. 停止させたときに、起動していた依存するサービスを起動する。


で、コード上での該当する位置が、次のところになります。


// 指定のサービスを停止させ、停止するまで待つ。
// 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
コメント
No comments posted yet.
タイトル  
名前  
Url
コメント