Click here to Skip to main content
15,880,608 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I'm writing a console application using Net6. It runs on Raspberry, Ubuntu and Windows.

The user can quit the application by pressing Q, Ctrl-C or close the window.

I'm detecting the Q press in my static void Main method
C#
bool requestShutdown = false;
bool close = false;
while (!close && !requestShutdown)
{
  if (Console.KeyAvailable)
  {
    var keyPressed = Console.ReadKey(true);
    close = (keyPressed.Key == ConsoleKey.Q);
    if (close) DoLogging("Requesting shutdown (Q)");
  }
  Thread.Sleep(0);
  Thread.Sleep(250);
}
ShutDown();


where I'm also detecting the Ctrl-C using
C#
Console.CancelKeyPress += Console_CancelKeyPress;

...

private static void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e)
{
  DoLogging("Requesting shutdown (Ctrl-C)");
  requestShutdown = true;
}


This all works nice in Windows and Raspberry (running through Putty). The
C#
ShutDown();
block is called when either Q or Ctrl-C is pressed. So far so good !


However in Windows, it is possible for the user to just close the window by pressing the close button or use Alt-F4.
I know that I can capture this using the code
C#
    [DllImport("Kernel32")]
    private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
    private delegate bool EventHandler(ConsoleCloseCtrlType signal);
    private static EventHandler handler;

...

    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
      handler += new EventHandler(Handler);
      SetConsoleCtrlHandler(handler, true);
    }

...
    private static bool Handler(ConsoleCloseCtrlType signal)
    {
        DoLogging($"Requesting shutdown ({signal})");
        ShutDown();
        return true;
    }


but, this obviously will not work in Linux OS:es, since the Kernel32 import throws an exception on a Raspberry.

What I have tried:

I thought that it would be easy to use some kind of compiler directive to prevent the Kernel32 code to be included, but my Google Fu skills does not seem to be good enough to find a solution and trust me, I spent a number of hours trying to find it.

I use
Terminal
dotnet publish
to build the code for the three targets (Windows, Linux-x64 and Linux-arm) but I can't seem to find any way to just include the Kernel32 for the Windows build.
I've looked at ideas such as this but since I build for all three platforms on my Windows machine that suggestion does not work.
Also, since it is the Kernel32 dll I can't really see how I can load it dynamically at runtime.

I'm most likely missing something very obvious so if someone could enlighten me or give me a push in the right direction it would be most appreciated.

Thanks in advance,
King regards
Magnus
Posted
Updated 30-Dec-21 0:13am

Thanks to Luc who helped me in looking into this problem more thoroughly.

Before Lucs comment on using AppDomain.ProcessExit I actually tried this previously. My mistake was to just put a log4net debug statement in the event handler. Since the log4net debug output never showed up in the log file I assumed (which turned out to be incorrect) that it did not work and tried to pursue other ways of doing catching the Alt-F4 shutdown.

After Lucs comment I took a better look into

C#
AppDomain.CurrentDomain.ProcessExit += AppDomain_ProcessExit;


and realized that I needed to add this handler earlier than my log4net setup as described in this post.

Now everything seems to work just fine!
 
Share this answer
 
One event[^] should cover all of it...

:)
 
Share this answer
 
Comments
Magnus Sydoff 29-Dec-21 15:26pm    
Thanks for the answer Luc, but does the concept of Application exist in Net6?
From what I remember it is lives in the Windows Forms assembly, and that will not play nicely with Linux, or am I mistaken?

King regards
Magnus
Luc Pattyn 29-Dec-21 15:38pm    
You're right Magnus, Application class is a Windows thingy. My mistake.
Fortunately there also is AppDomain.ProcessExit.

:)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900