none
win8における再起動とサービス RRS feed

  • 質問

  • Windows Service をC++で作っています。
    win8上での動作を検証していたところ、問題が発覚しました。

    SCMなどからサービスを停止する場合は、正しく終了処理が行われるのですが、「再起動」を行うと終了処理を行わずにサービスが停止してしまいます。

    ちなみに、「シャットダウン」の場合は、ハイバネーションがおこなわれるらしく、次回、起動済みのサービスが、そのまま継続しているようです。

    そのサービスは、vc6時代にATL-COM-Wizardで起こしたものだったので、vs2008でATL-COM-Wizardで起こし直したものでも試しました。

    原因を調べたところ、SERVICE_CONTROL_STOP、SERVICE_CONTROL_SHUTDOWN が通知されていないようです。また、win7での動作との相違点を調べたところ、win7ではシステムログに「Service Control Manager」によるサービスの停止が記録されますが、win8では記録されません。

    win8上で動作するwindows-serviceが「再起動」を検出する方法はありませんか?


    2012年10月26日 3:11

回答

すべての返信

  • Windows 8では本当の意味での再起動はほとんど行われなくなりました。1年前のブログ記事ですが、Windows 8 でお届けする高速な起動とかどうぞ。

    サービスとしてはハイバネーションを検出すればいいですし、そもそもハイバネーションはWindows 7にも(というよりもっと前から)存在しました。それらに対応しなくてもよいのでしょうか?

    2012年10月26日 6:26
  • サービスハンドラのパラメータはVC6のころと比べるとかなり拡張されています。とくに、Win8では、ストアアプリ(こいつ自身はWindowsサービスの特殊な形で動作しています)との兼ね合いもあり、さらにいろいろ変わっていることが想定されます。

    確認してないので、わからない部分はありますが、ATLであれば、OnUnknownRequest() でハンドリングしていないメッセージが来ていないかを確認してみてはいかがでしょう?

    また、ATLでは直接サポートしていませんが(呼び出していないと思います)、RegisterServiceCtrlHandlerEx で拡張されたサービスハンドラを使うという手もあります。

    こっちであれば通知を受けられるのならば、CAtlServiceModuleT<>::ServieMain() を丸ごと、自分の派生クラスにコピーして、RegisterServiceCtrlHandler を Ex に変更し、HanderEx の追加を行えば対応できると思います。

    APIレベルで、ちょっと検索しただけで試してないので、拾えるかどうかはわかりません。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年10月26日 6:27
  • ええ、ハイバネーションからの復帰時に、プロセスの保持するメモリー内容が変化していなければ問題ありません。もっとも、変化すれば、ハーバネーションとは言いがたいと思いますが...

    今回の問題は、起動中のサービスが、後始末の機会を与えられずに終了してしまうケースがあることなのです。

    2012年10月27日 5:01
  • Handler()が受ける通知は、OnUnknownRequest()を含めて全て点検しました。HandlerEx()を試してみます。
    2012年10月27日 5:04
  • RegisterServiceCtrlHandlerEx だめでした。
    管理ツール→「サービス」など、SCMからの停止、開始などはトラップしてのロギングができるのですが、相変わらずwin8の「再起動」だけは捕まえることができませんでした。

    そもそも、win8では「再起動」時の「サービスの停止」をやっているのかが疑問となっっております。

    2012年10月29日 1:25
  • HanderExに何が届いているのか確認してみませんか?

    従来のSERVICE_CONTROL_SHUTDOWNだけを見ているのでしょうか? Windows VistaからSERVICE_CONTROL_PRESHUTDOWNを受け取れるそうです。Windows 8からはSERVICE_CONTROL_USERMODEREBOOTも受け取れるそうです。特にSERVICE_CONTROL_USERMODEREBOOTについてはググってもドキュメントが出てきませんね。

    2012年10月29日 1:48
  • ご支援ありがとうございます。

    佐祐理さま、

    Handler/HandlerEx が受ける整数型の引数を、そのままロギングしているので、Handler(Ex)が呼ばれれば記録されると思っています。

    私の実装に問題があり、トラップし損ねている可能性は十分に意識しておりまして、「再起動」や「ハイバネーション」以外では正しくトラップできていることを確認いたしました。

    私としてはwin8のbugの可能性を感じており、MSDNのインシデントを使っての調査依頼を出そうとしています。結果が判明したら報告させていただきます。

    2012年10月29日 2:17
  • 念のため、SetServiceStatus()でSERVICE_ACCEPT_PRESHUTDOWNやSERVICE_ACCEPT_USERMODEREBOOTを指定した上で、受信できないのですよね?
    2012年10月29日 2:23
  • うまくいきました。ありがとうございます。

    CAtlServiceModuleT::SetServiceStatus(DWORD)
    ではなく、win32の

    WINADVAPI
    BOOL
    WINAPI
    SetServiceStatus(
        __in        SERVICE_STATUS_HANDLE   hServiceStatus,
        __in        LPSERVICE_STATUS        lpServiceStatus
        );
    だったのですね。

    CAtlServiceModuleT 派生クラスのコンストラクタで、

            m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    などとすることにより、SERVICE_CONTROL_SHUTDOWN(=5)の通知を受け取ることができました。

    win8での「再起動」時に、SCMを通じてのサービス停止が行われない点には互換性の観点からの不満がありますが、何とか後始末を実装することができそうです。

    ありがとうございました。

    2012年10月29日 3:19