サービス関連記事
やりたいこと
仕事でWindowsのサービスを扱った際、ログイン/ログアウトしたときに〇〇をする、みたいなことを書いたのだが、なにか、再起動したときのログインの動きが直感的ではないというか、妙な動きをしているように見えた。(まだログイン画面でログイン押してないのにサービス的にはログインしたことになって動き始めてる、とか。)
その辺を検証したかったのだが、Windowsの**「サービス」**というものを作ったことがなかったので、自宅でちゃちゃっと実験できる用意がなかった。
上の実験をするために、ついでに&急がば回れで、まずはC#でWindowsサービスをつくれるようになっておきたい。
やったこと
MSの公式と下記のページをかなり参考にさせていただき、C#でサービスを作った。
■C#でWindows Serviceを作る 1~5
https://qiita.com/yossihard/items/46f72af754915b242bed
■Tutorial: Create a Windows service app
https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/walkthrough-creating-a-windows-service-application-in-the-component-designer
手順
■プロジェクトの作成
まずプロジェクトを作る。
「新しいプロジェクトの作成」画面で、**「Windowsサービス(.NET Framework)」**を選択する。
(今回は.NETで作成。)
プロジェクトを開くと、下図のように、サービスの**[デザイン]**が開いた状態になっている。
■インストーラーの追加
このデザインの画面で、何もないところを右クリック > [インストーラーの追加] を選択する。
ProjectInstaller.csが追加される。
ProjectInstaller.csの**[デザイン]**が開いた状態になる。
SericeProcessInstallerとServiceInstallerがもとから入っている
ここに、サービスの基本設定をしていく。
■サービスの基本設定をする
SericeProcessInstallerの設定をする。
デザイナー上の「SericeProcessInstaller」を右クリ→プロパティ
Accountを設定する。
とりあえず、今回はサービスの作成をしたいだけで、管理者権限が必要になるようなことはしないので、Userにしておく。
次に、ServiceInstallerの設定をする。
- DelayedAutoStart:他の自動的に開始されるサービスが実行されるまで、サービスの開始を遅延するかどうか
- Description:サービスの説明
- DisplayName:サービス管理ツール等での表示用の名前
- ServiceName:サービス識別名
- StartType:サービスの開始タイミングを指定
※それぞれ、タスクマネージャとかサービス管理画面でみると、こういう関係。
StartTypeは下記を参照。
https://docs.microsoft.com/ja-jp/dotnet/api/system.serviceprocess.servicestartmode?view=netframework-4.8
BootとSystemはドライバ用で、普通のサービスはAutomaticかManualを選択しておけばよいっぽい。
■ビルドする
インストールする際に使うので、ビルドしてexeができたフォルダパスを控えておく。
例えば、私の環境だとC:\Users\masa\source\repos\WindowsService2\WindowsService2\bin\Debug
■作ったサービスをインストールする
開発者コマンドプロンプトを管理者権限で起動する。
開発者コマンドプロンプトで下記を実行する
上記を実行すると、ユーザー名とパスワードを入力する画面が表示されるので、管理者権限のあるユーザー名とパスワードを入力する。※ユーザー名の先頭には、**「コンピューター名\」**をつけること。
たとえば、PC名が「masa-PC」でユーザー名が「masa」だったら、下記のような感じ。
コンピュータ名はコントロールパネルの「システム」で見れる。
成功したら、こんなのが出る。
インストールしたサービスをservices.mscで見ると下記のような感じ。
インストールしたサービスをタスクマネージャーで見ると下記のような感じ。
■その他サービスの各種設定
デザイナー画面にしてるときに表示されるプロパティで、ServiceBaseの設定をする。
まず、電源周りのイベントを受け取りたい、Session関連のイベントを受け取りたいなど、必要な情報、うけとりたい情報を設定する。(いろいろ実験してたので、画像中のサービス名がservice 1だったり2だったりしてます。すみません)
また、Shutdownできるか、一時停止できるか、などもここで設定する。
上のプロパティでCanPauseAndContinue
をtrueにしてると、下記のようにサービス管理画面で右クリしたときのメニューで「一時停止」と「再起動」が押せるようになる。
■デバッグする
※管理者権限でVSを起動していない場合、アタッチしようとすると「管理者権限で再起動しますか?」ということを聞かれるので、管理者権限でVSを再起動してからもう一度アタッチする。
■各種イベント発生時にやりたいことを書く
ソリューションエクスプローラーで
service1.csを右クリックして、コードを表示、を選択し、コードを出す。
クラス名のところ(今回はService1)の右クリ→**[上書きを追加]**を押す。
(オーバーライドを追加するということ)
下記のような画面がでるので、必要なものだけチェックしてOKを押す。
今回はとりあえず実験的に、サービス管理画面でサービスを**「一時停止」して「再開」したときにオーバーライドしたメソッドを通ることをみたいので「OnPause」と「OnContinue」**にチェックを入れてOKを押す。
そのメソッドを通ったときにデバッグ用メッセージを出すようにコードを書く。
これで、サービスを一時停止→再開と操作してやると、メッセージが出る。
これで、いったんサービスを作って実際に動かす一通りの実験はできたことになる。
■コードを修正したときにサービスに反映させる
ビルドしなおしてそれを反映させようと思ったら、一度サービスをアンインストールして、ビルドしなおした後、再度インストールする。
- サービス停止
- ビルド
- サービスをアンインストール
- サービスをインストール
という順番。手動でやっていると面倒なので、下記のようなバッチを作っておくと楽かもしれない。
rem まず開発者用コマンドプロンプトを起動してから
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat"
rem サービス名(サービス管理画面の名前欄に出てくる名前)
set SERVICENAME=Service1DisplayName
set SOLUTIONPATH="C:\Users\masa\source\repos\WindowsService1\WindowsService1.sln"
set EXEPAH="C:\Users\masa\source\repos\WindowsService1\WindowsService1\bin\Debug\WindowsService1.exe"
rem サービス停止
net stop "%SERVICENAME%"
rem ビルドする
MSBuild %SOLUTIONPATH% /t:clean;rebuild /p:Configuration=Debug;Platform="Any CPU" > nul
if %ERRORLEVEL% neq 0 (
echo ErrorLevel:%ERRORLEVEL%
echo ビルド失敗
pause
exit
)
rem アンインストール実施
installutil -u %EXEPAH%
rem インストール実施
installutil /username=masa-PC\masa /password=******** /unattended %EXEPAH%
rem サービス再開
net start "%SERVICENAME%"
pause
参考
■C#でWindows Serviceを作る 1~5
https://qiita.com/yossihard/items/46f72af754915b242bed
■Tutorial: Create a Windows service app
https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/walkthrough-creating-a-windows-service-application-in-the-component-designer
■権限
https://www.atmarkit.co.jp/ait/articles/0905/08/news095.html