我的VS解决方案中有3个项目.其中一个是Web应用程序,第二个是Windows服务,最后一个是我的Web应用程序的安装项目.
我想要的是在我的安装项目中安装Web应用程序的结束,在我的自定义操作中尝试安装我的Windows服务,因为那时我已经拥有了程序集的位置.
我在代码中发现了一些您重复使用的错误,并修复了这些错误并将其清理干净了一些.同样,原始代码取自此处.
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 }
如果有人发现此代码有任何问题,请告诉我!
好的,这是真正为我工作的,它已经在多台具有不同操作系统的机器上进行了测试(Vista,XP,Win2k,Win2003服务器)
代码已经从这里获取,因此无论谁编写这段代码都可以获得完全的功劳.
将dll或源文件添加到项目中后,请确保添加ServiceTools命名空间,然后您可以访问一些非常方便的功能,例如...
//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");
我希望这有帮助.
请看一下这篇文章.
有时您可能希望以编程方式安装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); }
在为我的服务创建一个安装程序类的实例(非常基本)后,我所要做的就是调用:
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
安装它和
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
卸载服务.这里,调用代码与服务可执行文件位于同一程序集中.
要通过命令行安装服务,我所要做的就是通过命令行参数将其连接到可执行文件并测试System.Environment.UserInteractive
以确定它是否正在执行服务或者是否有人试图安装 - 卸载它...瞧...时髦的互操作......没有指针泄漏......
在两个类中共有大约20行代码就可以了.
要替换InstallUtil,只需看看ManagedInstallerClass.InstallHelper
通过使用Topshelf项目,您可以通过调用可执行文件来安装:
MyService.exe install
Topshelf还负责其他Windows Service管道。