none
How to capture closing of c# console apps RRS feed

  • Question

  • suppose i have c# console apps when user run the apps then apps do some job and then close or exit. so i want to capture or fire a routine which will fire just before close the console apps as a result i can de-allocate / dispose the memory of many instance created during program run.

    so guide me is there any event in console apps like win form which fire before closing the apps. please guide me with sample code. thanks

    Sunday, April 24, 2016 7:42 PM

Answers

  • Hi  Mou_kolkata,

    >> so i want to capture or fire a routine which will fire just before close the console apps as a result i can de-allocate / dispose the memory of many instance created during program run.

    I have created a demo as below to execute something before the console application be closed and you could have a look.

            static void OnProcessExit()
            {
                string path = @"D:\OnProcessExitRecording.txt";
                if (!File.Exists(path))
                {
                    File.Create(path);
                    TextWriter tw = new StreamWriter(path);
                    tw.WriteLine("This program has exited at " + DateTime.Now.ToString());
                    tw.Close();
                }
                else if (File.Exists(path))
                {
                    TextWriter tw = new StreamWriter(path, true);
                    tw.WriteLine("This program has exited at " + DateTime.Now.ToString());
                    tw.Close();
                }
            }
            static bool ConsoleEventCallback(int eventType)
            {
                if (eventType == 2)
                {
                    OnProcessExit();
                }
                return false;
            }
            static ConsoleEventDelegate handler;   // Keeps it from getting garbage collected
                                                   // Pinvoke
            private delegate bool ConsoleEventDelegate(int eventType);
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
    
    
    
            static void Main(string[] args)
            {
                handler = new ConsoleEventDelegate(ConsoleEventCallback);
                SetConsoleCtrlHandler(handler, true);
                Console.ReadLine();
           }
    

    Best Regards,

    Albert Zhang

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 3:49 PM
    Monday, April 25, 2016 7:36 AM
  • Hi,

    I do not have a propper example that would make much sense. But just let us create some example that is not useful but hopefully shows what I mean.

    Imagine we want to write a Logger class. This will hold a stream or writer open all the time (No idea why we want that, but ok, we decided that this is the requirement. Maybe we want to make sure that noone can delete or see the logfile!). This stream implements IDisposable so we should make sure that it is closed again.

    In our application we have the great idea to have one Logger inside the static class.

    So we could build classes like this:

    Logger class implementing the Disposable pattern

    using System;
    using System.Diagnostics;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        public class Logger : IDisposable
        {
            /// <summary>
            /// Implements IDisposable so we implement IDisposable, too!
            /// </summary>
            private StreamWriter _writer;
    
            /// <summary>
            /// Creates a new instance of Logger.
            /// </summary>
            /// <param name="filename">File to log to.</param>
            public Logger(string filename)
            {
                _writer = new StreamWriter(filename);
            }
    
            /// <summary>
            /// Finalizer
            /// </summary>
            ~Logger()
            {
                // We should never get into this point. Getting here is an error of the developer!
                Debug.WriteLine("Error - we forgot to dispose {0}", GetType().FullName);
                Dispose(false);
            }
    
            /// <summary>
            /// Dispose / close this instance.
            /// </summary>
            public void Dispose()
            {
                // Do a full dispose
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            /// <summary>
            /// Dispose / close this instance.
            /// </summary>
            public void Close()
            {
                Dispose();
            }
    
            protected virtual void Dispose(bool disposing)
            {
                // Call base class
                //base.Dispose(disposing);
    
                if (disposing)
                {
                    // Dispose managed stuff
                    _writer?.Close();
                }
    
                // Dispose unmanaged stuff.
            }
    
            // Some usefull methods are required here to write log messages.
        }
    }
    

    Main application using this:

    namespace ConsoleApplication1
    {
        public class Program
        {
            public static Logger ApplicatLogger;
    
            static void Main(string[] args)
            {
                using (ApplicatLogger = new Logger("logfile.txt"))
                {
                    // Do your application stuff here ...
                }
            }
        }
    }

    That way you control the ressource. There might be situations, where it is a little harder e.g. when you have a windows Forms application where the main thread continues and the UI will run in the separate thread. But even there a solution could be quite easy and straight forward.

    With kind regards,

    Konrad

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 5:49 PM
    Monday, April 25, 2016 4:11 PM
  • Hi,

    the description can be found on MSDN:

    SetConsoleCrtlHandler Function: 
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx

    The HandlerRoutine:
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms683242(v=vs.85).aspx
    (
    Here you find the available eventTypes)

    The 2 is the CTRL_CLOSE_EVENT:
    A signal that the system sends to all processes attached to a console when the user closes the console (either by clicking Close on the console window's window menu, or by clicking the End Task button command from Task Manager).

    delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++ (https://msdn.microsoft.com/en-us/library/ms173172.aspx)

    It was made static because that way it does not belong to an instance which the GC could collect.

    With kind regards,

    Konrad

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 5:49 PM
    Monday, April 25, 2016 4:23 PM

All replies

  • Hi  Mou_kolkata,

    >> so i want to capture or fire a routine which will fire just before close the console apps as a result i can de-allocate / dispose the memory of many instance created during program run.

    I have created a demo as below to execute something before the console application be closed and you could have a look.

            static void OnProcessExit()
            {
                string path = @"D:\OnProcessExitRecording.txt";
                if (!File.Exists(path))
                {
                    File.Create(path);
                    TextWriter tw = new StreamWriter(path);
                    tw.WriteLine("This program has exited at " + DateTime.Now.ToString());
                    tw.Close();
                }
                else if (File.Exists(path))
                {
                    TextWriter tw = new StreamWriter(path, true);
                    tw.WriteLine("This program has exited at " + DateTime.Now.ToString());
                    tw.Close();
                }
            }
            static bool ConsoleEventCallback(int eventType)
            {
                if (eventType == 2)
                {
                    OnProcessExit();
                }
                return false;
            }
            static ConsoleEventDelegate handler;   // Keeps it from getting garbage collected
                                                   // Pinvoke
            private delegate bool ConsoleEventDelegate(int eventType);
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
    
    
    
            static void Main(string[] args)
            {
                handler = new ConsoleEventDelegate(ConsoleEventCallback);
                SetConsoleCtrlHandler(handler, true);
                Console.ReadLine();
           }
    

    Best Regards,

    Albert Zhang

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 3:49 PM
    Monday, April 25, 2016 7:36 AM
  • Hi,

    I think that this is simply the wrong way to handle resources. You should write code in a way that you keep care of the memory allocated / other blocked resources so that you can do the dispose / de.allocation when you no longer use them.

    In c# it is the disposable pattern which you should look at. The core rules are simply:
    - When you use a disposable object, then put them into using e.g. using (var disposableInstance = new DisposableClass()) { ... }. If that pattern does not fit (e.g. unmanaged resources) then you use try / finally!

    - When you have to store a disposable object (or you have some unmanaged resources that needs to be closed), then your class implements IDisposable on its own!

    That way your resources will be handled before the application quits (which is quite lame because once an application quits, used memory, handles and so on are freed.)

    So please do it properly from the start else you start messing around and doing hacks which will result in poor quality code and buggy applications.

    With kind regards,

    Konrad

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 3:51 PM
    • Unmarked as answer by Mou_kolkata Monday, April 25, 2016 3:51 PM
    Monday, April 25, 2016 7:46 AM
  • I'm a bit confused why you want to explicitly de-allocate this memory.

    Is it not being freed up anyhow?

    Or do you have a memory leak?

    Why is that?

    Many instances of what?


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Monday, April 25, 2016 8:25 AM
    Moderator
  • You memory design sounds really wierd to outright faulty or just lacking the most basic understanding of how stuff works in .NET.
    So I will mostly ignore your question and give you some "Programmign Guideliens" that should make this question unessesary.

    The Garbage collector will clean up any managed resources at application closure or when memory demands require it. That (and not having to handle naked pointers) is the reason we invented it.
    You should not interfere with it's work here:
    Garbage Collection - Pros and Limits

    The only reasources you need to worry about are umanaged resources. For that there is the dispose pattern:
    Dispose Pattern

    If you handle unmanaged resources directly in your class, you must provide a finalizer so the GC can do it's work.
    You should also implement IDisposeable as convenience for people using your class, but the finalizer has priority.

    If you only handle stuff that implement IDisposeable the first rule is to never keep a reference to that around. Create it, use it and dispose of it in the same codeblock. Ideally using a using directive.
    Do not split up creation and disposing for performance reason. Do not save them into variables that live longer then the function they are created in.

    Splitting creation and disposing up will always end up biting you.

    In the very rare cases you need too (like keeping a file open in a word processor), just implement IDisposeable in the class with the "Disposeable stuff".
    This implementation only exist to relay the dispose call to encapsulated classes.

    Finalize and Dispose call tend to use the same code in the end, but with one differnce:
    You never relay a finalize call. Finalisation is between the GC and that specific instance.
    You always relay a dispose call. Relaying it to contained classes is the only reason many class implement IDisposeable to begin with.

    Monday, April 25, 2016 1:16 PM
  • @KOnrad would u post some sample code or hint to handle it. IDisposable is most often used when people work with unmanage resource. i do not want to use IDisposable rather looking for some other way around to handle this issue.
    Monday, April 25, 2016 3:51 PM
  • i have couple of question.

    what is eventType == 2 ?  what other value eventType can have ?

    tell me something about SetConsoleCtrlHandler. what SetConsoleCtrlHandler does ?

    when people use SetConsoleCtrlHandler ?

    what is this for static ConsoleEventDelegate handler; ?



    Monday, April 25, 2016 3:54 PM
  • Hi,

    I do not have a propper example that would make much sense. But just let us create some example that is not useful but hopefully shows what I mean.

    Imagine we want to write a Logger class. This will hold a stream or writer open all the time (No idea why we want that, but ok, we decided that this is the requirement. Maybe we want to make sure that noone can delete or see the logfile!). This stream implements IDisposable so we should make sure that it is closed again.

    In our application we have the great idea to have one Logger inside the static class.

    So we could build classes like this:

    Logger class implementing the Disposable pattern

    using System;
    using System.Diagnostics;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        public class Logger : IDisposable
        {
            /// <summary>
            /// Implements IDisposable so we implement IDisposable, too!
            /// </summary>
            private StreamWriter _writer;
    
            /// <summary>
            /// Creates a new instance of Logger.
            /// </summary>
            /// <param name="filename">File to log to.</param>
            public Logger(string filename)
            {
                _writer = new StreamWriter(filename);
            }
    
            /// <summary>
            /// Finalizer
            /// </summary>
            ~Logger()
            {
                // We should never get into this point. Getting here is an error of the developer!
                Debug.WriteLine("Error - we forgot to dispose {0}", GetType().FullName);
                Dispose(false);
            }
    
            /// <summary>
            /// Dispose / close this instance.
            /// </summary>
            public void Dispose()
            {
                // Do a full dispose
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            /// <summary>
            /// Dispose / close this instance.
            /// </summary>
            public void Close()
            {
                Dispose();
            }
    
            protected virtual void Dispose(bool disposing)
            {
                // Call base class
                //base.Dispose(disposing);
    
                if (disposing)
                {
                    // Dispose managed stuff
                    _writer?.Close();
                }
    
                // Dispose unmanaged stuff.
            }
    
            // Some usefull methods are required here to write log messages.
        }
    }
    

    Main application using this:

    namespace ConsoleApplication1
    {
        public class Program
        {
            public static Logger ApplicatLogger;
    
            static void Main(string[] args)
            {
                using (ApplicatLogger = new Logger("logfile.txt"))
                {
                    // Do your application stuff here ...
                }
            }
        }
    }

    That way you control the ressource. There might be situations, where it is a little harder e.g. when you have a windows Forms application where the main thread continues and the UI will run in the separate thread. But even there a solution could be quite easy and straight forward.

    With kind regards,

    Konrad

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 5:49 PM
    Monday, April 25, 2016 4:11 PM
  • Hi,

    the description can be found on MSDN:

    SetConsoleCrtlHandler Function: 
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx

    The HandlerRoutine:
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms683242(v=vs.85).aspx
    (
    Here you find the available eventTypes)

    The 2 is the CTRL_CLOSE_EVENT:
    A signal that the system sends to all processes attached to a console when the user closes the console (either by clicking Close on the console window's window menu, or by clicking the End Task button command from Task Manager).

    delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++ (https://msdn.microsoft.com/en-us/library/ms173172.aspx)

    It was made static because that way it does not belong to an instance which the GC could collect.

    With kind regards,

    Konrad

    • Marked as answer by Mou_kolkata Monday, April 25, 2016 5:49 PM
    Monday, April 25, 2016 4:23 PM