如何以编程方式在C#中安装Windows服务?
我在VS解决scheme中有3个项目。 其中一个是Web应用程序,第二个是Windows服务,最后一个是我的Web应用程序的安装项目。
我想要的是在我的安装项目中安装Web应用程序的最后阶段,在我的自定义操作中尝试安装我的Windows服务,因为到那时我已经拥有了程序集的位置。
好的,这里是真正为我工作的,它已经在不同操作系统(Vista,XP,Win2k,Win2003服务器)
代码已经从这里拿走了,所以完全相信写这段代码的人。
一旦你添加到你的项目的DLL或源文件确保添加ServiceTools名称空间,然后您可以访问一些非常方便的function,如…
//Installs and starts the service ServiceInstaller.InstallAndStart("MyServiceName", "MyServiceDisplayName", "C:\PathToServiceFile.exe"); //Removes the service ServiceInstaller.Uninstall("MyServiceName"); //Checks the status of the service ServiceInstaller.GetServiceStatus("MyServiceName"); //Starts the service ServiceInstaller.StartService("MyServiceName"); //Stops the service ServiceInstaller.StopService("MyServiceName"); //Check if service is installed ServiceInstaller.ServiceIsInstalled("MyServiceName");
我希望这有帮助。
我在代码中发现了一些错误,并且修复了这些错误,并将其清理了一下。 再次,原始代码从这里被采取。
public static class ServiceInstaller { private const int STANDARD_RIGHTS_REQUIRED = 0xF0000; private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010; [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; } #region OpenSCManager [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] static extern IntPtr OpenSCManager(string machineName, string databaseName, ScmAccessRights dwDesiredAccess); #endregion #region OpenService [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceAccessRights dwDesiredAccess); #endregion #region CreateService [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceAccessRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword); #endregion #region CloseServiceHandle [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseServiceHandle(IntPtr hSCObject); #endregion #region QueryServiceStatus [DllImport("advapi32.dll")] private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus); #endregion #region DeleteService [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DeleteService(IntPtr hService); #endregion #region ControlService [DllImport("advapi32.dll")] private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus); #endregion #region StartService [DllImport("advapi32.dll", SetLastError = true)] private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors); #endregion public static void Uninstall(string serviceName) { IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess); try { IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess); if (service == IntPtr.Zero) throw new ApplicationException("Service not installed."); try { StopService(service); if (!DeleteService(service)) throw new ApplicationException("Could not delete service " + Marshal.GetLastWin32Error()); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scm); } } public static bool ServiceIsInstalled(string serviceName) { IntPtr scm = OpenSCManager(ScmAccessRights.Connect); try { IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus); if (service == IntPtr.Zero) return false; CloseServiceHandle(service); return true; } finally { CloseServiceHandle(scm); } } public static void InstallAndStart(string serviceName, string displayName, string fileName) { IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess); try { IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess); if (service == IntPtr.Zero) service = CreateService(scm, serviceName, displayName, ServiceAccessRights.AllAccess, 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(scm); } } public static void StartService(string serviceName) { IntPtr scm = OpenSCManager(ScmAccessRights.Connect); try { IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Start); if (service == IntPtr.Zero) throw new ApplicationException("Could not open service."); try { StartService(service); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scm); } } public static void StopService(string serviceName) { IntPtr scm = OpenSCManager(ScmAccessRights.Connect); try { IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Stop); if (service == IntPtr.Zero) throw new ApplicationException("Could not open service."); try { StopService(service); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scm); } } private static void StartService(IntPtr service) { SERVICE_STATUS status = new SERVICE_STATUS(); StartService(service, 0, 0); var changedStatus = WaitForServiceStatus(service, ServiceState.StartPending, ServiceState.Running); if (!changedStatus) throw new ApplicationException("Unable to start service"); } private static void StopService(IntPtr service) { SERVICE_STATUS status = new SERVICE_STATUS(); ControlService(service, ServiceControl.Stop, status); var changedStatus = WaitForServiceStatus(service, ServiceState.StopPending, ServiceState.Stopped); if (!changedStatus) throw new ApplicationException("Unable to stop service"); } public static ServiceState GetServiceStatus(string serviceName) { IntPtr scm = OpenSCManager(ScmAccessRights.Connect); try { IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus); if (service == IntPtr.Zero) return ServiceState.NotFound; try { return GetServiceStatus(service); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scm); } } private static ServiceState GetServiceStatus(IntPtr service) { SERVICE_STATUS status = new SERVICE_STATUS(); if (QueryServiceStatus(service, status) == 0) throw new ApplicationException("Failed to query service status."); return status.dwCurrentState; } private static bool WaitForServiceStatus(IntPtr service, ServiceState waitStatus, ServiceState desiredStatus) { SERVICE_STATUS status = new SERVICE_STATUS(); QueryServiceStatus(service, status); if (status.dwCurrentState == desiredStatus) return true; int dwStartTickCount = Environment.TickCount; int dwOldCheckPoint = status.dwCheckPoint; while (status.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 = status.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000; else if (dwWaitTime > 10000) dwWaitTime = 10000; Thread.Sleep(dwWaitTime); // Check the status again. if (QueryServiceStatus(service, status) == 0) break; if (status.dwCheckPoint > dwOldCheckPoint) { // The service is making progress. dwStartTickCount = Environment.TickCount; dwOldCheckPoint = status.dwCheckPoint; } else { if (Environment.TickCount - dwStartTickCount > status.dwWaitHint) { // No progress made within the wait hint break; } } } return (status.dwCurrentState == desiredStatus); } private static IntPtr OpenSCManager(ScmAccessRights rights) { IntPtr scm = OpenSCManager(null, null, rights); if (scm == IntPtr.Zero) throw new ApplicationException("Could not connect to service control manager."); return scm; } } public enum ServiceState { Unknown = -1, // The state cannot be (has not been) retrieved. NotFound = 0, // The service is not known on the host server. Stopped = 1, StartPending = 2, StopPending = 3, Running = 4, ContinuePending = 5, PausePending = 6, Paused = 7 } [Flags] public enum ScmAccessRights { 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 ServiceAccessRights { 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 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 }
请让我知道是否有人发现这个代码有什么问题!
请看看这篇文章 。
有时您可能想要以编程方式安装Windows服务,但目标计算机没有InstallUtil.exe。
添加对System.Configuration.Install
的引用
使用下面的代码。
请注意, exeFileName
是InstallerClass.exe而不是ServiceClass.exe。
public static void InstallService(string exeFilename) { string[] commandLineOptions = new string[1] { "/LogFile=install.log" }; System.Configuration.Install.AssemblyInstaller installer = new System.Configuration.Install.AssemblyInstaller(exeFilename, commandLineOptions); installer.UseNewContext = true; installer.Install(null); installer.Commit(null); }
要卸载:
public static void UninstallService(string exeFilename) { string[] commandLineOptions = new string[1] { "/LogFile=uninstall.log" }; System.Configuration.Install.AssemblyInstaller installer = new System.Configuration.Install.AssemblyInstaller(exeFilename, commandLineOptions); installer.UseNewContext = true; installer.Uninstall(null); }
在为我的服务创build一个安装程序类的实例(非常基本)之后,我只需要调用:
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
安装它和
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
卸载服务。 调用代码在这里与服务可执行文件在同一个程序集中。
要通过命令行安装服务,我所要做的就是通过命令行参数将其连接到可执行文件,然后testingSystem.Environment.UserInteractive
以确定它是执行的服务还是正在尝试安装的用户 – 卸载它并瞧…没有时髦的互操作性的东西…没有指针泄漏…
总共约20行代码分布在两个class上。
replaceInstallUtil只是看看ManagedInstallerClass.InstallHelper
通过使用Topshelf项目,您可以通过调用您的可执行文件进行安装:
MyService.exe install
Topshelf也照顾其他Windows服务pipe道。
由于我面临的挑战是以编程方式安装在特定用户下运行的服务。 我扩展了InstallAndStart
方法来使用lp
和lpPassword
…
没有太多,但可能有帮助。
public static void InstallAndStart( string serviceName, string displayName, string fileName, string username, string password) { IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess); try { IntPtr service = OpenService( scm, serviceName, ServiceAccessRights.AllAccess); if (service == IntPtr.Zero) service = CreateService( scm, serviceName, displayName, ServiceAccessRights.AllAccess, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, fileName, null, IntPtr.Zero, null, username, password); if (service == IntPtr.Zero) throw new ApplicationException("Failed to install service."); try { StartService(service); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scm); } }
在这篇文章中,我读了所有的post和评论布仍然我不知道如何设置帐户types和StartType方法,当我要添加Windows服务。 这个代码示例工作正常,我的方面它只是添加一个服务自己的本地系统)但我准备安装程序我必须考虑StartMode和用户帐户types的方法,因为客户系统。
ServiceBootFlag枚举提供了StartType,但Accounttypes仍然是一个问题。
[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);
使用下面的代码来使用C#安装Windows服务:
public void InstallWinService(string winServicePath) { try { ManagedInstallerClass.InstallHelper(new string[] { winServicePath}); } catch (Exception) { throw; } }