Console problem

BlitzMax Forums/BlitzMax Programming/Console problem

nawi(Posted 2009) [#1]
How can I (in a console program)
a) Run some code after the user clicks the X button to close the program
b) Catch some keyboard input without stopping the program. Keyhit, getchar etc won't work in console program. Input() stops the program.

What I'm doing, is that my server has to do some cleanup at the end of the program, but I don't know how to execute CleanUp() function at the end of the program.


Kistjes(Posted 2009) [#2]
Use the OnEnd() function.


Phil Newton(Posted 2009) [#3]
I'm having the exact same problem right now. OnEnd doesn't seem to work when the X button is closed in a console app.


Nate the Great(Posted 2009) [#4]
bmax can make games for consoles like Xbox? sorry but have I been uninformed this whole time? or is this c++?


Phil Newton(Posted 2009) [#5]
Nope, talking about a text-based console window, like when you run "cmd" from Windows.

Sorry :)


Nate the Great(Posted 2009) [#6]
oh ok just making sure I wasn't missing out :)


nawi(Posted 2009) [#7]
Use the OnEnd() function.

This doesn't work, since "end" is not called when you close the program.


Kistjes(Posted 2009) [#8]
This doesn't work, since "end" is not called when you close the program.

Didn't know that.


plash(Posted 2009) [#9]
OnEnd doesn't seem to work when the X button is closed in a console app.
It does seem to, in a sense, but it does not seem like you can actually return to regular process (after any instructions you give it, it stills exits, ultimately).

SuperStrict

Framework brl.blitz
Import brl.standardio
Import brl.system

OnEnd(Cleanup)

Input("Terminate me!")
End

Function Cleanup()
	
	CreateFile("Ahha.blah") ' Proof!
	
End Function



Nate the Great(Posted 2009) [#10]
maybe have a loop that says if appterminate then do this


EOF(Posted 2009) [#11]
I am working on a Console Control module as it happens but I have not got round to doing the KeyDown()/KeyHit() side of things
I only have Input() so far as a method for reading the user input

WINDOWS ONLY

Examples of some of the commands:
Console.Open "Test window"
Console.SetColor RED,GREY
Console.Cls
Console.SetCursorPos 10,5
Console.Write "Hello world"

t$=Console.Input("Enter your name > ")

Console.Close



nawi(Posted 2009) [#12]
Plash, you don't understand the problem. It's like this.


'Server code
Repeat
   'Do server stuff
   UpdateClients()

Forever 'I cannot use Input, it stops updating clients
        'cannot use keyhit, getchar, etc etc..

OnEnd(Cleanup)

Function Cleanup()
	
	CreateFile("Ahha.blah") ' Proof!
	
End Function

Cleanup will never be called if I run this as a console app and hit X to close the server. If I could somehow catch user input like (hit key escape) then that would be an okay solution too. The user should just hit escape to close the program. But keyhit, getchar doesn't work in console mode.


grable(Posted 2009) [#13]
@nawi, For non-halting input, try some of the functions from c stdio/conio..
Extern "C"
  Function getchar:Int()
  Function getch:Int()
  Function getche:Int()
  Function kbhit:Int()
EndExtern



plash(Posted 2009) [#14]
Cleanup will never be called if I run this as a console app and hit X to close the server.
Uhm.. Given the position you put your OnEnd call, that is absolutely correct.
How do you expect the Cleanup function to be called when it is never told to before the program actually exits? (OnEnd never gets called because it completely stops at whatever point in your loop to do the exit, at which point it calls all OnEnd callbacks)

EDIT: Think of it like this:
Your program is doing its main loop, updating clients and whatever.
Then the user hits the X button on the Console's window, which then goes through some stuff on the Win32 end.
It eventually calls your program's exit function (keep in mind these times are within nano/milli-seconds), which then calls all OnEnd callbacks.

If you will read that carefully, you will notice that you never actually called OnEnd.

EDIT2: Code example of the first edit:
SuperStrict

Framework brl.blitz
Import brl.system

Repeat
	
	Delay(2000) ' Simulatory..
	End() ' This will be our substitute for the user pressing the X button.
		' Note that you could also just do an infinite loop and just hit the X button (not using End())
	
Forever

OnEnd(Cleanup) ' NEVER gets called. Ever.

Function Cleanup()
	
	CreateFile("Ahha.blah")
	
End Function



Nate the Great(Posted 2009) [#15]
so you should put onend at the beginning right after super strict.


Zeke(Posted 2009) [#16]
Extern "WIN32"
	Function SetConsoleCtrlHandler:Int(func(),add:Int)
End Extern

Extern "C"
  Function getch:Int()
  Function kbhit:Int()
EndExtern

SetConsoleCtrlHandler(Cleanup,True)

Local running=1

Print "Close window or type something"
While running
	If kbhit() Then Print "keyhit: "+getch()
Wend

Function Cleanup()
	running=0
	Notify "Cleaning..."
End Function

but this is windows only..


nawi(Posted 2009) [#17]
Plash, you don't understand the problem. End() is not called when the user clicks the X button in a console program, so placing OnEnd before the loop doesn't fix anything.

Windows-only solutions don't help.

' Note that you could also just do an infinite loop and just hit the X button (not using End())

That's incorrect, I just tested.


Nurgle(Posted 2009) [#18]
@nawi the code that Plash has posted does work clicking the x in a console will create a file called Ahha.blah
example of infinite loop with no End
SuperStrict

Framework brl.blitz
Import brl.system
Import brl.standardio

OnEnd(Cleanup) 

Print "Click x to exit"

Repeat

	
Forever

Function Cleanup()
	
	CreateFile("Ahha.blah")
	
End Function



nawi(Posted 2009) [#19]
@Nurgle.
I see now that it does work, but there seems to be a really small time to execute any code. If I try to loop 100 times and print stuff, I only get like 10 print's. Likewise, my goal is to connect to a server and there is no time for that either.. In fact, if you add delay 5000, the app still closes rapidly.

What I'm trying to do, if that when the server is closed, the server connects to a serverlist-server, and notifys it to remove that server from the list. Yeah, I have a timeout system in plaec, and it will be removed after some time, but this causes the server to be on the list for a minute or too and players will try to connect to it, even though it should've been removed.


plash(Posted 2009) [#20]
Plash, you don't understand the problem. End() is not called when the user clicks the X button in a console program, so placing OnEnd before the loop doesn't fix anything.
OnEnd adds functions to be called when 'exit' is called (for Max use, 'End' is the same as calling 'exit'). The 'exit' function is in C, and is automatically called WHENEVER the program shuts down (via normal means - a crash/taskkill probably wont call it, afaik).

/mod/brl.mod/blitz.mod/blitz_app.c
void bbEnd(){
	exit(0);
}

void bbOnEnd( void (*f)() ){
	atexit( f );
}

Notice the internal functions for Max. 'End' actually does call 'exit' (with the exit code 0, meaning no error).
OnEnd adds a function to be called when the program is closed (and, subsequently, when you call 'End').


nawi(Posted 2009) [#21]
Yes I know that now Plash, but I explained a new problem in my post above.


plash(Posted 2009) [#22]
There is no way to get around that issue unless you can capture the events for the console and do with them as you wish.


Cold Storage(Posted 2010) [#23]
I'm a bit late to the party(!)

But, you could have used a 'boot' program to launch your main .exe.

The boot program hangs around polling every now and again to see if the main program has finished. If it has, then it closes everything off nicely for you, then self-terminates.

I've had to employ a similar set-up for my project....

I have one program that very graphically intensive but it needs to sit and wait for FTP feedback (not quick by any means!). So instead, I have an FTP program that launches the graphical program and passes data to it via a shared file.

This way the FTP program can take as long as it likes, but the graphical program can run un-hindered. ( I also hide the FTP window so the user doesn't know it's there ).

A kind of poor man's multi-thread. ;o)