/// <summary>开始执行服务</summary> /// <param name="service"></param> public override void Run(IHostedService service) { if (service == null) { throw new ArgumentNullException(nameof(service)); } _service = service; var num = Marshal.SizeOf(typeof(SERVICE_TABLE_ENTRY)); var intPtr = Marshal.AllocHGlobal(checked ((1 + 1) * num)); try { // Win32OwnProcess/StartPending _status.serviceType = 16; _status.currentState = ServiceControllerStatus.StartPending; _status.controlsAccepted = 0; _status.win32ExitCode = 0; _status.serviceSpecificExitCode = 0; _status.checkPoint = 0; _status.waitHint = 0; // CanStop | CanShutdown | CanPauseAndContinue | CanHandlePowerEvent | CanHandleSessionChangeEvent //_acceptedCommands = 1 | 4 | 2 | 64 | 128; // CanStop | CanShutdown _acceptedCommands = 1 | 4; SERVICE_TABLE_ENTRY result = default; result.callback = ServiceMainCallback; result.name = Marshal.StringToHGlobalUni(service.ServiceName); Marshal.StructureToPtr(result, intPtr, false); SERVICE_TABLE_ENTRY result2 = default; result2.callback = null; result2.name = (IntPtr)0; Marshal.StructureToPtr(result2, intPtr + num, false); /* * 如果StartServiceCtrlDispatcher函数执行成功,调用线程(也就是服务进程的主线程)不会返回,直到所有的服务进入到SERVICE_STOPPED状态。 * 调用线程扮演着控制分发的角色,干这样的事情: * 1、在新的服务启动时启动新线程去调用服务主函数(主意:服务的任务是在新线程中做的); * 2、当服务有请求时(注意:请求是由SCM发给它的),调用它对应的处理函数(主意:这相当于主线程“陷入”了,它在等待控制消息并对消息做处理)。 */ XTrace.WriteLine("启动服务 {0}", service.ServiceName); var flag = StartServiceCtrlDispatcher(intPtr); if (!flag) { XTrace.WriteLine("服务启动失败!"); } } finally { Marshal.FreeHGlobal(intPtr); } }
private SERVICE_TABLE_ENTRY GetEntry() { SERVICE_TABLE_ENTRY entry = new SERVICE_TABLE_ENTRY(); _nameFrozen = true; entry.callback = (Delegate)_mainCallback; entry.name = _handleName; return(entry); }
/// <devdoc> /// <para>Provides the main entry point for an executable that /// contains multiple associated services. Loads the specified services into memory so they can be /// started.</para> /// </devdoc> public static void Run(ServiceBase[] services) { if (services == null || services.Length == 0) { throw new ArgumentException(SR.NoServices); } IntPtr entriesPointer = Marshal.AllocHGlobal((IntPtr)((services.Length + 1) * Marshal.SizeOf(typeof(SERVICE_TABLE_ENTRY)))); SERVICE_TABLE_ENTRY[] entries = new SERVICE_TABLE_ENTRY[services.Length]; bool multipleServices = services.Length > 1; IntPtr structPtr = (IntPtr)0; for (int index = 0; index < services.Length; ++index) { services[index].Initialize(multipleServices); entries[index] = services[index].GetEntry(); structPtr = (IntPtr)((long)entriesPointer + Marshal.SizeOf(typeof(SERVICE_TABLE_ENTRY)) * index); Marshal.StructureToPtr(entries[index], structPtr, true); } SERVICE_TABLE_ENTRY lastEntry = new SERVICE_TABLE_ENTRY(); lastEntry.callback = null; lastEntry.name = (IntPtr)0; structPtr = (IntPtr)((long)entriesPointer + Marshal.SizeOf(typeof(SERVICE_TABLE_ENTRY)) * services.Length); Marshal.StructureToPtr(lastEntry, structPtr, true); // While the service is running, this function will never return. It will return when the service // is stopped. bool res = StartServiceCtrlDispatcher(entriesPointer); string errorMessage = ""; if (!res) { errorMessage = new Win32Exception().Message; Console.WriteLine(SR.CantStartFromCommandLine); } foreach (ServiceBase service in services) { service.Dispose(); if (!res) { service.WriteLogEntry(SR.Format(SR.StartFailed, errorMessage), true); } } }
private static void Win32RunService(ServiceBase [] services) { SERVICE_TABLE_ENTRY[] table = new SERVICE_TABLE_ENTRY[services.Length + 1]; NotifyStatus = new NotifyStatusCallback(Win32NotifyStatus); for (int i = 0; i < services.Length; i++) { table[i].lpServiceName = services[i].ServiceName ?? ""; table[i].lpServiceProc = new LPSERVICE_MAIN_FUNCTION(services[i].ServiceMainCallback); } // table[services.Length] is a NULL terminator share_process = (services.Length > 1); if (!StartServiceCtrlDispatcher(table)) { throw new Win32Exception(); } }
/// <summary>开始执行服务</summary> /// <param name="service"></param> public override void Run(ServiceBase service) { _service = service ?? throw new ArgumentNullException(nameof(service)); var num = Marshal.SizeOf(typeof(SERVICE_TABLE_ENTRY)); var table = Marshal.AllocHGlobal((IntPtr)((1 + 1) * num)); var handleName = Marshal.StringToHGlobalUni(service.ServiceName); try { // Win32OwnProcess/StartPending _status.serviceType = ServiceType.Win32OwnProcess; _status.currentState = ServiceControllerStatus.StartPending; _status.controlsAccepted = 0; _status.win32ExitCode = 0; _status.serviceSpecificExitCode = 0; _status.checkPoint = 0; _status.waitHint = 0; // 正常运行后可接受的命令 #if NETSTANDARD2_0 _acceptedCommands = ControlsAccepted.CanStop | ControlsAccepted.CanShutdown //| ControlsAccepted.CanPauseAndContinue | ControlsAccepted.ParamChange | ControlsAccepted.NetBindChange | ControlsAccepted.HardwareProfileChange | ControlsAccepted.CanHandlePowerEvent | ControlsAccepted.CanHandleSessionChangeEvent | ControlsAccepted.PreShutdown | ControlsAccepted.TimeChange | ControlsAccepted.TriggerEvent //| ControlsAccepted.UserModeReboot ; #else _acceptedCommands = ControlsAccepted.CanStop | ControlsAccepted.CanShutdown ; #endif //!!! 函数委托必须引着,避免GC回收导致PInvoke内部报错 _table = new SERVICE_TABLE_ENTRY { callback = ServiceMainCallback, name = handleName }; Marshal.StructureToPtr(_table, table, true); var result2 = new SERVICE_TABLE_ENTRY { callback = null, name = IntPtr.Zero }; Marshal.StructureToPtr(result2, table + num, true); /* * 如果StartServiceCtrlDispatcher函数执行成功,调用线程(也就是服务进程的主线程)不会返回,直到所有的服务进入到SERVICE_STOPPED状态。 * 调用线程扮演着控制分发的角色,干这样的事情: * 1、在新的服务启动时启动新线程去调用服务主函数(主意:服务的任务是在新线程中做的); * 2、当服务有请求时(注意:请求是由SCM发给它的),调用它对应的处理函数(主意:这相当于主线程“陷入”了,它在等待控制消息并对消息做处理)。 */ //XTrace.WriteLine("运行服务 {0}", service.ServiceName); var flag = StartServiceCtrlDispatcher(table); if (!flag) { XTrace.WriteLine(new Win32Exception().Message); } XTrace.WriteLine("退出服务 {0} CtrlDispatcher={1}", service.ServiceName, flag); } catch (Exception ex) { XTrace.WriteException(ex); XTrace.WriteLine("运行服务 {0} 出错,{1}", _service.ServiceName, new Win32Exception(Marshal.GetLastWin32Error()).Message); } finally { if (table != IntPtr.Zero) { Marshal.FreeHGlobal(table); } if (handleName != IntPtr.Zero) { Marshal.FreeHGlobal(handleName); } //_service.TryDispose(); } }
/// <devdoc> /// <para>Provides the main entry point for an executable that /// contains multiple associated services. Loads the specified services into memory so they can be /// started.</para> /// </devdoc> public static void Run(ServiceBase[] services) { if (services == null || services.Length == 0) { throw new ArgumentException(SR.NoServices); } int sizeOfSERVICE_TABLE_ENTRY = Marshal.SizeOf <SERVICE_TABLE_ENTRY>(); IntPtr entriesPointer = Marshal.AllocHGlobal(checked ((services.Length + 1) * sizeOfSERVICE_TABLE_ENTRY)); SERVICE_TABLE_ENTRY[] entries = new SERVICE_TABLE_ENTRY[services.Length]; bool multipleServices = services.Length > 1; IntPtr structPtr; for (int index = 0; index < services.Length; ++index) { services[index].Initialize(multipleServices); entries[index] = services[index].GetEntry(); structPtr = entriesPointer + sizeOfSERVICE_TABLE_ENTRY * index; Marshal.StructureToPtr(entries[index], structPtr, fDeleteOld: false); } SERVICE_TABLE_ENTRY lastEntry = new SERVICE_TABLE_ENTRY(); lastEntry.callback = null; lastEntry.name = (IntPtr)0; structPtr = entriesPointer + sizeOfSERVICE_TABLE_ENTRY * services.Length; Marshal.StructureToPtr(lastEntry, structPtr, fDeleteOld: false); // While the service is running, this function will never return. It will return when the service // is stopped. // After it returns, SCM might terminate the process at any time // (so subsequent code is not guaranteed to run). bool res = StartServiceCtrlDispatcher(entriesPointer); foreach (ServiceBase service in services) { if (service._startFailedException != null) { // Propagate exceptions throw during OnStart. // Note that this same exception is also thrown from ServiceMainCallback // (so SCM can see it as well). service._startFailedException.Throw(); } } string errorMessage = ""; if (!res) { errorMessage = new Win32Exception().Message; Console.WriteLine(SR.CantStartFromCommandLine); } foreach (ServiceBase service in services) { service.Dispose(); if (!res) { service.WriteLogEntry(SR.Format(SR.StartFailed, errorMessage), true); } } }
internal static extern int StartServiceCtrlDispatcher(SERVICE_TABLE_ENTRY[] lpServiceStartTable);
private static void Win32RunService (ServiceBase [] services) { SERVICE_TABLE_ENTRY[] table = new SERVICE_TABLE_ENTRY[services.Length + 1]; NotifyStatus = new NotifyStatusCallback (Win32NotifyStatus); for (int i = 0; i<services.Length; i++) { table[i].lpServiceName = services[i].ServiceName ?? ""; table[i].lpServiceProc = new LPSERVICE_MAIN_FUNCTION (services[i].ServiceMainCallback); } // table[services.Length] is a NULL terminator share_process = (services.Length > 1); if (!StartServiceCtrlDispatcher (table)) throw new Win32Exception (); }