mirror of https://github.com/winsw/winsw
Fix service crashes
parent
e97bc5bc72
commit
1f188cf20b
|
@ -193,20 +193,28 @@ namespace WinSW.Util
|
||||||
if (!AttachConsole(process.Id))
|
if (!AttachConsole(process.Id))
|
||||||
{
|
{
|
||||||
int error = Marshal.GetLastWin32Error();
|
int error = Marshal.GetLastWin32Error();
|
||||||
Log.Debug("Failed to attach to console. " + error switch
|
switch (error)
|
||||||
{
|
{
|
||||||
Errors.ERROR_ACCESS_DENIED => "WinSW is already attached to a console.", // TODO: test mode
|
// The process does not have a console.
|
||||||
Errors.ERROR_INVALID_HANDLE => "The process does not have a console.",
|
case Errors.ERROR_INVALID_HANDLE:
|
||||||
Errors.ERROR_INVALID_PARAMETER => "The process has exited.",
|
return false;
|
||||||
_ => new Win32Exception(error).Message // unreachable
|
|
||||||
});
|
|
||||||
|
|
||||||
return error == Errors.ERROR_INVALID_PARAMETER ? (bool?)null : false;
|
// The process has exited.
|
||||||
|
case Errors.ERROR_INVALID_PARAMETER:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// The calling process is already attached to a console.
|
||||||
|
case Errors.ERROR_ACCESS_DENIED:
|
||||||
|
default:
|
||||||
|
Log.Warn("Failed to attach to console. " + new Win32Exception(error).Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = SetConsoleCtrlHandler(null, true);
|
// Don't call GenerateConsoleCtrlEvent immediately after SetConsoleCtrlHandler.
|
||||||
|
// A delay was observed as of Windows 10, version 2004 and Windows Server 2019.
|
||||||
_ = GenerateConsoleCtrlEvent(CtrlEvents.CTRL_C_EVENT, 0);
|
_ = GenerateConsoleCtrlEvent(CtrlEvents.CTRL_C_EVENT, 0);
|
||||||
_ = SetConsoleCtrlHandler(null, false);
|
|
||||||
bool succeeded = FreeConsole();
|
bool succeeded = FreeConsole();
|
||||||
Debug.Assert(succeeded);
|
Debug.Assert(succeeded);
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,10 @@ namespace WinSW.Tests
|
||||||
Assert.Equal(ServiceControllerStatus.Running, controller.Status);
|
Assert.Equal(ServiceControllerStatus.Running, controller.Status);
|
||||||
Assert.True(controller.CanStop);
|
Assert.True(controller.CanStop);
|
||||||
|
|
||||||
|
Assert.EndsWith(
|
||||||
|
ServiceMessages.StartedSuccessfully + Environment.NewLine,
|
||||||
|
File.ReadAllText(Path.ChangeExtension(config.FullPath, ".wrapper.log")));
|
||||||
|
|
||||||
if (Environment.GetEnvironmentVariable("System.DefinitionId") != null)
|
if (Environment.GetEnvironmentVariable("System.DefinitionId") != null)
|
||||||
{
|
{
|
||||||
session = new InterProcessCodeCoverageSession(Helper.Name);
|
session = new InterProcessCodeCoverageSession(Helper.Name);
|
||||||
|
@ -48,6 +52,10 @@ namespace WinSW.Tests
|
||||||
_ = Helper.Test(new[] { "stop", config.FullPath }, config);
|
_ = Helper.Test(new[] { "stop", config.FullPath }, config);
|
||||||
controller.Refresh();
|
controller.Refresh();
|
||||||
Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
|
Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
|
||||||
|
|
||||||
|
Assert.EndsWith(
|
||||||
|
ServiceMessages.StoppedSuccessfully + Environment.NewLine,
|
||||||
|
File.ReadAllText(Path.ChangeExtension(config.FullPath, ".wrapper.log")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace WinSW
|
||||||
|
{
|
||||||
|
internal static class ServiceMessages
|
||||||
|
{
|
||||||
|
internal const string StartedSuccessfully = "Service started successfully.";
|
||||||
|
internal const string StoppedSuccessfully = "Service stopped successfully.";
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ using WinSW.Extensions;
|
||||||
using WinSW.Logging;
|
using WinSW.Logging;
|
||||||
using WinSW.Native;
|
using WinSW.Native;
|
||||||
using WinSW.Util;
|
using WinSW.Util;
|
||||||
|
using Messages = WinSW.ServiceMessages;
|
||||||
|
|
||||||
namespace WinSW
|
namespace WinSW
|
||||||
{
|
{
|
||||||
|
@ -206,7 +207,7 @@ namespace WinSW
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.DoStart();
|
this.DoStart();
|
||||||
this.LogMinimal("Service started successfully.");
|
this.LogMinimal(Messages.StartedSuccessfully);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +221,7 @@ namespace WinSW
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.DoStop();
|
this.DoStop();
|
||||||
this.LogMinimal("Service stopped successfully.");
|
this.LogMinimal(Messages.StoppedSuccessfully);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -257,6 +258,8 @@ namespace WinSW
|
||||||
{
|
{
|
||||||
bool succeeded = ConsoleApis.FreeConsole();
|
bool succeeded = ConsoleApis.FreeConsole();
|
||||||
Debug.Assert(succeeded);
|
Debug.Assert(succeeded);
|
||||||
|
succeeded = ConsoleApis.SetConsoleCtrlHandler(null, true);
|
||||||
|
Debug.Assert(succeeded);
|
||||||
|
|
||||||
this.HandleFileCopies();
|
this.HandleFileCopies();
|
||||||
|
|
||||||
|
@ -561,7 +564,9 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool succeeded = ConsoleApis.AllocConsole();
|
bool succeeded = ConsoleApis.AllocConsole(); // inherited
|
||||||
|
Debug.Assert(succeeded);
|
||||||
|
succeeded = ConsoleApis.SetConsoleCtrlHandler(null, false); // inherited
|
||||||
Debug.Assert(succeeded);
|
Debug.Assert(succeeded);
|
||||||
|
|
||||||
Process process;
|
Process process;
|
||||||
|
@ -573,6 +578,8 @@ namespace WinSW
|
||||||
{
|
{
|
||||||
succeeded = ConsoleApis.FreeConsole();
|
succeeded = ConsoleApis.FreeConsole();
|
||||||
Debug.Assert(succeeded);
|
Debug.Assert(succeeded);
|
||||||
|
succeeded = ConsoleApis.SetConsoleCtrlHandler(null, true);
|
||||||
|
Debug.Assert(succeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Info($"Started process {process.Format()}.");
|
Log.Info($"Started process {process.Format()}.");
|
||||||
|
|
Loading…
Reference in New Issue