The Delphi console application in question tries to utilize WinExec
to call Cygwin
's echo.exe
to output with color. Cygwin
is installed under C:\cygwin
. Its echo.exe
is C:\cygwin\bin\echo.exe
.
The reason to choose WinExec
over ShellExecute
is ShellExecute
will instantiate a new shell and echo the texts in that new shell.
The same behavior occurs when I invoke the console application within Windows' CMD shell.
As shown in the picture, the shell does not return to the prompt. I though WinExec does not finish or need another carriage.
program TestConsole;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
begin
WinExec('C:\cygwin\bin\echo.exe -e "\e[1;34mColored text.\e[0m"', SW_NORMAL);
end.
As shown in the picture, it is clear that WinExec already finish. But the shell still does not return to the prompt. I am confused about the reason. Could you help to comment? Any comment will be appreciated!!
program TestConsole;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
var
I: Integer;
begin
I := WinExec('C:\cygwin\bin\echo.exe -e "\e[1;34mColored text.\e[0m"', SW_NORMAL);
Writeln(IntToStr(I));
end.
In fact that shell has already returned to the prompt before your colored text ever gets printed. You know that by the fact that the shell prints a prompt. It wouldn't do that if it were still waiting for your program to finish running. Prove it to yourself by typing more commands at the prompt and observing that the shell runs them for you.
When you call WinExec
, you run the program asynchronously. That function doesn't wait for the echo
command to complete before it returns control to your program, and your program doesn't wait for the command to complete, either. Since the shell is only waiting for your program, and not any other programs that your program might have started, the shell prints its prompt as soon as your program terminates, which evidently occurs before the echo
command manages to print any output.
To fix this, you need to wait for the echo
command to terminate before you allow your own program to terminate. WinExec
doesn't all you to do that, though. That's just as well since it's been deprecated for about 17 years. Instead, use CreateProcess
. It will return a process handle, and you can pass that process handle to WaitForSingleObject
, which will block until the process terminates.