0

[Delphi XE4, Win 7]

At startup my GUI application spawns a visible 'cmd.exe' console window (using 'CreateProcess'). The console is up as long as the GUI app is running.

The console window expects input from the keyboard, but the input/command has to come from the GUI app (the GUI sends the command to be executed to the console, and the user can watch what's happening in the console window - so no console output redirection). I tried to use an anon pipe for sending commands to the console (stdin redirected), but it doesn't work. Code snippet :

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    Fsa: SECURITY_ATTRIBUTES;
    Fsi: STARTUPINFO;
    Fpi: PROCESS_INFORMATION;
    Fpipe_stdin_read : THandle;
    Fpipe_stdin_write: THandle;
    procedure CreateProcessCmd;
  end;

...

procedure TForm1.Button1Click(Sender: TObject);
begin
  // write command to pipe
  WriteFile(Fpipe_stdin_write, ...);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CreateProcessCmd;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  CloseHandle(Fpi.hProcess);
  CloseHandle(Fpi.hThread);
  CloseHandle(Fpipe_stdin_read);
  CloseHandle(Fpipe_stdin_write);
  inherited;
end;

procedure TForm1.CreateProcessCmd;
begin
  // init security structure
  Fsa.nLength := SizeOf(SECURITY_ATTRIBUTES);
  Fsa.bInheritHandle := True;
  Fsa.lpSecurityDescriptor := nil;
  // create a pipe for the child process's stdin
  if not CreatePipe(Fpipe_stdin_read, Fpipe_stdin_write, @Fsa, 0) then
  begin
    ...;
    Exit;
  end;
  // init startup info structure
  FillChar(Fsi, SizeOf(STARTUPINFO), #0);
  Fsi.cb := SizeOf(STARTUPINFO);
  Fsi.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW or STARTF_USEPOSITION;
  Fsi.hStdError := GetStdHandle(STD_ERROR_HANDLE);  // don't redirect std err
  Fsi.hStdOutput := GetStdHandle(STD_OUTPUT_HANDLE);  // don't redirect std out
  Fsi.hStdInput := Fpipe_stdin_read;
  Fsi.wShowWindow := SW_SHOW;
  Fsi.dwX := 1000;
  Fsi.dwY := 50;
  // init process info structure
  FillChar(Fpi, SizeOf(PROCESS_INFORMATION), #0);
  // create process with new console
  if not CreateProcess(nil,PChar(GetEnvironmentVariable('COMSPEC')),nil,nil,True,CREATE_NEW_CONSOLE,nil,nil,Fsi,Fpi) then
    ...;
end;

The cmd console window will be created but immediately closed after that. Without the redirecting code parts the console is up and running (expecting keyboard input, of course).

What am I doing wrong? Any insight / working code is really appreciated.

Note: A similiar question has already been asked (How to send command to console application from GUI application) but that one works with capturing/redirecting the console output - in my case this is not an option, the output generated after sending a command has to be displayed in the console window.

Community
  • 1
  • 1
uliF
  • 31
  • 2
  • 1
    Why is it not an option - as in, why do you have to have the console window? Why not redirect and allow typing from inside your GUI app too, as well as output showing there? – David May 02 '15 at 17:31
  • @David M: The program that is to be executed in the console doesn't flush the output buffer immediately. So the output cannot be displayed in real time if it's redirected to the GUI app. Don't know why, but In the console window output is in real time. – uliF May 03 '15 at 06:43

1 Answers1

0

I don't think it's possible to redirect only some of the standard handles. When you set Fsi.hStdError := GetStdHandle(STD_ERROR_HANDLE), you're assigning that field the stderr handle of your process. Since you're running a GUI process, that handle doesn't exist. The created process inherits that bogus handle, tries to write to it, fails, and terminates.

You could try calling AllocConsole first. That will give your process standard console I/O handles that the new process can inherit.

Otherwise, it looks like you're going to have to capture the output yourself and display it somewhere in your program.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • @ Rob Kennedy: I got the impression that it is possible by the MSN article *How to spawn console processes with redirected standard handles* (http://support.microsoft.com/en-us/kb/190351): "... If the parent process only wishes to redirect one or two standard handles, specifying GetStdHandle() for the specific handles causes the child to create the standard handle as it normally would without redirection. ..." I'm pretty new to pipes/redirecting, so maybe I'm completely misunderstanding this. – uliF May 03 '15 at 06:59
  • I agree with your interpretation of that article, but it's inconclusive because the article's demo program is a console program. You could investigate further by writing your own console program to stand in for the child program. Run that instead of cmd.exe, and use the debugger to investigate what output handles it has and how it behaves when using them. – Rob Kennedy May 03 '15 at 14:41