using System; using System.Text; using System.ServiceProcess; using System.ComponentModel; using System.Runtime.InteropServices; using System.Globalization; using System.Collections; using System.Threading; namespace ZeroLevel.Services.AsService { public class ServiceInstaller : ComponentInstaller { private const string NetworkServiceName = "NT AUTHORITY\\NetworkService"; private const string LocalServiceName = "NT AUTHORITY\\LocalService"; //private EventLogInstaller eventLogInstaller; private string serviceName = ""; private string displayName = ""; private string description = ""; private string[] servicesDependedOn = new string[0]; private ServiceStartMode startType = ServiceStartMode.Manual; private bool delayedStartMode; private static bool environmentChecked; private static bool isWin9x; /// Indicates the friendly name that identifies the service to the user. /// The name associated with the service, used frequently for interactive tools. [DefaultValue("")] [ServiceProcessDescription("ServiceInstallerDisplayName")] public string DisplayName { get { return this.displayName; } set { if (value == null) { value = ""; } this.displayName = value; } } /// Gets or sets the description for the service. /// The description of the service. The default is an empty string (""). [DefaultValue("")] [ComVisible(false)] [ServiceProcessDescription("ServiceInstallerDescription")] public string Description { get { return this.description; } set { if (value == null) { value = ""; } this.description = value; } } /// Indicates the services that must be running for this service to run. /// An array of services that must be running before the service associated with this installer can run. [ServiceProcessDescription("ServiceInstallerServicesDependedOn")] public string[] ServicesDependedOn { get { return this.servicesDependedOn; } set { if (value == null) { value = new string[0]; } this.servicesDependedOn = value; } } /// Indicates the name used by the system to identify this service. This property must be identical to the of the service you want to install. /// The name of the service to be installed. This value must be set before the install utility attempts to install the service. /// The property is invalid. [DefaultValue("")] [TypeConverter("System.Diagnostics.Design.StringValueConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] [ServiceProcessDescription("ServiceInstallerServiceName")] public string ServiceName { get { return this.serviceName; } set { if (value == null) { value = ""; } if (!ServiceControllerExtensions.ValidServiceName(value)) { throw new ArgumentException(Res.GetString("ServiceName", value, 80.ToString(CultureInfo.CurrentCulture))); } this.serviceName = value; //this.eventLogInstaller.Source = value; } } /// Indicates how and when this service is started. /// A that represents the way the service is started. The default is Manual, which specifies that the service will not automatically start after reboot. /// The start mode is not a value of the enumeration. /// /// /// [DefaultValue(ServiceStartMode.Manual)] [ServiceProcessDescription("ServiceInstallerStartType")] public ServiceStartMode StartType { get { return this.startType; } set { if (!Enum.IsDefined(typeof(ServiceStartMode), value)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(ServiceStartMode)); } if (value != 0 && value != ServiceStartMode.System) { this.startType = value; return; } throw new ArgumentException(Res.GetString("ServiceStartType", value)); } } /// Gets or sets a value that indicates whether the service should be delayed from starting until other automatically started services are running. /// true to delay automatic start of the service; otherwise, false. The default is false. [DefaultValue(false)] [ServiceProcessDescription("ServiceInstallerDelayedAutoStart")] public bool DelayedAutoStart { get { return this.delayedStartMode; } set { this.delayedStartMode = value; } } /// Initializes a new instance of the class. public ServiceInstaller() { //this.eventLogInstaller = new EventLogInstaller(); //this.eventLogInstaller.Log = "Application"; //this.eventLogInstaller.Source = ""; //this.eventLogInstaller.UninstallAction = UninstallAction.Remove; //base.Installers.Add(this.eventLogInstaller); } internal static void CheckEnvironment() { if (ServiceInstaller.environmentChecked) { if (!ServiceInstaller.isWin9x) { return; } throw new PlatformNotSupportedException(Res.GetString("CantControlOnWin9x")); } ServiceInstaller.isWin9x = (Environment.OSVersion.Platform != PlatformID.Win32NT); ServiceInstaller.environmentChecked = true; if (!ServiceInstaller.isWin9x) { return; } throw new PlatformNotSupportedException(Res.GetString("CantInstallOnWin9x")); } /// Copies properties from an instance of to this installer. /// The from which to copy. /// The component you are associating with this installer does not inherit from . public override void CopyFromComponent(IComponent component) { if (!(component is ServiceBase)) { throw new ArgumentException(Res.GetString("NotAService")); } ServiceBase serviceBase = (ServiceBase)component; this.ServiceName = serviceBase.ServiceName; } /// Installs the service by writing service application information to the registry. This method is meant to be used by installation tools, which process the appropriate methods automatically. /// An that contains the context information associated with the installation. /// The installation does not contain a for the executable.-or- The file name for the assembly is null or an empty string.-or- The service name is invalid.-or- The Service Control Manager could not be opened. /// The display name for the service is more than 255 characters in length. /// The system could not generate a handle to the service. -or-A service with that name is already installed. /// /// /// /// /// public override void Install(IDictionary stateSaver) { base.Context.LogMessage(Res.GetString("InstallingService", this.ServiceName)); try { ServiceInstaller.CheckEnvironment(); string servicesStartName = null; string password = null; ServiceProcessInstaller serviceProcessInstaller = null; if (base.Parent is ServiceProcessInstaller) { serviceProcessInstaller = (ServiceProcessInstaller)base.Parent; } else { int num = 0; while (num < base.Parent.Installers.Count) { if (!(base.Parent.Installers[num] is ServiceProcessInstaller)) { num++; continue; } serviceProcessInstaller = (ServiceProcessInstaller)base.Parent.Installers[num]; break; } } if (serviceProcessInstaller == null) { throw new InvalidOperationException(Res.GetString("NoInstaller")); } switch (serviceProcessInstaller.Account) { case ServiceAccount.LocalService: servicesStartName = "NT AUTHORITY\\LocalService"; break; case ServiceAccount.NetworkService: servicesStartName = "NT AUTHORITY\\NetworkService"; break; case ServiceAccount.User: servicesStartName = serviceProcessInstaller.Username; password = serviceProcessInstaller.Password; break; } string text = base.Context.Parameters["assemblypath"]; if (string.IsNullOrEmpty(text)) { throw new InvalidOperationException(Res.GetString("FileName")); } if (text.IndexOf('"') == -1) { text = "\"" + text + "\""; } if (!ServiceInstaller.ValidateServiceName(this.ServiceName)) { throw new InvalidOperationException(Res.GetString("ServiceName", this.ServiceName, 80.ToString(CultureInfo.CurrentCulture))); } if (this.DisplayName.Length > 255) { throw new ArgumentException(Res.GetString("DisplayNameTooLong", this.DisplayName)); } string dependencies = null; if (this.ServicesDependedOn.Length != 0) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < this.ServicesDependedOn.Length; i++) { string text2 = this.ServicesDependedOn[i]; try { text2 = new ServiceController(text2, ".").ServiceName; } catch { } stringBuilder.Append(text2); stringBuilder.Append('\0'); } stringBuilder.Append('\0'); dependencies = stringBuilder.ToString(); } IntPtr intPtr = SafeNativeMethods.OpenSCManager(null, null, 983103); IntPtr intPtr2 = IntPtr.Zero; if (intPtr == IntPtr.Zero) { throw new InvalidOperationException(Res.GetString("OpenSC", "."), new Win32Exception()); } int serviceType = 16; int num2 = 0; for (int j = 0; j < base.Parent.Installers.Count; j++) { if (base.Parent.Installers[j] is ServiceInstaller) { num2++; if (num2 > 1) { break; } } } if (num2 > 1) { serviceType = 32; } try { intPtr2 = NativeMethods.CreateService(intPtr, this.ServiceName, this.DisplayName, 983551, serviceType, (int)this.StartType, 1, text, null, IntPtr.Zero, dependencies, servicesStartName, password); if (intPtr2 == IntPtr.Zero) { throw new Win32Exception(); } if (this.Description.Length != 0) { NativeMethods.SERVICE_DESCRIPTION sERVICE_DESCRIPTION = default(NativeMethods.SERVICE_DESCRIPTION); sERVICE_DESCRIPTION.description = Marshal.StringToHGlobalUni(this.Description); bool num3 = NativeMethods.ChangeServiceConfig2(intPtr2, 1u, ref sERVICE_DESCRIPTION); Marshal.FreeHGlobal(sERVICE_DESCRIPTION.description); if (!num3) { throw new Win32Exception(); } } if (Environment.OSVersion.Version.Major > 5 && this.StartType == ServiceStartMode.Automatic) { NativeMethods.SERVICE_DELAYED_AUTOSTART_INFO sERVICE_DELAYED_AUTOSTART_INFO = default(NativeMethods.SERVICE_DELAYED_AUTOSTART_INFO); sERVICE_DELAYED_AUTOSTART_INFO.fDelayedAutostart = this.DelayedAutoStart; if (!NativeMethods.ChangeServiceConfig2(intPtr2, 3u, ref sERVICE_DELAYED_AUTOSTART_INFO)) { throw new Win32Exception(); } } stateSaver["installed"] = true; } finally { if (intPtr2 != IntPtr.Zero) { SafeNativeMethods.CloseServiceHandle(intPtr2); } SafeNativeMethods.CloseServiceHandle(intPtr); } base.Context.LogMessage(Res.GetString("InstallOK", this.ServiceName)); } finally { base.Install(stateSaver); } } /// Indicates whether two installers would install the same service. /// true if calling on both of these installers would result in installing the same service; otherwise, false. /// A to which you are comparing the current installer. public override bool IsEquivalentInstaller(ComponentInstaller otherInstaller) { ServiceInstaller serviceInstaller = otherInstaller as ServiceInstaller; if (serviceInstaller == null) { return false; } return serviceInstaller.ServiceName == this.ServiceName; } private void RemoveService() { base.Context.LogMessage(Res.GetString("ServiceRemoving", this.ServiceName)); IntPtr intPtr = SafeNativeMethods.OpenSCManager(null, null, 983103); if (intPtr == IntPtr.Zero) { throw new Win32Exception(); } IntPtr intPtr2 = IntPtr.Zero; try { intPtr2 = NativeMethods.OpenService(intPtr, this.ServiceName, 65536); if (intPtr2 == IntPtr.Zero) { throw new Win32Exception(); } NativeMethods.DeleteService(intPtr2); } finally { if (intPtr2 != IntPtr.Zero) { SafeNativeMethods.CloseServiceHandle(intPtr2); } SafeNativeMethods.CloseServiceHandle(intPtr); } base.Context.LogMessage(Res.GetString("ServiceRemoved", this.ServiceName)); try { using (ServiceController serviceController = new ServiceController(this.ServiceName)) { if (serviceController.Status != ServiceControllerStatus.Stopped) { base.Context.LogMessage(Res.GetString("TryToStop", this.ServiceName)); serviceController.Stop(); int num = 10; serviceController.Refresh(); while (serviceController.Status != ServiceControllerStatus.Stopped && num > 0) { Thread.Sleep(1000); serviceController.Refresh(); num--; } } } } catch { } Thread.Sleep(5000); } /// Rolls back service application information written to the registry by the installation procedure. This method is meant to be used by installation tools, which process the appropriate methods automatically. /// An that contains the context information associated with the installation. /// /// /// /// /// public override void Rollback(IDictionary savedState) { base.Rollback(savedState); object obj = savedState["installed"]; if (obj != null && (bool)obj) { this.RemoveService(); } } private bool ShouldSerializeServicesDependedOn() { if (this.servicesDependedOn != null && this.servicesDependedOn.Length != 0) { return true; } return false; } /// Uninstalls the service by removing information about it from the registry. /// An that contains the context information associated with the installation. /// The Service Control Manager could not be opened.-or- The system could not get a handle to the service. /// /// /// /// /// public override void Uninstall(IDictionary savedState) { base.Uninstall(savedState); this.RemoveService(); } private static bool ValidateServiceName(string name) { if (name != null && name.Length != 0 && name.Length <= 80) { char[] array = name.ToCharArray(); for (int i = 0; i < array.Length; i++) { if (array[i] < ' ' || array[i] == '/' || array[i] == '\\') { return false; } } return true; } return false; } } }