我有一个控制台应用程序,我从GUI应用程序启动.控制台应用程序获取文件名的参数以进行解析和处理.目前我能够捕获其输出并将其显示在GUI应用程序中,但我希望能够向其发送命令以便控制甚至停止其执行.
如何向控制台应用程序发送命令或字符串或任何内容,最好使用我打开的管道来读取其输出?
const
CReadBuffer = 2400;
var
saSecurity: TSecurityAttributes;
hRead: THandle;
hWrite: THandle;
suiStartup: TStartupInfo;
piProcess: TProcessInformation;
pBuffer: array[0..CReadBuffer] of AnsiChar;
dRead: DWord;
dRunning: DWord;
dWritten: DWord;
Command: String;
BytesLeft: Integer;
BytesAvail: Integer;
begin
saSecurity.nLength := SizeOf(TSecurityAttributes);
saSecurity.bInheritHandle := True;
saSecurity.lpSecurityDescriptor := nil;
if CreatePipe(hRead, hWrite, @saSecurity, 0) then
begin
FillChar(suiStartup, SizeOf(TStartupInfo), #0);
suiStartup.cb := SizeOf(TStartupInfo);
suiStartup.hStdInput := hRead;
suiStartup.hStdOutput := hWrite;
suiStartup.hStdError := hWrite;
suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
suiStartup.wShowWindow := SW_HIDE;
Command := 'messageparser.exe c:\messagefile.msg';
UniqueString(Command);
if CreateProcess(nil, PChar(Command), @saSecurity,
@saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess) then
begin
repeat
dRunning := WaitForSingleObject(piProcess.hProcess, 100);
Application.ProcessMessages;
repeat
dRead := 0;
if not PeekNamedPipe(hread, @pbuffer, CReadBuffer, @dRead, @BytesAvail, @BytesLeft) then
RaiseLastOSError;
if dRead <> 0 then
begin
ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil);
pBuffer[dRead] := #0;
OemToCharA(pBuffer, pBuffer);
// do something with the data
// if a condition is present then do the following:
// WriteFile(hWrite, some_command, size_of_buffer, DWritten, nil);
end;
until (dRead < CReadBuffer);
until (dRunning <> WAIT_TIMEOUT);
CloseHandle(piProcess.hProcess);
CloseHandle(piProcess.hThread);
end;
CloseHandle(hRead);
CloseHandle(hWrite);
end;
Run Code Online (Sandbox Code Playgroud)
然后在控制台端,有一个线程在等待输入.这是execute方法:
while not Terminated do
begin
ReadLn(Command);
// process command
Sleep(10);
end;
Run Code Online (Sandbox Code Playgroud)
这对我来说是新的,所以如果有关于如何正确的提示,我欢迎他们:).但是每当我发送一个命令时,它都会从我在ReadPipe中读取的pBuffer中看到,而不是命令是什么.
希望这可以帮助.
-
找到了一个基于Nat的技巧的解决方案.
您需要两个管道,一个用于将输出发送给您的进程(stdout),另一个用于将输入发送到进程(stdin).
从您的代码中,看起来您将同一管道的两端放入TStartupInfo记录中.所以你有效地让这个过程与自己对话.:-)
所以,你需要调用CreatePipe()两次,创建两个管道,一个用于stdin,一个用于stdout(和stderr).
然后,把的阅读手柄stdin中suiStartup.hStdInput和的写作手柄stdout在suiStartup.hStdOutput
要将数据发送到进程,请写入stdin管道的写入句柄.要读取进程的输出,请读取stdout管道的读取句柄.
编辑:(再次)
对于本页描述的所有重复句柄以及可继承和不可继承的内容(特别是在代码示例中),您需要确保发送给进程的句柄是可继承的(如您所做).
您还应该确保父进程使用的管道句柄不可继承.但你不具备做这个...我已经与以前不这样做逃掉.
您可以通过调用做到这一点DuplicateHandle()的手柄,指定他们是不可继承和关闭旧的把手,或调用SetHandleInformation()与标志指定0(如讨论这里).
我已经有一段时间了,但是我很确定这是因为句柄的引用计数与调用进程相关联,而不是子进程.这可以防止在您仍在使用它时关闭句柄(例如,调用进程可能会关闭'stdin').确保你关闭手柄,否则你将最终泄漏手柄.
HTH.
N - [