Как установить службу 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 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;
}
}