using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp3
{
internal class Program
{
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleClosedDelegate handler, bool add);
private delegate bool ConsoleClosedDelegate(CtrlType ctrlType);
private enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool _done = false;
static void Main(string[] args)
{
SetConsoleCtrlHandler(OnConsoleClosed, true);
Task task = Task.Run(() =>
{
for (int i = 0; i < 100; ++i)
{
string t = $"Iteration {i + 1}";
Console.WriteLine(t);
System.Diagnostics.Debug.WriteLine(t);
Thread.Sleep(100);
}
_done = true;
});
task.Wait();
System.Diagnostics.Debug.WriteLine("Main() is done");
}
private static bool OnConsoleClosed(CtrlType ctrlType)
{
if (!_done)
{
Console.WriteLine("Terminating...");
System.Diagnostics.Debug.WriteLine("Terminating...");
Task task = Task.Run(() =>
{
while (!_done)
{
System.Diagnostics.Debug.WriteLine("Waiting 200ms...");
Thread.Sleep(200);
}
});
task.Wait();
}
System.Diagnostics.Debug.WriteLine("OnConsoleClosed is done");
return true;
}
}
}
В целом, всё работает. События приходят. Но, как всегда, есть проблема.
В новых версиях винды в качестве консоли используется обёрточное (как я понимаю) окно, гордо называемое Terminal
. Когда его закрываешь, вызывается обработчик OnConsoleClosed
. Но через 1-3 секунд эта обёртка решает, что программа зависла и рубит процесс, не давая потоку завершиться. Возможно, в старой консоли код работал бы. Но проверить эту теорию мне сейчас не на чем А в новой винде переключение на старую консоль тупо перестало работать (хотя в настройках такая опция осталась)
А как проверить, программа сейчас запущена в старой консоли или в новом терминале? И что в коде написать, чтобы терминал не рубил процесс по таймауту после своего закрытия?