I often (really, very often) write console programs. Most of them are simple test programs to test algorithms, calculations or language features, or stuff copied from StackOverflow.
But console programs, if run from the IDE, or from the Windows Explorer, have one annoying feature: they close immediately if they are finished. So if my program has many Writelns
in it, they simply rush by and the console window closes before I can inspect the output. To avoid that, I often put Readln;
in the last line of the program. If the program is finished, it pauses and waits for me to press Enter.
But such a Readln;
is annoying if I really want to run the program from an existing console window (aka a Windows command line). Then I don't want to have to press Enter, because the output is shown in the current console window already, and that won't close until I tell it to.
To get the best of both worlds, I wrote my simple Velthuis.AutoConsole
unit. Put it in the uses
clause of your console program and, if the program is a console program and it was started from the command line, or if it is not a console program, it will do nothing. But if it is a console program and it was started any other way (from the Windows Explorer, from the Delphi IDE with or without debugger, from another non-console program), then, before the console window can close, it will display:
Press any key...
Then I really only have to press a key (it does not have to be Enter, it can be any key) and the program will end, closing the console Window.
I placed the new unit in the zip for my Console unit. You can download it from the page I linked to.
Here is the code of this simple unit. I think I may have to add a ConsoleCtrlHandler
, so the window is not closed when the user presses Ctrl+C or closes the console window with the x
close button on the window frame. But I am not sure if that is necessary. If I press those, I usually want to stop the program anyway. Comments on this are welcome.
unit Velthuis.AutoConsole; interface implementation uses Velthuis.Console, // as described in the link above Winapi.Windows; function GetConsoleWindow: HWnd; stdcall; external 'kernel32.dll' name 'GetConsoleWindow'; function StartedFromConsole: Boolean; var ConsoleHWnd: THandle; ProcessId: DWORD; begin ConsoleHwnd := GetConsoleWindow; if ConsoleHWnd <> 0 then begin GetWindowThreadProcessId(ConsoleHWnd, ProcessId); Result := GetCurrentProcessId <> ProcessId; end else Result := False; end; procedure Pause; begin if IsConsole and not StartedFromConsole then begin Write('Press any key... '); ReadKey; end; end; initialization finalization Pause; end.
Update
I removed the reliance on the Velthuis.Console
unit. I added this piece, a simplified version of ReadKey
, which does not try to translate the key, making things a lot simpler:
procedure WaitForInput; var InputRec: TInputRecord; NumRead: Cardinal; OldKeyMode: DWORD; StdIn: THandle; begin StdIn := GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(StdIn, OldKeyMode); SetConsoleMode(StdIn, 0); repeat ReadConsoleInput(StdIn, InputRec, 1, NumRead); until (InputRec.EventType and KEY_EVENT <> 0) and InputRec.Event.KeyEvent.bKeyDown; SetConsoleMode(StdIn, OldKeyMode); end;
and changed the Pause
procedure a little:
procedure Pause; begin if IsConsole and not StartedFromConsole then begin Write('Press any key... '); WaitForInput; end; end;
well great job but. when many line show on the screen
ReplyDeleteThe screen lucks SCROLL. one can not go UP.
It will be nice to have a scroll too.
I am talking about the black Screen.
ReplyDeleteEscape key should take me out all together
even in the midle of the process
and Not to the next funcion
To get out of a console application, you can generally press Ctrl+C, not Esc. I removed the reliance on Velthuis.Console, which probably prevented you from scrolling. Things should work now.
ReplyDelete