Как установить службу windows программно в C#?
У меня есть 3 проекта в моем VS решении. Один из них-это веб-приложение, второй-служба Windows, а последний-проект установки для моего веб-приложения.
то, что я хочу, это к концу установки веб-приложения в моем проекте установки, в моем пользовательском действии, чтобы попытаться установить мою службу windows, учитывая, что у меня есть расположение сборки к тому времени.
8 ответов:
Я нашел несколько ошибок в коде, который вы повторно использовали и исправили их, а также немного очистили его. Опять же, исходный код берется из здесь.
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 server )
код был взят из здесь таким образом, полный кредит идет к тому, кто написал этот кусок кода.
после добавления 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.исполняемый.
добавить ссылку
System.Configuration.Installиспользуйте код ниже.
отметим, что
exeFileName- это InstallerClass .exe, а не ServiceClass .исполняемый.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 installTopshelf также заботится о других сантехнике службы 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; } }
Comments