sai’s diary

プログラミング関連の備忘録とつぶやきを書いています。

C# - Windows サービス アプリケーションのお試し

C#を扱うことになりそうなので、勉強のためWindowsのサービスアプリを動かしてみました。

ビルド環境の準備

ビルド環境はフリーのSharpDevelop 4.4を利用。
SharpDevelop 4.3用の日本語化パッチがあり、適用してみたところ大丈夫そうでした。

日本語化パッチの適用手順
  1. SharpDevelopを停止する。
  2. <SharpDevelopインストール先>\SharpDevelop\4.4\data\resources配下にStringResources.jp.resourcesファイルを配置。
  3. <SharpDevelopインストール先>\SharpDevelop\4.4\data\resources\languages\LanguageDefinition.xmlファイルを修正。
  4. SharpDevelopを起動して、メニューのTools→Options→UI LanguageからJapaniseを選択
修正前)<!--\<Languages name="Japanese"   code="jp"  icon="japan.png" />-->  
修正後)<Languages name="Japanese"   code="jp"  icon="japan.png" />  

動作確認

あとはSharpDevelopのメニューからファイル→新規作成→ソリューション、
C#Windowsアプリケーション→コンソールアプリケーションを選択するとひな形が作られるのでひな形をベースにMSDNサイトのサイトを見ながらコーディング。

方法 : プログラムでサービスを作成する
方法 : サービス アプリケーションにインストーラーを追加する
ServiceInstaller クラス
EventLog クラス

using System;
using System.ServiceProcess;
using System.Diagnostics;
using System.Collections;
using System.Configuration.Install;
using System.ComponentModel;
using System.Threading;

namespace SampleService {

    /* サービスインストール用クラス */
    [RunInstaller(true)]
    public class SampleServiceInstaller : Installer {

        private ServiceInstaller serviceInstaller;
        private ServiceProcessInstaller processInstaller;

        /* コンストラクタ */
        public SampleServiceInstaller() {
            /* プロセスのインストーラ設定 */
            processInstaller = new ServiceProcessInstaller();
            processInstaller.Account = ServiceAccount.LocalSystem;  /* アカウント=ローカルシステム */

            /* サービスのインストーラ設定 */
            serviceInstaller = new ServiceInstaller();
            serviceInstaller.ServiceName = "SampleService";         /* このサービスを識別するためにシステムが使用する名前を示す。(ServiceBase.ServiceNameと一致させること) */
            serviceInstaller.Description = "サンプルです。";         /* サービスの説明 */
            serviceInstaller.StartType   = ServiceStartMode.Manual; /* スタートアップの種類=手動 */

            Installers.Add(serviceInstaller);
            Installers.Add(processInstaller);
        }
    }


    public class Entry {
        /* Main関数 */
        public static void Main() {
            /* サービス開始 */
            ServiceBase.Run(new Service1());
            return;
        }
    }


    /* サービス定義用クラス */
    public class Service1: ServiceBase {

        /* イベントログ用メンバ変数 */
        private EventLog eventLog;

        /* コンストラクタ */
        public Service1() {
            ServiceName         = "SampleService";  /* サービス名 */
            CanPauseAndContinue = true;             /* サービスの一時停止・再開をサポート */
            AutoLog             = false;            /* 自動のログ出力を無効化 */

            eventLog        = new System.Diagnostics.EventLog();
            eventLog.Source = "SampleService";  /* イベントビューアーで表示されるソース */
        }

        /* サービス開始時のハンドラ(必須) */
        protected override void OnStart( string[] args ) {
            eventLog.WriteEntry("OnStart.",EventLogEntryType.Information);
        }

        /* サービス停止時のハンドラ(必須) */
        protected override void OnStop() {
            eventLog.WriteEntry("OnStop.",EventLogEntryType.Warning);
        }

        /* サービス一時停止時のハンドラ(オプション) */
        protected override void OnPause() {
            eventLog.WriteEntry("OnPause.",EventLogEntryType.Error );
        }

        /* サービス一時停止解除時のハンドラ(オプション) */
        protected override void OnContinue() {
            eventLog.WriteEntry("OnContinue.",EventLogEntryType.FailureAudit);
        }
    }
}

ビルド後にコマンドプロンプトを管理権限で起動して、下記コマンドを実施してサービスをインストール

cd c:\Windows\Microsoft.NET\Framework\v4.0.30319
InstallUtil.exe "<ビルドしたバイナリ>"

インストール後に「コンピュータの管理」から該当サービスを開始すればOKでした。
(AnyCPUでビルドしたバイナリをc:\Windows\Microsoft.NET\Framework64\v4.0.30319でインストールしようとしたら怒られました。)

尚、インストールコマンドに/uを指定するとアンインストールになります。

cd c:\Windows\Microsoft.NET\Framework\v4.0.30319
InstallUtil.exe "<ビルドしたバイナリ>" /u

C#はnewした領域を解放しなくて良いそうですが、違和感がありますね。
3.9 自動メモリ管理

他に参考になりそうなページ。
C# チュートリアル
C# プログラミング ガイド