2009-01-23 18 views
78

मेरे पास एक कंसोल एप्लिकेशन है जिसमें बहुत सारे थ्रेड हैं। ऐसे थ्रेड हैं जो कुछ शर्तों की निगरानी करते हैं और यदि वे सत्य हैं तो प्रोग्राम को समाप्त कर देते हैं। यह समाप्ति किसी भी समय हो सकती है।कंसोल कंसोल कैप्चर करें C#

मुझे एक ऐसी घटना की आवश्यकता है जिसे प्रोग्राम बंद होने पर ट्रिगर किया जा सके ताकि मैं अन्य सभी धागे को साफ़ कर सकूं और सभी फाइल हैंडल और कनेक्शन को ठीक से बंद कर सकूं। मुझे यकीन नहीं है कि पहले से ही .NET ढांचे में बनाया गया है, इसलिए मैं अपना खुद लिखने से पहले पूछ रहा हूं।

अगर वहाँ की तर्ज पर एक घटना थी मैं सोच रहा था:

MyConsoleProgram.OnExit += CleanupBeforeExit; 
+2

मुझे पता है कि यह बहुत देर हो चुकी टिप्पणी है, लेकिन अगर आपको "फाइलें और कनेक्शन बंद करना" एकमात्र चीज है जिसे आप क्लीनअप के रूप में करना चाहते हैं तो आपको वास्तव में ऐसा करने की ज़रूरत नहीं है। क्योंकि विंडोज टर्मिनेशन के दौरान प्रक्रिया से जुड़े सभी हैंडल बंद कर देता है। –

+3

^केवल तभी जब उन संसाधनों का स्वामित्व प्रक्रिया समाप्त हो। यह बिल्कुल जरूरी है, उदाहरण के लिए, आप पृष्ठभूमि में एक छिपा COM अनुप्रयोग (कहें, शब्द, या एक्सेल) स्वचालित कर रहे हैं, और आपको अपने ऐप से बाहर निकलने से पहले इसे मारना सुनिश्चित करना होगा, आदि – BrainSlugs83

+1

इसमें एक छोटा सा है उत्तर देख रहे हैं http://stackoverflow.com/questions/2555292/how-to-run-code-before-program-exit – barlop

उत्तर

83

मुझे यकीन नहीं है कि मुझे वेब पर कोड कहां मिला, लेकिन मुझे अब यह मेरी पुरानी परियोजनाओं में से एक में मिला। यह आपको अपने कंसोल में क्लीनअप कोड करने की अनुमति देगा, उदा। जब यह अचानक बंद कर दिया है या एक बंद होने के कारण ...

[DllImport("Kernel32")] 
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add); 

private delegate bool EventHandler(CtrlType sig); 
static EventHandler _handler; 

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 Handler(CtrlType sig) 
{ 
    switch (sig) 
    { 
     case CtrlType.CTRL_C_EVENT: 
     case CtrlType.CTRL_LOGOFF_EVENT: 
     case CtrlType.CTRL_SHUTDOWN_EVENT: 
     case CtrlType.CTRL_CLOSE_EVENT: 
     default: 
      return false; 
    } 
} 


static void Main(string[] args) 
{ 
    // Some biolerplate to react to close window event 
    _handler += new EventHandler(Handler); 
    SetConsoleCtrlHandler(_handler, true); 
    ... 
} 

अद्यतन

टिप्पणियां ऐसा लगता है कि इस विशेष समाधान अच्छी तरह से नहीं काम करता है की जाँच नहीं उन लोगों के लिए (या बिल्कुल) पर विंडोज 7। निम्नलिखित thread इस

+3

क्या आप इसे बाहर निकलने के लिए उपयोग कर सकते हैं? जब यह बंद हो रहा है के अलावा! –

+0

जेम्स, मुझे कोई जानकारी नहीं है लेकिन हैंडलर हस्ताक्षर एक बूल देता है, इसलिए मैं कोशिश करता हूं कि जब आप सच/झूठी वापसी करते हैं तो क्या होता है – flq

+6

यह बहुत अच्छा काम करता है, केवल 'बूल हैंडलर()' को झूठी वापसी करनी चाहिए; '(यह रिटर्न कोड में कुछ भी नहीं) तो यह काम करेगा। यदि यह सत्य लौटाता है, तो विंडोज "प्रक्रिया समाप्त करें" संवाद को संकेत देता है। = डी – Cipi

3

WinForms क्षुधा के लिए नहीं है;

Application.ApplicationExit += CleanupBeforeExit; 

कंसोल ऐप के लिए,

AppDomain.CurrentDomain.DomainUnload += CleanupBeforeExit; 

कोशिश लेकिन मैं बुलाया जाता है कि या अगर यह मौजूदा डोमेन के भीतर से काम करेंगे क्या बिंदु पर यकीन नहीं है। मुझे संदेह नहीं है।

+0

डोमेनउनलोड के लिए सहायता दस्तावेज़ कहते हैं, "इस ईवेंट के लिए इवेंट हैंडलर प्रतिनिधि आवेदन डोमेन से पहले कोई समाप्ति गतिविधियां कर सकता है अनलोड किया गया है। " तो ऐसा लगता है जैसे यह वर्तमान डोमेन के भीतर काम करता है। हालांकि, यह उसकी ज़रूरत के लिए काम नहीं कर सकता है क्योंकि उसके धागे डोमेन को रख सकते हैं। –

+1

यह केवल CTRL + C और CTRL + को संभालता है, यह लौटने, पर्यावरण के माध्यम से मौजूद नहीं है। न तो बंद करें बटन पर क्लिक करें। – Kit10

3

के बारे में वार्तालाप ऐसा लगता है कि आपके पास सीधे आवेदन को समाप्त करने वाले धागे हैं? शायद यह बेहतर होगा कि थ्रेड सिग्नल मुख्य थ्रेड कहें कि एप्लिकेशन को समाप्त किया जाना चाहिए।

इस सिग्नल को प्राप्त करने पर, मुख्य धागा साफ-सुथरा अन्य धागे को बंद कर सकता है और आखिरकार खुद को बंद कर देता है।

+2

मुझे इस उत्तर से सहमत होना है। आवेदन निकास को मजबूर करना और फिर बाद में साफ करने की कोशिश करना वह रास्ता नहीं है। अपने आवेदन को नियंत्रित करें, नोट। इसे नियंत्रित करने मत दो। – Randolpho

+1

मेरे द्वारा उत्पन्न एक धागा सीधे एकमात्र चीज नहीं है जो मेरा आवेदन बंद कर सकता है। Ctrl-C और "बंद बटन" अन्य तरीके हैं जो इसे समाप्त कर सकते हैं। फ्रैंक द्वारा पोस्ट किया गया कोड, मामूली संशोधन के बाद, पूरी तरह से फिट बैठता है। – ZeroKelvin

7

भी जांच:

AppDomain.CurrentDomain.ProcessExit 
+5

विंडोज 7 पर भी काम नहीं करता है। – SpeziFish

+6

यह केवल वापसी या पर्यावरण से बाहर निकलने के लिए प्रतीत होता है। इसके अलावा, यह CTRL + C, CTRL + Break, और कंसोल पर वास्तविक बंद बटन नहीं पकड़ता है। – Kit10

0

VB.net में रुचि रखने वालों के लिए। (मैंने इंटरनेट की खोज की और इसके लिए समकक्ष नहीं मिला) यहां इसका अनुवाद vb.net में किया गया है।

<DllImport("kernel32")> _ 
    Private Function SetConsoleCtrlHandler(ByVal HandlerRoutine As HandlerDelegate, ByVal Add As Boolean) As Boolean 
    End Function 
    Private _handler As HandlerDelegate 
    Private Delegate Function HandlerDelegate(ByVal dwControlType As ControlEventType) As Boolean 
    Private Function ControlHandler(ByVal controlEvent As ControlEventType) As Boolean 
     Select Case controlEvent 
      Case ControlEventType.CtrlCEvent, ControlEventType.CtrlCloseEvent 
       Console.WriteLine("Closing...") 
       Return True 
      Case ControlEventType.CtrlLogoffEvent, ControlEventType.CtrlBreakEvent, ControlEventType.CtrlShutdownEvent 
       Console.WriteLine("Shutdown Detected") 
       Return False 
     End Select 
    End Function 
    Sub Main() 
     Try 
      _handler = New HandlerDelegate(AddressOf ControlHandler) 
      SetConsoleCtrlHandler(_handler, True) 
    ..... 
End Sub 
+0

ऊपर समाधान मेरे लिए काम नहीं करता है vb.net 4.5 ढांचे ControlEventType हल नहीं हो रहा है। मैं इस विचार को समाधान के रूप में उपयोग करने में सक्षम था https://stackoverflow.com/questions/15317082/how-to-close-console-application-gracefully-on-windows-shutdown – glant

19

पूर्ण काम कर उदाहरण के लिए,, Ctrl-C के साथ काम करता एक्स के साथ विंडो बंद करने और मारने:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading; 

namespace TestTrapCtrlC { 
    public class Program { 
     static bool exitSystem = false; 

     #region Trap application termination 
     [DllImport("Kernel32")] 
     private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add); 

     private delegate bool EventHandler(CtrlType sig); 
     static EventHandler _handler; 

     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 Handler(CtrlType sig) { 
      Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown"); 

      //do your cleanup here 
      Thread.Sleep(5000); //simulate some cleanup delay 

      Console.WriteLine("Cleanup complete"); 

      //allow main to run off 
      exitSystem = true; 

      //shutdown right away so there are no lingering threads 
      Environment.Exit(-1); 

      return true; 
     } 
     #endregion 

     static void Main(string[] args) { 
      // Some biolerplate to react to close window event, CTRL-C, kill, etc 
      _handler += new EventHandler(Handler); 
      SetConsoleCtrlHandler(_handler, true); 

      //start your multi threaded program here 
      Program p = new Program(); 
      p.Start(); 

      //hold the console so it doesn’t run off the end 
      while (!exitSystem) { 
       Thread.Sleep(500); 
      } 
     } 

     public void Start() { 
      // start a thread and start doing some processing 
      Console.WriteLine("Thread started, processing.."); 
     } 
    } 
} 
+1

मैंने विंडोज 7 पर इसका सब कुछ परीक्षण किया 'हैंडलर' को 'रिटर्न सच्चे' और थोड़ी देर के लिए सेकंड्स गिनने के अलावा छोड़कर। एप्लिकेशन ctrl-c पर चल रहा है लेकिन एक्स –

3

मैं मिला है एक ऐसी ही बात नहीं, बस मेरे कंसोल अनुप्रयोग अनंत लूप में चल रहे हो जाएगा बीच में एक preemptive बयान के साथ।यहाँ मेरी समाधान है:

class Program 
{ 
    static int Main(string[] args) 
    { 
     // Init Code... 
     Console.CancelKeyPress += Console_CancelKeyPress; // Register the function to cancel event 

     // I do my stuffs 

     while (true) 
     { 
      // Code .... 
      SomePreemptiveCall(); // The loop stucks here wating function to return 
      // Code ... 
     } 
     return 0; // Never comes here, but... 
    } 

    static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e) 
    { 
     Console.WriteLine("Exiting"); 
     // Termitate what I have to terminate 
     Environment.Exit(-1); 
    } 
} 
1

link टिप्पणी में Charle बी द्वारा ऊपर उल्लेख किया

दीप नीचे flq को कहते हैं:

SetConsoleCtrlHandler windows7 पर काम नहीं करेगा अगर आप user32

से लिंक

धागे में कुछ और जहां एक छिपी हुई खिड़की को तोड़ने का सुझाव दिया जाता है। इसलिए मैं एक विनफॉर्म बनाता हूं और ऑनलोड में मैं कंसोल से जुड़ा हूं और मूल मुख्य निष्पादित करता हूं। और फिर SetConsoleCtrlHandle ठीक काम करता है (जैसा कि flq ने सुझाव दिया SetConsoleCtrlHandle कहा जाता है)

public partial class App3DummyForm : Form 
{ 
    private readonly string[] _args; 

    public App3DummyForm(string[] args) 
    { 
     _args = args; 
     InitializeComponent(); 
    } 

    private void App3DummyForm_Load(object sender, EventArgs e) 
    { 
     AllocConsole(); 
     App3.Program.OriginalMain(_args); 
    } 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool AllocConsole(); 
} 
+0

के साथ बंद होने पर 5 सेकंड के बाद बंद हो जाता है असल में यह काम नहीं करता है। मेरे पास मल्टी-विंडो डब्लूएफपी ऐप है और मैं कुछ अतिरिक्त जानकारी दिखाने के लिए कंसोल ('आपके ऑब्जेक्ट के रूप में' AllocConsole') का उपयोग करता हूं। समस्या यह है कि यदि उपयोगकर्ता कंसोल विंडो पर (एक्स) पर क्लिक करता है तो पूरा ऐप (सभी विंडोज) बंद हो जाता है। 'SetConsoleCtrlHandler' काम करता है, लेकिन ऐप हैंडलर में किसी भी कोड को निष्पादित करने से पहले किसी भी तरह से रोकता है (मुझे लगता है कि ब्रेकपॉइंट्स निकाल दिए गए हैं और फिर ऐप रोकता है)। –

+0

लेकिन मुझे समाधान मिला जो मेरे लिए काम करता है - मैं सरल ** अक्षम ** बंद बटन। देखें: http://stackoverflow.com/questions/6052992/how-can-i-disable-close-button-of-console-window-in-a-visual-studio-console-appl –

0

विजुअल स्टूडियो 2015 + विंडोज 10

  • सफाई के लिए अनुमति दें
  • एकल चरण एप्लिकेशन
  • कुछ goldplating

कोड:

using System; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Threading; 

namespace YourNamespace 
{ 
    class Program 
    { 
     // if you want to allow only one instance otherwise remove the next line 
     static Mutex mutex = new Mutex(false, "YOURGUID-YOURGUID-YOURGUID-YO"); 

     static ManualResetEvent run = new ManualResetEvent(true); 

     [DllImport("Kernel32")] 
     private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);     
     private delegate bool EventHandler(CtrlType sig); 
     static EventHandler exitHandler; 
     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 ExitHandler(CtrlType sig) 
     { 
      Console.WriteLine("Shutting down: " + sig.ToString());    
      run.Reset(); 
      Thread.Sleep(2000); 
      return false; // If the function handles the control signal, it should return TRUE. If it returns FALSE, the next handler function in the list of handlers for this process is used (from MSDN). 
     } 


     static void Main(string[] args) 
     { 
      // if you want to allow only one instance otherwise remove the next 4 lines 
      if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false)) 
      { 
       return; // singleton application already started 
      } 

      exitHandler += new EventHandler(ExitHandler); 
      SetConsoleCtrlHandler(exitHandler, true); 

      try 
      { 
       Console.BackgroundColor = ConsoleColor.Gray; 
       Console.ForegroundColor = ConsoleColor.Black; 
       Console.Clear(); 
       Console.SetBufferSize(Console.BufferWidth, 1024); 

       Console.Title = "Your Console Title - XYZ"; 

       // start your threads here 
       Thread thread1 = new Thread(new ThreadStart(ThreadFunc1)); 
       thread1.Start(); 

       Thread thread2 = new Thread(new ThreadStart(ThreadFunc2)); 
       thread2.IsBackground = true; // a background thread 
       thread2.Start(); 

       while (run.WaitOne(0)) 
       { 
        Thread.Sleep(100); 
       } 

       // do thread syncs here signal them the end so they can clean up or use the manual reset event in them or abort them 
       thread1.Abort(); 
      } 
      catch (Exception ex) 
      { 
       Console.ForegroundColor = ConsoleColor.Red; 
       Console.Write("fail: "); 
       Console.ForegroundColor = ConsoleColor.Black; 
       Console.WriteLine(ex.Message); 
       if (ex.InnerException != null) 
       { 
        Console.WriteLine("Inner: " + ex.InnerException.Message); 
       } 
      } 
      finally 
      {     
       // do app cleanup here 

       // if you want to allow only one instance otherwise remove the next line 
       mutex.ReleaseMutex(); 

       // remove this after testing 
       Console.Beep(5000, 100); 
      } 
     } 

     public static void ThreadFunc1() 
     { 
      Console.Write("> "); 
      while ((line = Console.ReadLine()) != null) 
      { 
       if (line == "command 1") 
       { 

       } 
       else if (line == "command 1") 
       { 

       } 
       else if (line == "?") 
       { 

       } 

       Console.Write("> "); 
      } 
     } 


     public static void ThreadFunc2() 
     { 
      while (run.WaitOne(0)) 
      { 
       Thread.Sleep(100); 
      } 

      // do thread cleanup here 
      Console.Beep();   
     } 

    } 
} 
0

ज़ीरोकेल्विन का उत्तर विंडोज 10 x64, .NET 4.6 कंसोल ऐप में काम करता है।

class Program 
{ 
    private delegate bool ConsoleCtrlHandlerDelegate(int sig); 

    [DllImport("Kernel32")] 
    private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerDelegate handler, bool add); 

    static ConsoleCtrlHandlerDelegate _consoleCtrlHandler; 

    static void Main(string[] args) 
    { 
     _consoleCtrlHandler += s => 
     { 
      //DoCustomShutdownStuff(); 
      return false; 
     }; 
     SetConsoleCtrlHandler(_consoleCtrlHandler, true); 
    } 
} 

हैंडलर से गलत रिटर्निंग रूपरेखा है कि हम नहीं "निपटने" कर रहे हैं नियंत्रण बताता है: जो लोग CtrlType enum से निपटने के लिए की जरूरत नहीं है के लिए, यहाँ ढांचे के बंद में हुक करने के लिए एक बहुत आसान तरीका है सिग्नल, और इस प्रक्रिया के लिए हैंडलर की सूची में अगला हैंडलर फ़ंक्शन का उपयोग किया जाता है। यदि कोई भी हैंडलर सत्य नहीं लौटाता है, तो डिफ़ॉल्ट हैंडलर को बुलाया जाता है।

ध्यान दें कि जब उपयोगकर्ता लॉगऑफ या शट डाउन करता है, तो कॉलबैक विंडोज द्वारा नहीं कहा जाता है लेकिन इसे तुरंत समाप्त कर दिया जाता है।