我有一个用C#编写的标准.NET Windows服务.
它可以在不使用InstallUtil的情况下自行安装吗?我应该使用服务安装程序类吗?我该怎么用?
我希望能够拨打以下电话:
MyService.exe -install
它将具有与调用相同的效果:
InstallUtil MyService.exe
Marc Gravell.. 154
是的,这是完全可能的(即我这样做); 你只需要引用正确的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); } }
+ 1d,另见http://stackoverflow.com/questions/1449994/inno-setup-for-windows-service (18认同)
@MarcGravell你应该在这里包含代码,因为如果没有它,这个答案就不是很有用了. (5认同)
adrianbanks.. 39
看一下ManagedInstaller类的InstallHelper方法.您可以使用以下方法安装服务:
string[] args; ManagedInstallerClass.InstallHelper(args);
这正是InstallUtil所做的.参数与InstallUtil相同.
这种方法的好处是它不涉及注册表中的混乱,它使用与InstallUtil相同的机制.
是的,这是完全可能的(即我这样做); 你只需要引用正确的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.
运行反射器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); } } }
上面的示例对我而言并不真正有用,并且作为第一解决方案到论坛的链接非常难以理解。这是我(部分)编写的一个类,其余部分与我发现的该链接隐藏在一起
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.ServiceProcess; using System.Runtime.InteropServices; namespace SystemControl { class Services { #region "Environment Variables" public static string GetEnvironment(string name, bool ExpandVariables=true) { if ( ExpandVariables ) { return System.Environment.GetEnvironmentVariable( name ); } else { return (string)Microsoft.Win32.Registry.LocalMachine.OpenSubKey( @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment\" ).GetValue( name, "", Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames ); } } public static void SetEnvironment( string name, string value ) { System.Environment.SetEnvironmentVariable(name, value); } #endregion #region "ServiceCalls Native" public static ServiceController[] List { get { return ServiceController.GetServices(); } } public static void Start( string serviceName, int timeoutMilliseconds ) { ServiceController service=new ServiceController( serviceName ); try { TimeSpan timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds ); service.Start(); service.WaitForStatus( ServiceControllerStatus.Running, timeout ); } catch { // ... } } public static void Stop( string serviceName, int timeoutMilliseconds ) { ServiceController service=new ServiceController( serviceName ); try { TimeSpan timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds ); service.Stop(); service.WaitForStatus( ServiceControllerStatus.Stopped, timeout ); } catch { // ... } } public static void Restart( string serviceName, int timeoutMilliseconds ) { ServiceController service=new ServiceController( serviceName ); try { int millisec1=Environment.TickCount; TimeSpan timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds ); service.Stop(); service.WaitForStatus( ServiceControllerStatus.Stopped, timeout ); // count the rest of the timeout int millisec2=Environment.TickCount; timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds-( millisec2-millisec1 ) ); service.Start(); service.WaitForStatus( ServiceControllerStatus.Running, timeout ); } catch { // ... } } public static bool IsInstalled( string serviceName ) { // get list of Windows services ServiceController[] services=ServiceController.GetServices(); // try to find service name foreach ( ServiceController service in services ) { if ( service.ServiceName==serviceName ) return true; } return false; } #endregion #region "ServiceCalls API" private const int STANDARD_RIGHTS_REQUIRED = 0xF0000; private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010; [Flags] public enum ServiceManagerRights { Connect = 0x0001, CreateService = 0x0002, EnumerateService = 0x0004, Lock = 0x0008, QueryLockStatus = 0x0010, ModifyBootConfig = 0x0020, StandardRightsRequired = 0xF0000, AllAccess = (StandardRightsRequired | Connect | CreateService | EnumerateService | Lock | QueryLockStatus | ModifyBootConfig) } [Flags] public enum ServiceRights { QueryConfig = 0x1, ChangeConfig = 0x2, QueryStatus = 0x4, EnumerateDependants = 0x8, Start = 0x10, Stop = 0x20, PauseContinue = 0x40, Interrogate = 0x80, UserDefinedControl = 0x100, Delete = 0x00010000, StandardRightsRequired = 0xF0000, AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig | QueryStatus | EnumerateDependants | Start | Stop | PauseContinue | Interrogate | UserDefinedControl) } public enum ServiceBootFlag { Start = 0x00000000, SystemStart = 0x00000001, AutoStart = 0x00000002, DemandStart = 0x00000003, Disabled = 0x00000004 } public enum ServiceState { Unknown = -1, // The state cannot be (has not been) retrieved. NotFound = 0, // The service is not known on the host server. Stop = 1, // The service is NET stopped. Run = 2, // The service is NET started. Stopping = 3, Starting = 4, } public enum ServiceControl { Stop = 0x00000001, Pause = 0x00000002, Continue = 0x00000003, Interrogate = 0x00000004, Shutdown = 0x00000005, ParamChange = 0x00000006, NetBindAdd = 0x00000007, NetBindRemove = 0x00000008, NetBindEnable = 0x00000009, NetBindDisable = 0x0000000A } public enum ServiceError { Ignore = 0x00000000, Normal = 0x00000001, Severe = 0x00000002, Critical = 0x00000003 } [StructLayout(LayoutKind.Sequential)] private class SERVICE_STATUS { public int dwServiceType = 0; public ServiceState dwCurrentState = 0; public int dwControlsAccepted = 0; public int dwWin32ExitCode = 0; public int dwServiceSpecificExitCode = 0; public int dwCheckPoint = 0; public int dwWaitHint = 0; } [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerA")] private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, ServiceManagerRights dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "OpenServiceA", CharSet = CharSet.Ansi)] private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceRights dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")] private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword); [DllImport("advapi32.dll")] private static extern int CloseServiceHandle(IntPtr hSCObject); [DllImport("advapi32.dll")] private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", SetLastError = true)] private static extern int DeleteService(IntPtr hService); [DllImport("advapi32.dll")] private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", EntryPoint = "StartServiceA")] private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors); ////// Takes a service name and tries to stop and then uninstall the windows serviceError /// /// The windows service name to uninstall public static void Uninstall(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.StandardRightsRequired | ServiceRights.Stop | ServiceRights.QueryStatus); if (service == IntPtr.Zero) { throw new ApplicationException("Service not installed."); } try { StopService(service); int ret = DeleteService(service); if (ret == 0) { int error = Marshal.GetLastWin32Error(); throw new ApplicationException("Could not delete service " + error); } } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scman); } } ////// Accepts a service name and returns true if the service with that service name exists /// /// The service name that we will check for existence ///True if that service exists false otherwise public static bool ServiceIsInstalled(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus); if (service == IntPtr.Zero) return false; CloseServiceHandle(service); return true; } finally { CloseServiceHandle(scman); } } ////// Takes a service name, a service display name and the path to the service executable and installs / starts the windows service. /// /// The service name that this service will have /// The display name that this service will have /// The path to the executable of the service public static void InstallAndStart(string ServiceName, string DisplayName, string FileName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect | ServiceManagerRights.CreateService); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus | ServiceRights.Start); if (service == IntPtr.Zero) { service = CreateService(scman, ServiceName, DisplayName, ServiceRights.QueryStatus | ServiceRights.Start, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, FileName, null, IntPtr.Zero, null, null, null); } if (service == IntPtr.Zero) { throw new ApplicationException("Failed to install service."); } try { StartService(service); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scman); } } ////// Takes a service name and starts it /// /// The service name public static void StartService(string Name) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Start); if (hService == IntPtr.Zero) { throw new ApplicationException("Could not open service."); } try { StartService(hService); } finally { CloseServiceHandle(hService); } } finally { CloseServiceHandle(scman); } } ////// Stops the provided windows service /// /// The service name that will be stopped public static void StopService(string Name) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Stop); if (hService == IntPtr.Zero) { throw new ApplicationException("Could not open service."); } try { StopService(hService); } finally { CloseServiceHandle(hService); } } finally { CloseServiceHandle(scman); } } ////// Stars the provided windows service /// /// The handle to the windows service private static void StartService(IntPtr hService) { SERVICE_STATUS status = new SERVICE_STATUS(); StartService(hService, 0, 0); WaitForServiceStatus(hService, ServiceState.Starting, ServiceState.Run); } ////// Stops the provided windows service /// /// The handle to the windows service private static void StopService(IntPtr hService) { SERVICE_STATUS status = new SERVICE_STATUS(); ControlService(hService, ServiceControl.Stop, status); WaitForServiceStatus(hService, ServiceState.Stopping, ServiceState.Stop); } ////// Takes a service name and returns the /// The service name that we will check for hisServiceState
of the corresponding service ///ServiceState
///The ServiceState of the service we wanted to check public static ServiceState GetServiceStatus(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, ServiceName, ServiceRights.QueryStatus); if (hService == IntPtr.Zero) { return ServiceState.NotFound; } try { return GetServiceStatus(hService); } finally { CloseServiceHandle(scman); } } finally { CloseServiceHandle(scman); } } ////// Gets the service state by using the handle of the provided windows service /// /// The handle to the service ///The private static ServiceState GetServiceStatus(IntPtr hService) { SERVICE_STATUS ssStatus = new SERVICE_STATUS(); if (QueryServiceStatus(hService, ssStatus) == 0) { throw new ApplicationException("Failed to query service status."); } return ssStatus.dwCurrentState; } ///ServiceState
of the service/// Returns true when the service status has been changes from wait status to desired status /// ,this method waits around 10 seconds for this operation. /// /// The handle to the service /// The current state of the service /// The desired state of the service ///bool if the service has successfully changed states within the allowed timeline private static bool WaitForServiceStatus(IntPtr hService, ServiceState WaitStatus, ServiceState DesiredStatus) { SERVICE_STATUS ssStatus = new SERVICE_STATUS(); int dwOldCheckPoint; int dwStartTickCount; QueryServiceStatus(hService, ssStatus); if (ssStatus.dwCurrentState == DesiredStatus) return true; dwStartTickCount = Environment.TickCount; dwOldCheckPoint = ssStatus.dwCheckPoint; while (ssStatus.dwCurrentState == WaitStatus) { // Do not wait longer than the wait hint. A good interval is // one tenth the wait hint, but no less than 1 second and no // more than 10 seconds. int dwWaitTime = ssStatus.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000; else if (dwWaitTime > 10000) dwWaitTime = 10000; System.Threading.Thread.Sleep(dwWaitTime); // Check the status again. if (QueryServiceStatus(hService, ssStatus) == 0) break; if (ssStatus.dwCheckPoint > dwOldCheckPoint) { // The service is making progress. dwStartTickCount = Environment.TickCount; dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if (Environment.TickCount - dwStartTickCount > ssStatus.dwWaitHint) { // No progress made within the wait hint break; } } } return (ssStatus.dwCurrentState == DesiredStatus); } ////// Opens the service manager /// /// The service manager rights ///the handle to the service manager private static IntPtr OpenSCManager(ServiceManagerRights Rights) { IntPtr scman = OpenSCManager(null, null, Rights); if (scman == IntPtr.Zero) { throw new ApplicationException("Could not connect to service control manager."); } return scman; } #endregion } }
要安装服务,请运行InstallAndStart命令,如下所示:
SystemControl.InstallAndStart( "apache", "Apache Web Server", @"""c:\apache\bin\httpd.exe"" -k runservice" );
确保正在运行该程序的帐户具有安装服务的权限。您可以始终在程序上以“以管理员身份运行”。
我还包括了几个用于非API访问的命令,这些命令不会安装或删除服务,但是您可以列出它们并控制多个命令(启动,停止,重新启动)。您实际上只需要提升安装或删除服务的权限。
还有一些用于获取和设置环境变量的命令,例如OPENSSL_CONF
或TEMP
。在大多数情