技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

.NET を理解する7

サービスの作成

.NET のサービスを作成するにあたり、色々調べてみる。

  • ServiceBase クラスを継承してサービス作る
  • ServiceController クラスで .NET アプリからサービスの開始停止を制御できる
  • ServiceControllerPermission サービス コントローラに対するコード アクセス セキュリティ アクセス許可を制御できるようにします。
  • ServiceInstaller でインストール時のサービス名とか、表示とかをいじる。
  • ServiceProcessInstaller サービスが動作するときの設定とか、アカウント、ユーザ権限などを操作します。
  • ServiceChangeDescription ターミナルサービスのセッション変更の理由を示します。
  • ServiceChangeReason ターミナル サービスのセッション変更の通知理由を示します。

と、クラスの概要。
まぁなんとなくはわかるにしても、作らなくてはだめぽ。
ということで、ExpressEdition でもできるサービス開発をする。

俺俺サービス作ってみる。

基本的にバックグラウンドで実行されるサービスってのを作ってみる。
Windows サービス作る場合、ServiceBase を継承して、適当なイベントメソッドをオーバライドして作る。

このサイトから1分おきにタイトル拾ってファイルに書き込むサービスを作る。
手元に VisualStudio2008 Standard しかねえwプロジェクトテンプレが無いが、根性でどうにかする。

class BlogLoader
{
    public static string[] GetNazogengoTitles()
    {
        XElement blog = XElement.Load("http://d.hatena.ne.jp/white-azalea/rss");
        XNamespace xmlns = "http://purl.org/rss/1.0/";
        var titles = from p in blog.Elements()
                     where p.Name.LocalName == "item"
                     select p.Element(xmlns + "title").Value;
        return titles.ToArray();
    }
}

public class SampleService : System.ServiceProcess.ServiceBase
{
    System.Timers.Timer timer;
    static void Main(string[] args)
    {
        System.ServiceProcess.ServiceBase[] ServicesToRun
            = new System.ServiceProcess.ServiceBase[] { new SampleService() };
        System.ServiceProcess.ServiceBase.Run(ServicesToRun);
        Console.ReadLine();
    }

    protected override void OnStart(string[] args)
    {
        base.OnStart(args);
        timer = new System.Timers.Timer(60000);
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
        timer.Enabled = true;
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        string filePath = this.Application.info.DirectoryPath.ToString() + "\\Files";
        string[] results = BlogLoader.GetNazogengoTitles();

        // ディレクトリが存在するか
        if (!System.IO.Directory.Exists(filePath))
        {
            System.IO.Directory.CreateDirectory(filePath);
        }

        // ファイル名を作成
        filePath = filePath + "\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";

        // ファイル作成と書き込み
        using (System.IO.StreamWriter writer = new System.IO.StreamWriter(filePath))
        {
            foreach (string single in results)
            {
                writer.WriteLine(single);
            }
        }
    }

    protected override void OnStop()
    {
        base.OnStop();
        timer.Enabled = false;
    }
}

サービスプロセスを作ったところで、このままではインストールもままならない。
ので、根性でサービスインストーラを作る。これで InstallUtil でどうにかできる。

namespace ServiceInstaller
{
    using System;
    using System.ServiceProcess;
    using System.Configuration.Install;
    using System.Collections.Generic;

    [System.ComponentModel.RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private System.ServiceProcess.ServiceInstaller serviceInstaller;
        private ServiceProcessInstaller processInstaller;

        // 以下にこのプロジェクトが依存するサービスを記述
        private string[] param = new string[] { };

        public ProjectInstaller() {
            processInstaller = new ServiceProcessInstaller();
            serviceInstaller = new System.ServiceProcess.ServiceInstaller();

            // Service will run under system account
            processInstaller.Account = ServiceAccount.LocalSystem;

            // Service will have Start Type of Automatic
            serviceInstaller.StartType = ServiceStartMode.Automatic;

            serviceInstaller.ServicesDependedOn = this.param;
            serviceInstaller.ServiceName = "NazoChecker";
            serviceInstaller.Description = "謎言語使いの言動を逐次チェックします。";

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

かなり根性。
そしてサクッとインストール!

PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v2.0.50727;
installutil SampleService.exe

うごけぇええええええ!!!

インストール段階で例外が発生しました。
System.Security.SecurityException: ソースが見つかりませんでしたが、いくつかまた
はすべてのログを検索できませんでした。アクセス不可能なログ: Security
orz

WindowsXP はコレで動くのですが、Windows7/Vista 連中はセキュリティががががが、、、、、
cmd.exe を管理者権限で再実行。
尚、アンインストールは

installutil /u SampleService.exe

Windows7 で this.Application.info.DirectoryPath.ToString() のディレクトリは、「C:\Windows\System32\」っぽい。
たぶん XP とかもではないかなー