Как программно установить Windows-сервис на C #?

У меня есть 3 проекта в моем VS-решении. Одним из них является веб-приложение, второе – служба Windows, а последний – проект установки для моего веб-приложения.

То, что я хочу, – это к концу установки веб-приложения в моем проекте установки, в рамках моего пользовательского действия, чтобы попытаться установить мою службу 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-сервер)

Код был взят отсюда, поэтому полный кредит принадлежит тому, кто написал этот fragment кода.

После того, как вы добавите 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); } 

После создания экземпляра classа установщика для моей службы (очень простой) все, что мне нужно было сделать, это позвонить:

 ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location }); 

установить его и

 ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location }); 

для удаления службы. Вызывающий код здесь, в той же сборке, что и исполняемый файл службы.

чтобы получить сервис для установки через командную строку, все, что мне нужно было сделать, – это подключить это к исполняемым System.Environment.UserInteractive хотя аргументы командной строки, и проверить System.Environment.UserInteractive чтобы узнать, является ли это выполнением службы или кто-то пытается установить – удалите ее и вуаля … нет фанки-перехвата … нет указателей на утечку …

Всего около 20 строк кода, распространяемых по двум classам, сделали трюк.

для замены InstallUtil просто взгляните на ManagedInstallerClass.InstallHelper

Используя проект Topshelf, который вы можете установить, вызывая ваш исполняемый файл:

 MyService.exe install 

Topshelf также заботится о других сантехнических службах Windows.

С тех пор, как я столкнулся с проблемой установки программ, программно выполняемых под определенным пользователем. Я расширил метод 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); } } 

В этой статье я прочитал все сообщения и комментарии. Я все еще не знаю. Как установить тип учетной записи и метод StartType, когда я собираюсь добавить службу Windows. Этот пример кода отлично работает на моей стороне, он просто добавляет собственную локальную систему службы). Но я готовлю программу установки. Я должен думать о методе StartMode и типа учетной записи пользователя из-за системы клиентов.
есть все, что перечисление ServiceBootFlag предоставляет StartType, но Тип учетной записи все еще проблема.

  [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); 

Используйте нижеприведенный код для установки службы Windows с помощью C #:

 public void InstallWinService(string winServicePath) { try { ManagedInstallerClass.InstallHelper(new string[] { winServicePath}); } catch (Exception) { throw; } } 
  • Интерфейс GUI и Windows
  • Как запустить MongoDB в качестве службы Windows?
  • Автоматизация Office через службу Windows на сервере 2008
  • «Автоматический» и «Автоматический (Задержка запуска)»
  • Установите службу Windows .NET без InstallUtil.exe
  • Как я могу запланировать службу Windows C # для выполнения задачи ежедневно?
  • Глобальный обработчик исключений для служб Windows?
  • В чем причина внезапного прекращения моей службы приложений?
  • Как сделать вызов моей службы WCF асинхронным?
  • Как запустить процесс из службы Windows в текущий сеанс пользователя
  • Как создать службу Windows из приложения java
  • Давайте будем гением компьютера.