Search code examples
delphishellconsolecygwinwindows-shell

Why the CMD/Cygwin shell does not return after WinExec?


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.

First attempt

picture of the first attempt

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.

Second attempt

picture of the second attempt

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.

Solution

  • 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.