Windowsのサービスプロジェクトを作成してみます。

サービスプロジェクトとは

Visual Studioでは画面を持つ通常のアプリケーションの他に、サービスを作成することもできます。
サービスはアプリケーションと異なり、以下のようなソフトを作成したい場合に有効です。

  • 画面を持たないアプリケーションを作成したい場合
  • OSの起動時に自動で実行させたい場合
  • サインアウト中もアプリケーションを終了させることなく動作させたい場合
  • 24時間、365日稼働するような長時間稼働システムの場合

長時間稼働システムでは必要に合わせてサインインし、画面を持つアプリケーションを起動します。
通常はサインアウト、サービスで処理を行なうといった形で複数ソフトに分散させる運用を行います。

次からは具体的にサービスのプロジェクトを作成してみます。

プロジェクトを作成する

プロジェクトを作成します。

開発環境

OSはWindowsを使用します。
開発環境が動作するOSであれば他のバージョン(Windows 11など)でも構いません。

開発環境はVisual Studio 2022を使用します。
次に指定する.NET Frameworkは古いバージョンからありますので、古いVisual Studioでも構いません。

Visual Studio 2022を起動後、新しいプロジェクトの作成にて「Windows サービス (.NET Framework)」を選択します。
C#およびVisual Basicがありますが、C#を選択します。

プロジェクト作成後、F5をクリックして開始してみます。
アプリケーションでは空のフォーム画面で起動するのですが、サービスはそのままでは起動できません。
エラーメッセージを表示後に終了してしまいます。

このため、サービスを起動する場合にはもう少し手間が必要です。
以降にてサービスを起動するまでの作業について説明します。

サービスにインストーラーを追加

サービスを使えるようにするためにはサービスにインストーラーを追加する必要があります。

まず、ソリューションエクスプローラーからService1.csをダブルクリックします。
Service1.csのデザイン画面を表示します。
デザイン画面ですが、「クラスにコンポーネントを追加するには・・・」といった殺風景な画面が出てくればOKです。

次にService1.csデザイン画面の空白と部分を右クリックし、「インストーラーの追加」を選択します。

インストーラーが追加されます。
正しく追加された場合、ソリューションエクスプローラーに「ProjectInstaller.cs」ファイルが追加され、デザインとして「serviceProcessInstaller1」と「serviceInstaller1」がセットされます。

サービスインストーラにはサービスの情報を設定します。
ここでは特に重要な設定について記載します。

ServiceInstaller.ServiceName

サービスの名前を設定します。
サービス名は後述するサービスのインストールで作成するサービス名と同じ名前にする必要があります。
ここではService1とします。

ServiceInstaller.StartType

サービスの起動方法について設定します。
ここではOS起動と同時にサービスを起動するため「Automatic」に設定します。

ServiceProcessInstaller.Account

サービスの起動に使用するアカウントの種類を設定します。
ここでは「LocalSystem」に設定します。
LocalSystemは強い権限を持つため、OSに対して多くのアクセスが行えます。

設定後、プロジェクトをビルドします。
ビルドが成功すればプロジェクトフォルダ内のbin¥Debugフォルダにプロジェクト名の実行ファイル(.exe)が作成されます。これがサービスの実行ファイルになります。
サービスの場合も実態はプロセス(.exe)ファイルになります。

これでインストーラーを追加は完了です。

サービスのインストールと実行

Windowsにサービスをインストールします。

コマンドプロンプトを管理者で実行します。
その後、以下のコマンドを入力して実行します。

sc.exe create サービス名 binPath= “実行ファイルのパス”

  1. sc.exeはサービス管理するためのプログラムです。
    このコマンドからサービスをインストールするには後ろにcreate サービス名と入力します。
    サービス名はServiceNameと一致させる必要があります。ここではService1とします。
  2. 後ろにbinPath= “実行ファイルのパス”の形でサービスの実態(.exe)を指定します。
    ビルドしたbin¥Debugフォルダ内の実行ファイルパスを指定します。
  3. 実行するとCreateService SUCCESSと表示します。
  4. タスクマネージャーを確認し、Service1が追加されていることを確認します。
  5. Service1を右クリックし、開始できれば成功です。
追記

scコマンドが成功しない場合、以下を確認してください。

  • 「sc」で実行している場合、拡張子を付けて「sc.exe」とする
  • PowerShellで実行している場合、コマンドプロンプトで実行してみる
  • 管理者起動していない場合、管理者で起動する
  • 実行ファイルのパスはダブルコーテーションで囲む
  • binPath=と実行ファイルパスの間に半角スペースを入れる

多くの場合はこれで改善するかと思われます。

これでサービスのインストールは完了です。
アンインストールする場合は以下のコマンドを実行します。(必ずサービスを停止後にアンイストールしてください)

sc.exe delete サービス名

デバッグ

サービスをデバッグ方法について説明します。
デバッグはF5によるデバッグ開始でなく、開始中のサービスプロセスに対してアタッチします。

[デバッグ]メニューより「プロセスにアタッチ」を選択します。

次にプロセスにアタッチする対象を選択します。

  1. 接続の種類が「ローカル」に選択されていることを確認します。
  2. リスト下の「すべてのユーザーのプロセスを表示する」にチェックを付けます。
    これはサービスの起動アカウントがVisual Studioで起動したユーザーでなく異なるユーザー「LocalSystem」で起動しているためです。
  3. サービスの実態(.exe)を選択します。ここではservice_project.exeを選択します。
  4. 「アタッチ」をクリックします。

このサービスにアタッチするためにはVisual Studioが管理者権限で実行されている必要があります。
Visual Studioの昇格を求められた場合、「異なる資格情報で再起動」を選択します。

Visual Studioを管理者で起動後、再度アタッチします。
プロセスにアタッチすることができます。
アタッチ後はアプリケーションと同様にデバッグすることができますが、サービスではプログラム自体の構造も異なります。
こちらについては別の記事でご紹介します。

注意点として起動しているサービスプロセス(.exe)とアタッチしているソースコードが共通のものである必要があります。
ソースコードを変更した場合は都度、ビルドを行いサービスプロセス(.exe)を差し替える必要があります。
そのためには以下の作業が必要です。

  1. サービスを停止します。
  2. 最新のソースコード状態でビルドします。
    サービスを停止していない場合はサービスプロセス(.exe)を差し替えできないため、ビルドに失敗します。
  3. サービスを開始します。
  4. 再度アタッチし、デバッグを行います。

    とはいえ、ビルドの度にサービスの停止と開始を行なうのは少々手間になります。
    プロジェクトのビルドイベントにて、sc stop サービス名、sc start サービス名を入れることで上記の1〜3をビルドと一緒に行なうことができます。(必須ではありません)

    まとめ

    今回は最低限ですがサービスの作成を行ってみました。
    アプリケーションと異なりサービスの書籍は少ないのですが、マイクロソフト社のチュートリアルもあります。
    興味があれば一読することをお勧めします。