[Delphi XE4, Win 7]
[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.
启动时,我的GUI应用程序会生成一个可见的“cmd.exe”控制台窗口(使用“CreateProcess”)。只要GUI应用程序正在运行,控制台就会启动。
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 :
控制台窗口需要来自键盘的输入,但输入/命令必须来自GUI应用程序(GUI将要执行的命令发送到控制台,用户可以查看控制台窗口中发生的事情 - 因此没有控制台输出重定向)。我试图使用anon管道向控制台发送命令(stdin重定向),但它不起作用。代码段:
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).
将创建cmd控制台窗口,但在此之后立即关闭。如果没有重定向代码部分,控制台就会启动并运行(当然需要键盘输入)。
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.
注意:已经提出了一个类似的问题(如何从GUI应用程序向控制台应用程序发送命令)但是一个用于捕获/重定向控制台输出 - 在我的情况下这不是一个选项,发送命令后生成的输出显示在控制台窗口中。
1 个解决方案
#1
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.
我认为不可能只重定向一些标准句柄。当您设置Fsi.hStdError:= GetStdHandle(STD_ERROR_HANDLE)时,您将为该字段分配进程的stderr句柄。由于您正在运行GUI进程,因此该句柄不存在。创建的进程继承该伪造句柄,尝试写入它,失败并终止。
You could try calling AllocConsole
first. That will give your process standard console I/O handles that the new process can inherit.
您可以先尝试调用AllocConsole。这将为您的进程提供新进程可以继承的标准控制台I / O句柄。
Otherwise, it looks like you're going to have to capture the output yourself and display it somewhere in your program.
否则,您似乎必须自己捕获输出并将其显示在程序中的某个位置。
#1
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.
我认为不可能只重定向一些标准句柄。当您设置Fsi.hStdError:= GetStdHandle(STD_ERROR_HANDLE)时,您将为该字段分配进程的stderr句柄。由于您正在运行GUI进程,因此该句柄不存在。创建的进程继承该伪造句柄,尝试写入它,失败并终止。
You could try calling AllocConsole
first. That will give your process standard console I/O handles that the new process can inherit.
您可以先尝试调用AllocConsole。这将为您的进程提供新进程可以继承的标准控制台I / O句柄。
Otherwise, it looks like you're going to have to capture the output yourself and display it somewhere in your program.
否则,您似乎必须自己捕获输出并将其显示在程序中的某个位置。