我目前正在编写一个小的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 });
...但我显然无法在那里设置启动参数......或者我可以吗?我宁愿不继续以后修改注册表..因此问题...有什么办法我可以用编程方式设置这些参数吗?
可以通过P /调用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; } }
这是一个更简洁的答案:
在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); } }