Archived

This forum has been archived. Please start a new discussion on GitHub.

Capture Console Exit c#

Hi,

When developing a console application I got a weird problem. I was trying to capture a console exit using this code snippet:
#region unmanaged
        // Declare the SetConsoleCtrlHandler function
        // as external and receiving a delegate.

        [DllImport("Kernel32")]
        public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

        // A delegate type to be used as the handler routine
        // for SetConsoleCtrlHandler.
        public delegate bool HandlerRoutine(CtrlTypes CtrlType);

        // An enumerated type for the control messages
        // sent to the handler routine.
        public enum CtrlTypes
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT,
            CTRL_CLOSE_EVENT,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT
        }

        #endregion

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
        {
            // Put your own handler here
            switch (ctrlType)
            {
                case CtrlTypes.CTRL_C_EVENT:
                    isclosing = true;
                    Console.WriteLine("CTRL+C received!");
                    break;

                case CtrlTypes.CTRL_BREAK_EVENT:
                    isclosing = true;
                    Console.WriteLine("CTRL+BREAK received!");
                    break;

                case CtrlTypes.CTRL_CLOSE_EVENT:
                    isclosing = true;
                    Console.WriteLine("Program being closed!");
                    break;

                case CtrlTypes.CTRL_LOGOFF_EVENT:
                case CtrlTypes.CTRL_SHUTDOWN_EVENT:
                    isclosing = true;
                    Console.WriteLine("User is logging off!");
                    break;

            }
            return true;
        }

In main function:
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
This code snippet works when not using Ice. However, whenever I call
Communicator ic = Util.initialize(ref args);
I get a nullreference exception when closing the console.
What can i do?
I'm using Ice 3.4.1 and developing in Visual Studio 2010 on a Windows 7.
Kind regards
Bob

Comments

  • xdm
    xdm La Coruña, Spain
    Hi Bob,

    Could you post a complete example that demonstrate the issue, i have been doing some testing based on the code you posted, but have not found any problems.

    Best regards,
    Jose
  • Hi,
    thanks for your response.
    This is the code:
    class Program
        {
            private static bool isclosing = false;
    
            static void Main(string[] args)
            {
                PositionCalculatorI calculatorI = new PositionCalculatorI();
                SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
                int status = 0;
                Communicator ic = null;
                try
                {
                    ic = Util.initialize(ref args);
                    Ice.Properties properties = ic.getProperties();
                    ObjectAdapter adapter = ic.createObjectAdapter("CalculatorAdapter");
                    Identity id = ic.stringToIdentity(properties.getProperty("Identity"));
                    adapter.add(calculatorI, id);
                    adapter.activate();
                    //ic.waitForShutdown();
                    Console.WriteLine("ServerICE Initialised");
                    Console.ReadLine();
                }
                catch (Exception exception)
                {
                    Console.Error.WriteLine(exception);
                    status = 1;
                }
    
                if (ic != null)
                {
                    try
                    {
                        ic.destroy();
                    }
                    catch (Exception e)
                    {
                        Console.Error.WriteLine(e);
                        status = 1;
                    }
                }
    
                Environment.Exit(status);
            }
    
            private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
            {
                // Put your own handler here
                switch (ctrlType)
                {
                    case CtrlTypes.CTRL_C_EVENT:
                        isclosing = true;
                        Console.WriteLine("CTRL+C received!");
                        break;
    
                    case CtrlTypes.CTRL_BREAK_EVENT:
                        isclosing = true;
                        Console.WriteLine("CTRL+BREAK received!");
                        break;
    
                    case CtrlTypes.CTRL_CLOSE_EVENT:
                        isclosing = true;
                        Console.WriteLine("Program being closed!");
                        break;
    
                    case CtrlTypes.CTRL_LOGOFF_EVENT:
                    case CtrlTypes.CTRL_SHUTDOWN_EVENT:
                        isclosing = true;
                        Console.WriteLine("User is logging off!");
                        break;
    
                }
                return true;
            }
    
            #region unmanaged
            // Declare the SetConsoleCtrlHandler function
            // as external and receiving a delegate.
    
            [DllImport("Kernel32")]
            public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
    
            // A delegate type to be used as the handler routine
            // for SetConsoleCtrlHandler.
            public delegate bool HandlerRoutine(CtrlTypes CtrlType);
    
            // An enumerated type for the control messages
            // sent to the handler routine.
            public enum CtrlTypes
            {
                CTRL_C_EVENT = 0,
                CTRL_BREAK_EVENT,
                CTRL_CLOSE_EVENT,
                CTRL_LOGOFF_EVENT = 5,
                CTRL_SHUTDOWN_EVENT
            }
    
            #endregion
        }
    
    This code is my complete program.cs (except for the namespace).
    When i comment out this line:
    SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
    
    this code works perfectly and runs smootly. However, I want to be able to detect closing of the console so i can shut down my program properly.
    Kind regards
    Bob
  • xdm
    xdm La Coruña, Spain
    Hi,

    I tested your demo and it works here.
    ConsoleApplication.exe --Ice.Config=config.server
    ServerICE Initialised
    CTRL+C received!
    

    Could you post the stack trace of the exception.
  • Hi,

    Does it give the right output when closing the console with the 'X' in the corner.
    Could you post the stack trace of the exception.
    That's kind of the problem, we don't get a stack trace. But since you got it working it will probably be another problem. The question is: what is wrong?

    Kind regards
    Bob
  • I'm Bob's teammate and for now, we solved the problem by:
    Right click on your project --> properties --> Debug --> uncheck "Enable the Visual Studio hosting proces".

    But, this doesn't solve the whole problem. When a client connects to the server and we close the server afterwards (no mather if we close the client first or not), it still gives a nullreference... and the stack is empty, like bob said...

    Kind Regards
  • xdm
    xdm La Coruña, Spain
    Seems that is a VS 2010 bug

    Debugging C# Console application that handles Console.CancelKeyPress is broken in .NET 4.0 | Microsoft Connect

    Enabling "unmanaged code debugging" workaround the problem.
  • When I try this, it gives the following error when I use Ctrl+C:

    "First-chance exception at 0x75066a6f in CalculatorTest.exe: 0x40010005: Control-C."

    Kind regards

    EDIT: it gives me three options: Break, continue and Ignore. Both Continue and Ignore just skip the error and 'working' *ahum* but when I click Break, it gives an exception at kernel32.dll!75066a6f()
  • xdm
    xdm La Coruña, Spain
    That is expected and commented in the workaround, of the bug report.

    Click "Continue" and then the control handler is called.
  • Yeah indeed, but I can't always have to click 'Continue'... It shouldn't be triggered and automatically call the control handler...
  • xdm
    xdm La Coruña, Spain
    You can also disable the exception in VS 2010.

    Debug > Exceptions > Win 32 Exceptions > Control-C

    That seems to be enabled by default in VS 2010
  • Well, after trying all this, it works when I don't connect a client... But when I connected a client to the server (It doesn't matter whether I close the client or not) and I close the server, it gives this error:

    "An unhandled exception of type 'System.NullReferenceException' occurred in Unknown Module.

    Additional information: Object reference not set to an instance of an object"

    So it's quite the same error as before...

    Kind Regards

    EDIT: when I click 'Break' it gives this stack: ntdll.dll!774ff861()
  • xdm
    xdm La Coruña, Spain
    Hi,

    I cannot reproduce your problem, it works for me when i check "Enable unmanaged code debugging"

    Did you see any problem when run the program outside the Visual Studio Debugger?

    Seems to me that the problem is something specific to Visual Studio Debugger, and Control C signal, you will have better look asking in visual studio forums about this problem.

    Bests regards,
    Jose
  • Hi,

    it will be a Visual studio problem then. We are not able to run when outside de visual studio debugger.
    Anyway, thanks for the response and your help!

    kind regards
    Bob and Jens