Click here to Skip to main content
15,885,914 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi
I have inherited a console app written in C# that exits nicely when you click the console close button.

I'm trying to replicate that close button functionality in code but I keep running into internal code errors. Why does the console close button work but code does not?

What does the Close Box actually do to a app?

Ok, seems I need to explain a bit better.
The app operates in a visible console screen with status data being displayed and updated.
The app is quite complicated and large. It has threads running so proving quite difficult to shut down in code plus C# is not my thing although I muddle through.
Despite the threads running etc etc, clicking the console top right Close Box nicely quits the app without any errors.

I wish to replicate the console shutdown action in code so I can implement a midnight shutdown.
Using Environment.Exit(0) or Application.Exit throws lots of errors to do with threads.
If the console window can exit without errors then why can't I dump out of the app in code? I realise this is not a good way to approach the problem but I need a quick and dirty solution whilst I work on understanding things better and do it right later on.

Hope this helps explain a bit better.

What I have tried:

I've tried
C#
Environment.Exit(0);
and
C#
Application.Exit()
Posted
Updated 23-Feb-16 12:09pm
v2
Comments
Garth J Lancaster 22-Feb-16 22:27pm    
Not sure I follow what you're trying to do - you have a console program - it doesnt (99.999% of time) have a window of its own - it runs within a process, most often a command window called cmd.exe. Are you saying when the console program has finished you wish to terminate the cmd.exe process ? my 'guess' is you could get a list of ALL processes, filter for cmd.exe, then 'post a close' to it, but how you you know if you have the correct cmd.exe unless there's only one open ... Environment.Exit(0) & Application.Exit() only affect the console program, NOT the cmd.exe process thats running - imagine for example if you had a batch file with two console programs - yet the first one does as you suggest and then kills cmd.exe - ta ta second console program... "What does the Close Box actually do to a app?" - terminate it with extreme predjudice !
Member 11709930 23-Feb-16 16:57pm    
Garth, I've updated the original question to try and explain some of this.
I guess "terminate it with extreme predjudice !" is what I need for now until I can understand the threads involved and shut down nicely.
Philippe Mori 23-Feb-16 18:17pm    
Learn first how to do multithreaded program correctly. It is very bad idea to write poor code hoping to fix it afterward. Too often, that bad code is never rewritten at all and you will regret your choice for many years.

Console applications end when the program completes, try this;
a) Open Visual Studio & create a new Console application
b) Enter the following in the Main method
C#
static void Main(string[] args)
{
    Console.WriteLine("Hullo World");
}

c) Compile the application
d) Browse to the executable in Windows & double-click - a console window will appear and disappear.
This is how a console application works.
If you were to run it via the command prompt you will see the text "Hullo World" & you would return to the command prompt.
If you want the application to wait until you do something edit the above code as follows;
C#
static void Main(string[] args)
{
    Console.WriteLine("Hullo World");
    Console.WriteLine("Press any key to exit...");
    Console.ReadyKey();
}

Now when you run it via double-click the application will display your console window & then wait until you press any key before closing.
If you run it at the command prompt you will still see "Hullo World" and "Press any key to exit" and you will need to press a key to return to the command prompt.

Debug your existing console application to see why it is not "closing" itself

Kind Regards
 
Share this answer
 
Comments
Member 11709930 23-Feb-16 18:06pm    
Thanks, This app never completes. Runs 24/7 until manually closed. I've updated the original description to try and explain things better.
an0ther1 23-Feb-16 21:13pm    
Since you are going to stop it at midnight, how do you intend to start it again?
Without looking at the actual code I would guess it is running some type of loop that executes every x minutes or runs continually.
The underlying point is that a console application will end cleanly when the Main method ends.
Is there a reason that you could not simply check the current time at the beginning of each loop & exit if the time is after 11.55pm?
It might not be pretty, or best practice, but would meet your requirements.
If you are starting threads within the application go and stop each one, then exit.

Cheers
Member 11709930 24-Feb-16 19:52pm    
It would start again via Windows Scheduler.
Your assumptions are basically correct. I tried heading off the loop but the problems seem to lie in some of the threads not closing.
I've put more time into stepping through the code and there is CTL_C and CTL_BREAK handling in place-

private static bool TermHandlerRoutine(CtrlTypes dwCtrlType)
{
switch (dwCtrlType)
{ //no break so all close events handled same
case CtrlTypes.CTRL_CLOSE_EVENT:
case CtrlTypes.CTRL_BREAK_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
case CtrlTypes.CTRL_C_EVENT:
terminated = true;
return true;
}
return false;
}

'terminated = true;' is detected by the loop which then fires this to close off process console handlers -

public static void Exit()
{
if (!initialized)
{
return;
}

// Unregister each callback delegate that the list contains
for (int i = 0; i < callbacks.Count; i++)
{
SetConsoleCtrlHandler(callbacks[i], false);
}

callbacks.Clear();

initialized = false;
terminated = true;
}

That gets us out of the loop where we initiate a thread cleanup -
private void Cleanup()
{
// Stop SessionClients
foreach (var item in sessionClients)
{
if (item.Value != null)
{
item.Value.Stop();
}
}

// Wait for SessionClients to terminate
foreach (var item in sessionClients)
{
if (item.Value != null)
{
try
{
item.Value.Wait();
}
catch (System.Exception ex)
{
Console.Write(ex);
}
}
}

sessionClients.Clear();

if (appLoggerMonitor != null)
{
appLoggerMonitor.Destroy();
appLoggerMonitor = null;
}

if (appLogger != null)
{
appLogger.Release();
appLogger = null;
}

if (eventQueue != null)
{
while (eventQueue.HasActiveEventStreams)
{
eventQueue.Dispatch(-1);
}

eventQueue.Destroy();
eventQueue = null;
}

if (rfaConfigDB != null)
{
rfaConfigDB.Release();
rfaConfigDB = null;
}

if (appConfigDB != null)
{
appConfigDB.Release();
appConfigDB = null;
}


// Uninitialise Context
if (!Context.Uninitialize() && Context.InitializedCount == 0)
{
// report problem if and ONLY if Context.Uninitialize() returned false
// AND Context.InitializedCount returns zero;
// if Context.InitializedCount returns more than zero, RFA did not attempt to uninitialize its context
Utils.ReportError("Application", configClient.ConfigurationClientName, "RFA Context fails to uninitialize ... ");
}

AppUtil.CleanupLog();
eventQueueSemaphore.Release();
eventQueueSemaphore = null;
}


From this, item.Value.Stop() and item.Value.Wait() fire these-

public void Stop()
{
try
{
stopping = true;
thread.Abort();
}
catch (System.Exception)
{
}
}

public void Wait()
{
Member 11709930 24-Feb-16 19:53pm    
Seems there is a line limit hence clipped response. Here's the rest-

public void Wait()
{
thread.Join();
}

Ok, hope some of that makes sense.
It seems there is a problem with thread.Join() for one of the threads. When this is reached, stepping is dumped and the console window sits there with a blinking cursor. I tried surrounding it with a Try/Catch but nothing is caught and the code does not step to the lines below.
If I now hit CTL_C again, the app exits immediately.

Think my question now is, how do I debug thread.join ?
an0ther1 24-Feb-16 23:40pm    
You cannot. Thread.Join blocks the calling thread until a thread terminates.
You need to identify the thread that is not ending and work out why & then kill it - probably with fire :-)
Cheers
You've got problems with your application.

Clicking the Close button in the corner of the console window does NOT shutdown your app "nicely". It's quite the opposite. It stops your application abruptly and the memory it is occupying is freed. This can lead to resource leaks since not everything has been released in a nice manner.

Your work should really be on fixing the problems with the code, not trying to replicate something that's doing more bad than good.
 
Share this answer
 
Comments
Member 11709930 24-Feb-16 15:48pm    
As I said, C is not my thing and I do not have the luxury of time at this point to do things properly.
I need something that will dump the app in the same way that clicking the X does. That makes the boss happy and buys me the time to understand whats going on in this thing and do it properly.
Dave Kreskowiak 24-Feb-16 16:28pm    
Well, the only way to do that is to have the code get its own Process and then Kill it. Like I said, this is a bad thing.

Process.GetCurrentProcess Method (System.Diagnostics)[^]
Process.Kill Method (System.Diagnostics)[^]

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