C #에서 프로그래밍 방식으로 Windows 서비스를 설치하는 방법은 무엇입니까?
내 VS 솔루션에 3 개의 프로젝트가 있습니다. 그중 하나는 웹 앱이고, 두 번째는 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
}
누군가이 코드에서 잘못된 점을 발견하면 알려주세요!
좋아, 여기에 정말 나를 위해 일한 것이 있습니다. 다른 OS (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
중인 서비스인지 아니면 설치를 시도하는 사람인지 테스트 하는 것뿐입니다. 펑키 한 interop 물건 ... 포인터 누수 없음 ...
두 클래스에 걸쳐 총 약 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);
}
}
이 기사에서는 모든 게시물과 댓글을 읽었습니다. 여전히 Windows 서비스를 추가 할 때 계정 유형과 StartType 메서드를 어떻게 설정할 수 있는지 모르겠습니다. 이 코드 예제는 내 쪽에서 서비스 자체 로컬 시스템을 추가하는 것만으로도 잘 작동합니다.하지만 설치 프로그램을 준비 합니다. 고객 시스템 때문에 StartMode 및 User Account Type 방법을 생각해야합니다 . 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);
아래 코드를 사용하여 C #을 사용하여 Windows 서비스를 설치하십시오.
public void InstallWinService(string winServicePath)
{
try
{
ManagedInstallerClass.InstallHelper(new string[] { winServicePath});
}
catch (Exception)
{
throw;
}
}
참고URL : https://stackoverflow.com/questions/358700/how-to-install-a-windows-service-programmatically-in-c
'Development Tip' 카테고리의 다른 글
목록의 모든 값이 고유한지 테스트 (0) | 2020.10.15 |
---|---|
NavigationView 및 사용자 지정 레이아웃 (0) | 2020.10.15 |
Doctrine 2 엔터티에서 변경 / 업데이트 된 모든 필드를 가져 오는 기본 제공 방법이 있습니까? (0) | 2020.10.15 |
LAN을 통해 Visual Studio 디버깅 IIS Express 서버에 연결 (0) | 2020.10.15 |
멋진 글꼴이 아이콘을 표시하지 않습니다. (0) | 2020.10.15 |