【发布时间】:2016-07-22 17:01:46
【问题描述】:
我正在使用管道在我的程序中获取 cmd.exe 输出。有时,我注意到如果 cmd.exe 要求用户输入(我创建了隐藏的 cmd 窗口),程序就会挂起,因为没有人会将输入放在窗口中,而 cmd 只会留下来。所以我实现了 WaitForSingleObject 以避免在 cmd 要求用户输入或只是出于其他原因而挂起的情况下挂起。当我尝试执行 powershell 命令时出现问题,因为它看起来对 WaitForSingleObject 没有响应,而且我总是达到超时。功能是:
function GetDosOutput(const Exe, Param: string): string;
const
InheritHandleSecurityAttributes: TSecurityAttributes =
(nLength: SizeOf(TSecurityAttributes); bInheritHandle: True);
var
hReadStdout, hWriteStdout: THandle;
si: TStartupInfo;
pi: TProcessInformation;
WaitTimeout, BytesRead: DWord;
lReadFile: boolean;
Buffer: array[0..255] of AnsiChar;
begin
Result:= '';
if CreatePipe(hReadStdout, hWriteStdout, @InheritHandleSecurityAttributes, 0) then
begin
try
si:= Default(TStartupInfo);
si.cb:= SizeOf(TStartupInfo);
si.dwFlags:= STARTF_USESTDHANDLES;
si.hStdOutput:= hWriteStdout;
si.hStdError:= hWriteStdout;
if CreateProcess(Nil, PChar(Exe + ' ' + Param), Nil, Nil, True, CREATE_NO_WINDOW,
Nil, PChar(ExtractFilePath(ParamStr(0))), si, pi) then
begin
CloseHandle(hWriteStdout);
while True do
begin
try
WaitTimeout:= WaitForSingleObject(pi.hProcess, 20000);
if WaitTimeout = WAIT_TIMEOUT then
begin
Result:= 'No result available';
break;
end
else
begin
repeat
lReadFile:= ReadFile(hReadStdout, Buffer, SizeOf(Buffer) - 1, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead]:= #0;
OemToAnsi(Buffer, Buffer);
Result:= Result + String(Buffer);
end;
until not (lReadFile) or (BytesRead = 0);
end;
if WaitTimeout = WAIT_OBJECT_0 then
break;
finally
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
end;
end;
end;
finally
CloseHandle(hReadStdout);
end;
end;
end;
如果我调用这个函数传递:
cmd.exe /C 目录 c:\
一切顺利。但如果我打电话使用:
powershell dir c:\ 或 cmd.exe /C powershell dir c:\
WaitForSingleObject 达到超时,没有任何反应。对这个有帮助吗?
【问题讨论】:
-
Rob 的回答应该是准确的阻止原因。不过,我想不出任何方法来等待管道。可能你需要改变你的设计。也许在一个线程中阅读。或者也许在一个线程中等待。或者制作一个等待用户输入挂起的 mcve,以便我们重现问题。
标签: delphi