C#で記述された標準の.NETWindowsサービスがあります。
InstallUtilを使用せずに自分自身をインストールできますか?サービスインストーラークラスを使用する必要がありますか?どのように使用すればよいですか?
次のように電話できるようにしたいと思います。
MyService.exe -install
そして、それは呼び出すのと同じ効果があります:
InstallUtil MyService.exe
C#で記述された標準の.NETWindowsサービスがあります。
InstallUtilを使用せずに自分自身をインストールできますか?サービスインストーラークラスを使用する必要がありますか?どのように使用すればよいですか?
次のように電話できるようにしたいと思います。
MyService.exe -install
そして、それは呼び出すのと同じ効果があります:
InstallUtil MyService.exe
はい、それは完全に可能です(つまり、私はまさにこれを行います)。適切なdll(System.ServiceProcess.dll)を参照し、インストーラークラスを追加するだけです...
[RunInstaller(true)]
public sealed class MyServiceInstallerProcess : ServiceProcessInstaller
{
public MyServiceInstallerProcess()
{
this.Account = ServiceAccount.NetworkService;
}
}
[RunInstaller(true)]
public sealed class MyServiceInstaller : ServiceInstaller
{
public MyServiceInstaller()
{
this.Description = "Service Description";
this.DisplayName = "Service Name";
this.ServiceName = "ServiceName";
this.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
}
}
static void Install(bool undo, string[] args)
{
try
{
Console.WriteLine(undo ? "uninstalling" : "installing");
using (AssemblyInstaller inst = new AssemblyInstaller(typeof(Program).Assembly, args))
{
IDictionary state = new Hashtable();
inst.UseNewContext = true;
try
{
if (undo)
{
inst.Uninstall(state);
}
else
{
inst.Install(state);
inst.Commit(state);
}
}
catch
{
try
{
inst.Rollback(state);
}
catch { }
throw;
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
ManagedInstallerクラスのInstallHelperメソッドを見てください。以下を使用してサービスをインストールできます。
string[] args;
ManagedInstallerClass.InstallHelper(args);
これはまさに InstallUtil が行うことです。引数は、InstallUtil と同じです。
この方法の利点は、レジストリをいじることがなく、InstallUtil と同じメカニズムを使用することです。
関連する作業の量は自明ではありませんが、いつでも古き良き WinAPI 呼び出しにフォールバックできます。.NET サービスを .NET 対応メカニズムでインストールする必要はありません。
インストールするには:
OpenSCManager
ます。CreateService
サービスを登録するために呼び出します。ChangeServiceConfig2
オプションで、説明を設定するために呼び出します。CloseServiceHandle
。アンインストールするには:
OpenSCManager
ます。OpenService
ます。DeleteService
によって返されたハンドルを呼び出して、サービスを削除しOpenService
ます。CloseServiceHandle
。ServiceInstaller
/を使用するよりもこれを好む主な理由ServiceProcessInstaller
は、独自のカスタム コマンド ライン引数を使用してサービスを登録できることです。たとえば、それを として登録し"MyApp.exe -service"
、ユーザーが引数なしでアプリを実行する場合、サービスをインストール/削除するための UI を提供できます。
Reflector を実行ServiceInstaller
すると、この簡単な説明に欠けている詳細を埋めることができます。
PS 明らかに、これには「InstallUtil MyService.exe を呼び出すのと同じ効果」はありません。特に、InstallUtil を使用してアンインストールすることはできません。しかし、おそらくこれはあなたにとって実際には厳しい要件ではなかったようです.
これは、サービスを記述するときに使用するクラスです。通常、サービスが呼び出されていないときに表示されるインタラクティブな画面があります。そこから、必要に応じてクラスを使用します。同じマシン上で複数の名前付きインスタンスを許可するため、InstanceID フィールド
サンプルコール
IntegratedServiceInstaller Inst = new IntegratedServiceInstaller();
Inst.Install("MySvc", "My Sample Service", "Service that executes something",
_InstanceID,
// System.ServiceProcess.ServiceAccount.LocalService, // this is more secure, but only available in XP and above and WS-2003 and above
System.ServiceProcess.ServiceAccount.LocalSystem, // this is required for WS-2000
System.ServiceProcess.ServiceStartMode.Automatic);
if (controller == null)
{
controller = new System.ServiceProcess.ServiceController(String.Format("MySvc_{0}", _InstanceID), ".");
}
if (controller.Status == System.ServiceProcess.ServiceControllerStatus.Running)
{
Start_Stop.Text = "Stop Service";
Start_Stop_Debugging.Enabled = false;
}
else
{
Start_Stop.Text = "Start Service";
Start_Stop_Debugging.Enabled = true;
}
クラス自体
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Win32;
namespace MySvc
{
class IntegratedServiceInstaller
{
public void Install(String ServiceName, String DisplayName, String Description,
String InstanceID,
System.ServiceProcess.ServiceAccount Account,
System.ServiceProcess.ServiceStartMode StartMode)
{
//http://www.theblacksparrow.com/
System.ServiceProcess.ServiceProcessInstaller ProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
ProcessInstaller.Account = Account;
System.ServiceProcess.ServiceInstaller SINST = new System.ServiceProcess.ServiceInstaller();
System.Configuration.Install.InstallContext Context = new System.Configuration.Install.InstallContext();
string processPath = Process.GetCurrentProcess().MainModule.FileName;
if (processPath != null && processPath.Length > 0)
{
System.IO.FileInfo fi = new System.IO.FileInfo(processPath);
String path = String.Format("/assemblypath={0}", fi.FullName);
String[] cmdline = { path };
Context = new System.Configuration.Install.InstallContext("", cmdline);
}
SINST.Context = Context;
SINST.DisplayName = String.Format("{0} - {1}", DisplayName, InstanceID);
SINST.Description = String.Format("{0} - {1}", Description, InstanceID);
SINST.ServiceName = String.Format("{0}_{1}", ServiceName, InstanceID);
SINST.StartType = StartMode;
SINST.Parent = ProcessInstaller;
// http://bytes.com/forum/thread527221.html
SINST.ServicesDependedOn = new String[] { "Spooler", "Netlogon", "Netman" };
System.Collections.Specialized.ListDictionary state = new System.Collections.Specialized.ListDictionary();
SINST.Install(state);
// http://www.dotnet247.com/247reference/msgs/43/219565.aspx
using (RegistryKey oKey = Registry.LocalMachine.OpenSubKey(String.Format(@"SYSTEM\CurrentControlSet\Services\{0}_{1}", ServiceName, InstanceID), true))
{
try
{
Object sValue = oKey.GetValue("ImagePath");
oKey.SetValue("ImagePath", sValue);
}
catch (Exception Ex)
{
System.Windows.Forms.MessageBox.Show(Ex.Message);
}
}
}
public void Uninstall(String ServiceName, String InstanceID)
{
//http://www.theblacksparrow.com/
System.ServiceProcess.ServiceInstaller SINST = new System.ServiceProcess.ServiceInstaller();
System.Configuration.Install.InstallContext Context = new System.Configuration.Install.InstallContext("c:\\install.log", null);
SINST.Context = Context;
SINST.ServiceName = String.Format("{0}_{1}", ServiceName, InstanceID);
SINST.Uninstall(null);
}
}
}