68

Tôi có 3 dự án trong giải pháp VS của mình. Một trong số đó là một ứng dụng web, ứng dụng thứ hai là một Dịch vụ Windows và dự án cuối cùng là một dự án Thiết lập cho ứng dụng Web của tôi.Làm thế nào để cài đặt một dịch vụ windows theo lập trình trong C#?

Điều tôi muốn là vào cuối quá trình cài đặt ứng dụng web trong dự án thiết lập của tôi, trong hành động tùy chỉnh của tôi để thử và cài đặt dịch vụ cửa sổ của tôi, sau đó tôi có vị trí lắp ráp.

Trả lời

67

Ok, đây là những gì thực sự làm việc đối với tôi, nó đã được thử nghiệm trên nhiều máy tính với hệ điều hành khác nhau (Vista, XP, Win2k, Win2003 server)

Mã đã được lấy từ here vì vậy tín dụng đầy đủ sẽ được chuyển đến bất kỳ ai đã viết đoạn mã này.

Khi bạn thêm dll hoặc tập tin nguồn vào dự án của bạn chắc chắn để thêm namespace ServiceTools và sau đó bạn có thể sử dụng một số chức năng rất tiện dụng như ...

//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"); 

Tôi hy vọng điều này sẽ giúp.

+3

Tôi đã đăng câu trả lời có chứa một số sửa lỗi cho mã bạn đã đăng. Hãy xem chuỗi thảo luận mà bạn đã tìm thấy mã và bạn sẽ thấy rằng tác giả của mã này nhận ra rằng có một số lỗi trong đó. –

+0

Bài đăng mà tôi đề cập đến là: http://www.tech-archive.net/Archive/VB/microsoft.public.vb.winapi/2006-08/msg00253.html Ngoài ra, tôi đã tìm thấy một hoặc hai lỗi khác nơi xử lý dịch vụ không được phát hành. –

+6

Giải pháp đó trông giống như chiến đấu với 25 đầu hydra khi tất cả những gì bạn muốn là một bước đi yên tĩnh trong công viên ... có một cách đơn giản hơn – Newtopian

28

Vui lòng xem this article.


Đôi khi bạn có thể muốn cài đặt Dịch vụ Windows theo lập trình, nhưng máy đích không có InstallUtil.exe.

Thêm tham chiếu đến System.Configuration.Install

Sử dụng mã bên dưới.

Lưu ý rằng exeFileName là InstallerClass .exe và không phải là 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); 

} 

Để gỡ bỏ cài đặt:

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

} 
+0

tôi đã cố gắng đó đã nhưng nó không hoạt động. Không có trường hợp ngoại lệ hoặc bất cứ điều gì, nó chỉ không cài đặt dịch vụ – Konstantinos

+0

Có thể là đường dẫn đầy đủ hoặc vấn đề thông tin đăng nhập> U có thể thử viết một dịch vụ đơn giản. Bạn cũng đã thử sử dụng url ở trên, nơi SCM gọi API thích hợp bằng cách sử dụng P/Gọi trong C# – lakshmanaraj

+0

tôi sẽ thử nó theo cách cứng và sẽ đi kèm với phản hồi, thx – Konstantinos

65

Tôi đã tìm thấy một số lỗi trong mã mà bạn đã sử dụng lại và đã sửa các lỗi này và cũng làm sạch nó một chút. Một lần nữa, mã ban đầu được lấy từ here.

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 
} 

Vui lòng cho tôi biết nếu có ai tìm thấy bất kỳ điều gì sai với mã này!

+0

nhờ lars tôi sẽ kiểm tra xem nó ra một khi tôi nhận được một số thời gian miễn phí :) – Konstantinos

+0

đã làm bất cứ ai kiểm tra mã này chưa? Tôi đang nghĩ đến việc sử dụng nó. – rev

+10

Sử dụng nó trong sản xuất –

4

Bằng việc sử dụng dự án Topshelf bạn có thể cài đặt bằng cách gọi thực thi của bạn:

MyService.exe install 

Topshelf cũng sẽ chăm sóc của hệ thống ống nước Windows Service khác.

11

Sau khi tạo một thể hiện của một lớp cài đặt cho dịch vụ của tôi (rất cơ bản) tất cả tôi phải làm là để gọi:

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

để cài đặt nó và

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

để gỡ bỏ cài đặt các dịch vụ . Mã gọi là, ở đây, trong cùng một assembly như dịch vụ thực thi.

để cài đặt dịch vụ thông qua dòng lệnh tất cả những gì tôi phải thực hiện là kết nối nó với các đối số dòng lệnh và kiểm tra System.Environment.UserInteractive để biết đó có phải là dịch vụ đang thực hiện hay không. voila ... không có nội dung tương tác sôi nổi ... không có con trỏ nào bị rò rỉ ...

Tổng số khoảng 20 dòng mã trải qua hai lớp đã thực hiện thủ thuật.

để thay thế InstallUtil chỉ có một cái nhìn tại ManagedInstallerClass.InstallHelper

+0

Đơn giản. Bạn có thể đã đi đến cùng một kết luận khi phản ánh vào InstallUtil.exe. Nó thực hiện chính xác điều tương tự. Plus nó có một số bảng điều khiển sửa lỗi thú vị. Cài đặt và gỡ cài đặt hoạt động tốt. (Hãy nhớ chạy nó với tư cách Quản trị viên ...) – ygoe

1

Trong bài viết này, tôi đọc tất cả bài viết và bình luận của Bu tôi vẫn không biết thế nào tôi có thể thiết lập Loại tài khoản và phương pháp StartType khi Tôi gonna thêm cửa sổ dịch vụ. Ví dụ mã này hoạt động tốt bên tôi của nó chỉ cần thêm một dịch vụ hệ thống địa phương riêng) Nhưng tôi chuẩn bị chương trình cài đặt tôi phải nghĩ rằng StartModeTài khoản người dùng loại phương pháp vì hệ thống khách hàng.
có mọi giao diện mà ServiceBootFlag enum cung cấp StartType nhưng Loại tài khoản vẫn là sự cố.

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

Vì tôi đã gặp phải thách thức khi cài đặt dịch vụ theo chương trình chạy dưới một người dùng nhất định. Tôi đã mở rộng phương thức InstallAndStart để sử dụng số lplpPassword ...

Không nhiều nhưng có thể hữu ích.

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); 
    } 
} 
0

Sử dụng mã dưới đây để cài đặt dịch vụ cửa sổ sử dụng C#:

public void InstallWinService(string winServicePath) 
{ 
     try 
     { 
      ManagedInstallerClass.InstallHelper(new string[] { winServicePath}); 
     } 
     catch (Exception) 
     { 

      throw; 
     } 
} 
Các vấn đề liên quan