Dot-Net

阻止 .net 控制台應用程序關閉

  • August 9, 2013

有什麼方法可以阻止 .NET 控制台應用程序關閉?我有一個遵循這種模式的應用程序:

while (true)
{
   string x = Console.ReadLine();
   StartLongRunningTaskOnSeparateThread(x);
}

問題是可以關閉控制台視窗(因此切斷長時間執行的任務)。控制台應用程序是否有等效的 Forms.OnClosing 事件?

編輯 - 我不是想創造一些不可能殺死的東西,只是可能會發出警告資訊,例如“嘿,我還沒完成。你確定要關閉我嗎?”

EDIT2 - 防止通過“x”按鈕過早退出比阻止 Ctrl-C(我使用過Console.TreatControlCAsInput = true;)更重要。為此目的,假設任何啟動任務管理器的人都想殺死程序,以至於他們應該能夠這樣做。並且最終使用者寧願看到警告也不願意外取消他們長時間執行的任務。

這是我解決這個問題的嘗試。任務管理器仍然可以關閉應用程序。但是,我的想法是嘗試檢測它何時關閉,然後重新啟動它。但是,我沒有實現那部分。

以下程序將檢測到 CTRL-C && CTRL-BREAK 並繼續執行。

**編輯:**刪除了“X”按鈕

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace DoNotCloseMe
{
   class Program
   {

       const string _title = "DO NOT CLOSE - Important Program";

       static void Main(string[] args)
       {

           Console.Title = _title;

           IntPtr hMenu = Process.GetCurrentProcess().MainWindowHandle;
           IntPtr hSystemMenu = GetSystemMenu(hMenu, false);

           EnableMenuItem(hSystemMenu, SC_CLOSE, MF_GRAYED);
           RemoveMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND);

           WriteConsoleHeader();

           //This function only seems to be called once.
           //After calling MainLoop() below, CTRL-C && CTRL-BREAK cause Console.ReadLine() to return NULL 
           Console.CancelKeyPress += (sender, e) =>
           {
               Console.WriteLine("Clean-up code invoked in CancelKeyPress handler.");
               Console.WriteLine("Key Pressed: {0}", e.SpecialKey.ToString());
               System.Threading.Thread.Sleep(1000);
               MainLoop();
               // The application terminates directly after executing this delegate.
           };

           MainLoop();

       }

       private static void MainLoop()
       {
           while (true)
           {
               WriteConsoleHeader();
               string x = Console.ReadLine();
               if (!String.IsNullOrEmpty(x))
               {
                   switch (x.ToUpperInvariant())
                   {
                       case "EXIT":
                       case "QUIT":
                           System.Environment.Exit(0);
                           break;
                       default:
                           StartLongRunningTaskOnSeparateThread(x);
                           break;
                   }

               }
           }
       }

       private static void StartLongRunningTaskOnSeparateThread(string command)
       {
           var bg = new System.ComponentModel.BackgroundWorker();
           bg.WorkerReportsProgress = false;
           bg.WorkerSupportsCancellation = false;

           bg.DoWork += (sender, args) =>
           {
               var sleepTime = (new Random()).Next(5000);
               System.Threading.Thread.Sleep(sleepTime);
           };


           bg.RunWorkerCompleted += (sender, args) =>
           {
               Console.WriteLine("Commmand Complete: {0}", command);
           };

           bg.RunWorkerAsync();

       }

       private static void WriteConsoleHeader()
       {
           Console.Clear();
           Console.WriteLine(new string('*', Console.WindowWidth - 1));
           Console.WriteLine(_title);
           Console.WriteLine(new string('*', Console.WindowWidth - 1));
           Console.WriteLine("Please do not close this program.");
           Console.WriteLine("It is maintaining the space/time continuum.");
           Console.WriteLine("If you close it, Q will not be happy and you will be assimilated.");
           Console.WriteLine(new string('*', Console.WindowWidth - 1));
           Console.WriteLine("Development Mode: Use \"EXIT\" or \"QUIT\" to exit application.");
           Console.WriteLine(new string('*', Console.WindowWidth - 1));
       }

       #region "Unmanaged"

       [DllImport("user32.dll")]
       static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);

       [DllImport("user32.dll")]
       static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

       [DllImport("user32.dll")]
       static extern IntPtr RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);

       internal const uint SC_CLOSE = 0xF060;
       internal const uint MF_GRAYED = 0x00000001;
       internal const uint MF_BYCOMMAND = 0x00000000;

       #endregion
   }
}

引用自:https://stackoverflow.com/questions/877839