注意:我不得不从GITHub链接中反编译您的exe,因为您没有包含cs文件。
这是您的代码...
private void RegisterPreShutdownEvent()
{
FieldInfo field = typeof(ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
{
throw new Exception("acceptedCommands field not found");
}
int value = (int)field.GetValue(this);
field.SetValue(this, value | 256);
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 15)
{
this.OnPreShutdown();
}
}
我认为你的PRESHUTDOWN实现方案不够充分。虽然你已经绑定了事件并在PreShutdown时得到了通知,但是当完成后你没有采取任何措施来改变服务的状态。我仔细研究了你使用ServiceBase的反编译副本触发关闭的OnCustomCommand实现。
private void DeferredCustomCommand(int command)
{
try
{
this.OnCustomCommand(command);
this.WriteEventLogEntry("Service command was processed successfully.");
}
catch (Exception exception)
{
this.WriteEventLogEntry(string.Format("Failed to process service command. {0}", exception), EventLogEntryType.Error);
throw;
}
}
当使用DeferredShutdown()处理正常关闭时,它的流程如下。请注意,它会触发OnShutdown事件,然后检查并设置服务状态。
private unsafe void DeferredShutdown()
{
try
{
this.OnShutdown();
this.WriteEventLogEntry("Service has been successfully shut down.");
if ((this.status.currentState == SERVICE_PAUSED) || (this.status.currentState == SERVICE_RUNNING))
{
fixed (NativeMethods.SERVICE_STATUS* service_statusRef = &this.status)
{
this.status.checkPoint = 0;
this.status.waitHint = 0;
this.status.currentState = SERVICE_STOPPED;
NativeMethods.SetServiceStatus(this.statusHandle, service_statusRef);
if (this.isServiceHosted)
{
try
{
AppDomain.Unload(AppDomain.CurrentDomain);
}
catch (CannotUnloadAppDomainException exception)
{
this.WriteEventLogEntry(string.Format("Failed to unload app domain {0}. The following exception occurred: {1}.", AppDomain.CurrentDomain.FriendlyName, exception.Message), EventLogEntryType.Error);
}
}
}
}
}
catch (Exception exception2)
{
this.WriteEventLogEntry(string.Format("Failed to shut down service. The error that occurred was: {0}.", exception2), EventLogEntryType.Error);
throw;
}
}
我没有确切的答案来解决这个问题。但我找到了这个链接:https://www.atomia.com/2011/11/16/how-to-process-the-preshutdown-event-in-a-managed-windows-service/,看起来可能会有用。不同之处在于他们强制调用DeferredShutdown(),这将触发您的服务类的OnShutdown()事件,并在完成时正确更新服务状态。以下是他们解决方案的代码:
internal virtual int MyServiceControlCallbackEx(int control, int eventType, IntPtr eventData, IntPtr eventContext)
{
var baseCallback = typeof(ServiceBase).GetMethod("ServiceCommandCallbackEx", BindingFlags.Instance | BindingFlags.NonPublic);
switch (control)
{
case 0x0000000F:
return (int)baseCallback.Invoke(this, new object[] { 0x00000005, eventType, eventData, eventContext });
default:
return (int)baseCallback.Invoke(this, new object[] { control, eventType, eventData, eventContext });
}
}
internal virtual void MyInitialize(bool multipleServices)
{
var init = typeof(ServiceBase).GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic);
init.Invoke(this, new object[] { multipleServices });
var targetDelegate =
typeof(ServiceBase).Assembly.GetType("System.ServiceProcess.NativeMethods+ServiceControlCallbackEx");
var commandCallbackEx = typeof(ServiceBase).GetField("commandCallbackEx", BindingFlags.Instance | BindingFlags.NonPublic);
commandCallbackEx.SetValue(this, Delegate.CreateDelegate(targetDelegate, this, "MyServiceControlCallbackEx"));
var acceptedCommands = typeof(ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
int accCom = (int)acceptedCommands.GetValue(this);
acceptedCommands.SetValue(this, accCom | 0x00000100);
}
要使用它,您需要将这些方法添加到您的服务类中,并从构造函数中调用MyInitialize,然后覆盖OnShutdown()并编写您想要执行的代码。我认为他们还建议您在服务类中将CanShutdown属性设置为false。
myThread.IsBackground = true
进行标记可能会有所帮助。如果这不能解决你的问题,你需要进行转储。 - Oguz Ozgul