从Windows XP的Delphi应用程序中的命令行程序获取输出 [英] Getting output from a command-line program in a Delphi application on Windows XP
问题描述
我有用Delphi XE2编写的VCL应用程序,该应用程序需要执行命令行程序(也用Delphi XE2编写),并获取其输出的文本。我当前正在使用以下代码,该代码基于此处的代码:将shell / dos应用程序中的输出输出到Delphi应用程序中
I have VCL application written in Delphi XE2 that needs to execute a command-line program (also written in Delphi XE2) and obtain the text output by it. I am currently using the following code, which is based on that found here: 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会立即返回。但是,我显然无法获得程序返回的文本。
This works fine on most versions of Windows. Unfortunately it has recently come to our attention that it does not work on Windows XP. The call to WaitForSingleObject simply never returns. I tried replacing the second parameter INFINITE with a smaller value (e.g. 15000) but that doesnt't seem to make any difference. In Task Manager I can see that, after calling GetDosOutput, the command-line program is actually running. If I end the VCL application, the command-line program then seems to complete its work successfully (as evidenced by the fact that it outputs the files I was expecting it to). I've also noticed that if I remove STARTF_USESTDHANDLES from StartupInfo.dwFlags, the command-line program runs normally and WaitForSingleObject returns promptly; however I am then obviously unable to obtain the text returned by the program.
有人对我如何在Windows XP上运行它提出建议吗?
Does anybody have a suggestion as to how I can get this working on Windows XP?
推荐答案
在freepascal中有一个非常有用的单元称为 process,它可以完成此工作,并且已经完成了端口它到Delphi ,因此您可以使用一个简单的划线器在 Delphi 中捕获命令的输出:
There is a really useful unit in freepascal called "process", which does just that, and, work has been done to port it to Delphi so you can capture the output of a command in Delphi using a simple one liner:
RunCommand()
或者您可以通过创建更高级的功能来捕获命令的输出
Or you can capture the output of the command with more advanced features by creating a TProcess object yourself (which RunCommand just wraps).
项目在这里:
- https://github.com/z505/TProcess-Delphi
- 一个简单的演示: https://github.com/z505/TProcess-Delphi/tree/master/demo-simple
- https://github.com/z505/TProcess-Delphi
- A simple demo: https://github.com/z505/TProcess-Delphi/tree/master/demo-simple
如何捕获命令的输出,即 dir(列表目录内容,著名的MS DOS命令)到字符串中,然后将其添加到备注中:
How to capture the output of a command, i.e. "dir" (list directory contents, famous MS DOS command) into a string then add it to a memo:
uses
dprocess;
// ...
var
output: ansistring;
begin
RunCommand('cmd', ['/c', 'dir'], output, [poNoConsole]);
memo1.Lines.Add(output);
end;
这篇关于从Windows XP的Delphi应用程序中的命令行程序获取输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!