我有一个用 Delphi XE2 编写的 VCL 应用程序,它需要执行一个命令行程序(也是用 Delphi XE2 编写的)并获取它输出的文本。我目前正在使用以下代码,该代码基于此处找到的代码:Getting output from a shell/dos app into a Delphi app
function GetDosOutput(ACommandLine : string; AWorkingDirectory : string): string;
var
SecurityAttributes : TSecurityAttributes;
StartupInfo : TStartupInfo;
ProcessInformation: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of AnsiChar;
BytesRead: Cardinal;
Handle: Boolean;
begin
Result := '';
SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
SecurityAttributes.bInheritHandle := True;
SecurityAttributes.lpSecurityDescriptor := nil;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SecurityAttributes, 0);
try
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb := SizeOf(TStartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartupInfo.wShowWindow := SW_HIDE;
StartupInfo.hStdInput := StdOutPipeRead;
StartupInfo.hStdOutput := StdOutPipeWrite;
StartupInfo.hStdError := StdOutPipeWrite;
FillChar(ProcessInformation, SizeOf(ProcessInformation), 0);
Handle := CreateProcess(
nil,
PChar(ACommandLine),
nil,
nil,
True,
0,
nil,
PChar(AWorkingDirectory),
StartupInfo,
ProcessInformation
);
CloseHandle(StdOutPipeWrite);
if Handle then
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Result := Result + Buffer;
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
finally
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
end;
finally
CloseHandle(StdOutPipeRead);
end;
end;
这适用于大多数 Windows 版本。不幸的是,最近我们注意到它不能在 Windows XP 上运行。对 WaitForSingleObject 的调用永远不会返回。我尝试用较小的值(例如 15000)替换第二个参数 INFINITE,但这似乎没有任何区别。在任务管理器中我可以看到,在调用 GetDosOutput 之后,命令行程序实际上正在运行。如果我结束 VCL 应用程序,命令行程序 then 似乎会成功完成其工作(事实证明它输出了我期望的文件)。我还注意到,如果我从 StartupInfo.dwFlags 中删除 STARTF_USESTDHANDLES,命令行程序将正常运行并且 WaitForSingleObject 会立即返回;但是我显然无法获得程序返回的文本。
有人建议我如何在 Windows XP 上运行它吗?
最佳答案
freepascal 中有一个非常有用的单元,称为“进程”,它就是这样做的,并且已经完成移植它到 Delphi 的工作,以便您可以捕获Delphi 中命令的输出,使用一个简单的单行代码:
运行命令()
或者您可以通过自己创建一个 TProcess 对象(RunCommand 只是包装)来捕获具有更多高级功能的命令的输出。
项目在这里:
- https://github.com/z505/TProcess-Delphi
- 一个简单的演示:https://github.com/z505/TProcess-Delphi/tree/master/demo-simple
如何捕获命令的输出,即“dir”(列出目录内容,著名的 MS DOS 命令)到字符串中,然后将其添加到备忘录中:
uses
dprocess;
// ...
var
output: ansistring;
begin
RunCommand('cmd', ['/c', 'dir'], output, [poNoConsole]);
memo1.Lines.Add(output);
end;
关于delphi - 从 Windows XP 上的 Delphi 应用程序中的命令行程序获取输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19019714/