Dot-Net
使用 .Net ServiceInstaller 在服務安裝中設置“啟動參數”?
我目前正在編寫一個小的 Windows 服務應用程序,我可以通過以下方式成功地安裝/解除安裝它等:
serviceProcessInstaller = new ServiceProcessInstaller(); serviceInstaller = new System.ServiceProcess.ServiceInstaller(); serviceProcessInstaller.Account = ServiceAccount.LocalSystem; serviceInstaller.ServiceName = "ABC"; serviceInstaller.StartType = ServiceStartMode.Automatic; serviceInstaller.Description = "DEF"; Installers.AddRange(new Installer[] { serviceProcessInstaller, serviceInstaller });…但我顯然無法在那裡設置啟動參數…或者我可以嗎?我寧願以後不要繼續修改系統資料庫..因此問題…有什麼辦法可以以程式方式設置這些參數嗎?
這是一個更簡潔的答案:
在您的 ServiceInstaller 類(使用 Installer 作為基類的類)中,添加以下兩個覆蓋:
public partial class ServiceInstaller : System.Configuration.Install.Installer { public ServiceInstaller () { ... } protected override void OnBeforeInstall(System.Collections.IDictionary savedState) { Context.Parameters["assemblypath"] += "\" /service"; base.OnBeforeInstall(savedState); } protected override void OnBeforeUninstall(System.Collections.IDictionary savedState) { Context.Parameters["assemblypath"] += "\" /service"; base.OnBeforeUninstall(savedState); } }
參數可以通過 P/Invoking ChangeServiceConfig API 來設置。它們出現在 lpBinaryPathName 參數中您的執行檔的引用路徑和文件名之後。
當服務通過 Main 方法啟動時,這些參數將可供您的服務使用:
static void Main(string[] args)(Main 傳統上位於名為 Program.cs 的文件中)。
下面顯示瞭如何修改安裝程序以在正常服務安裝邏輯執行後呼叫此 API。您最有可能需要修改的部分在建構子中。
using System; using System.Collections; using System.Collections.Generic; using System.Configuration.Install; using System.ComponentModel; using System.Configuration.Install; using System.Diagnostics; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Text; namespace ServiceTest { [RunInstaller(true)] public class ProjectInstaller : Installer { private string _Parameters; private ServiceProcessInstaller _ServiceProcessInstaller; private ServiceInstaller _ServiceInstaller; public ProjectInstaller() { _ServiceProcessInstaller = new ServiceProcessInstaller(); _ServiceInstaller = new ServiceInstaller(); _ServiceProcessInstaller.Account = ServiceAccount.LocalService; _ServiceProcessInstaller.Password = null; _ServiceProcessInstaller.Username = null; _ServiceInstaller.ServiceName = "Service1"; this.Installers.AddRange(new System.Configuration.Install.Installer[] { _ServiceProcessInstaller, _ServiceInstaller}); _Parameters = "/ThisIsATest"; } public override void Install(IDictionary stateSaver) { base.Install(stateSaver); IntPtr hScm = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); if (hScm == IntPtr.Zero) throw new Win32Exception(); try { IntPtr hSvc = OpenService(hScm, this._ServiceInstaller.ServiceName, SERVICE_ALL_ACCESS); if (hSvc == IntPtr.Zero) throw new Win32Exception(); try { QUERY_SERVICE_CONFIG oldConfig; uint bytesAllocated = 8192; // Per documentation, 8K is max size. IntPtr ptr = Marshal.AllocHGlobal((int)bytesAllocated); try { uint bytesNeeded; if (!QueryServiceConfig(hSvc, ptr, bytesAllocated, out bytesNeeded)) { throw new Win32Exception(); } oldConfig = (QUERY_SERVICE_CONFIG) Marshal.PtrToStructure(ptr, typeof(QUERY_SERVICE_CONFIG)); } finally { Marshal.FreeHGlobal(ptr); } string newBinaryPathAndParameters = oldConfig.lpBinaryPathName + " " + _Parameters; if (!ChangeServiceConfig(hSvc, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, newBinaryPathAndParameters, null, IntPtr.Zero, null, null, null, null)) throw new Win32Exception(); } finally { if (!CloseServiceHandle(hSvc)) throw new Win32Exception(); } } finally { if (!CloseServiceHandle(hScm)) throw new Win32Exception(); } } [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern IntPtr OpenSCManager( string lpMachineName, string lpDatabaseName, uint dwDesiredAccess); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern IntPtr OpenService( IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] private struct QUERY_SERVICE_CONFIG { public uint dwServiceType; public uint dwStartType; public uint dwErrorControl; public string lpBinaryPathName; public string lpLoadOrderGroup; public uint dwTagId; public string lpDependencies; public string lpServiceStartName; public string lpDisplayName; } [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool QueryServiceConfig( IntPtr hService, IntPtr lpServiceConfig, uint cbBufSize, out uint pcbBytesNeeded); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ChangeServiceConfig( IntPtr hService, uint dwServiceType, uint dwStartType, uint dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword, string lpDisplayName); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseServiceHandle( IntPtr hSCObject); private const uint SERVICE_NO_CHANGE = 0xffffffffu; private const uint SC_MANAGER_ALL_ACCESS = 0xf003fu; private const uint SERVICE_ALL_ACCESS = 0xf01ffu; } }