- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要执行一个“DOS”程序(控制台应用程序)并动态检索其输出(能够随时结束 DOS 程序也很好,因为 DOS 程序可能会运行数小时)。
我有这个这个功能,但它有时(很少)卡住。
我需要一个新功能或修复以下功能。
procedure ExecuteAndGetOutDyn(CONST ACommand, AParameters: String; AMemo: TMemo);
CONST
CReadBuffer = 128*KB; //original was 2400bytes
VAR
SecurityAttrib: TSecurityAttributes;
hRead: THandle;
hWrite: THandle;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
pBuffer: array[0..CReadBuffer] of AnsiChar;
dRead: DWord;
dRunning: DWord;
WasOK: Boolean;
begin
SecurityAttrib.nLength := SizeOf(TSecurityAttributes);
SecurityAttrib.bInheritHandle := True;
SecurityAttrib.lpSecurityDescriptor := nil;
if CreatePipe(hRead, hWrite, @SecurityAttrib, 0) then
begin
FillChar(StartupInfo, SizeOf(TStartupInfo), #0);
StartupInfo.cb := SizeOf(TStartupInfo);
StartupInfo.hStdInput := hRead;
StartupInfo.hStdOutput := hWrite;
StartupInfo.hStdError := hWrite;
StartupInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow:= SW_HIDE;
if CreateProcess(NIL, PChar(ACommand + ' ' + AParameters), @SecurityAttrib, @SecurityAttrib, True, NORMAL_PRIORITY_CLASS, NIL, NIL, StartupInfo, ProcessInfo) then
begin
REPEAT
dRunning:= WaitForSingleObject(ProcessInfo.hProcess, 100);
Application.ProcessMessages;
REPEAT
dRead := 0;
WasOK := Windows.ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, NIL);
if NOT WasOK then mesajerror('Cannot read console output.');
pBuffer[dRead] := #0;
OemToAnsi(pBuffer, (pBuffer));
AMemo.Lines.Add(String(pBuffer));
UNTIL (dRead < CReadBuffer) OR NOT WasOK;
UNTIL (dRunning <> WAIT_TIMEOUT) { OR Abort};
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
end;
CloseHandle(hRead);
CloseHandle(hWrite);
end;
end;
最佳答案
一个明显的问题是你的管道。您有一个管道,您安排子进程 stdout 写入一端,子进程 stdin 从另一端读取。那不好。为什么你希望进程从它自己的输出中读取它的输入?同时父进程从管道中读取。你有两个进程试图读取这个管道。我无法想象结局会很好。
你需要两个管道。一个用于 child 的标准输入。 parent 写入它, child 从中读取。另一个管道用于 child 的标准输出。 child 写, parent 读。
或者,如果您不希望子进程有任何标准输入,则创建一个管道,将写入端连接到子进程标准输出并让父进程从读取端读取。
另一个问题是,如果进程已经终止,并且您已经阅读了它的所有内容,那么调用 ReadFile
将无限期阻塞。在尝试从中读取之前,您需要确保管道包含某些内容。我会使用 GetFileSizeEx
为了那个原因。
就我个人而言,我倾向于在一个线程中完成所有这些操作,以避免调用 ProcessMessages
。 .
您还应该始终检查 API 返回值是否有错误。对 WaitForSingleObject
的调用没有这样做。和 ReadFile
.
我提出以下几点建议:
program DynamicStdOutCapture;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Math,
Winapi.Windows;
function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall;
external kernel32;
procedure Execute(const Command: string; const Parameters: string;
const Timeout: DWORD; const Output: TProc<string>);
const
InheritHandleSecurityAttributes: TSecurityAttributes =
(nLength: SizeOf(TSecurityAttributes); bInheritHandle: True);
var
hReadStdout, hWriteStdout: THandle;
si: TStartupInfo;
pi: TProcessInformation;
WaitRes, BytesRead: DWORD;
FileSize: Int64;
AnsiBuffer: array [0 .. 1024 - 1] of AnsiChar;
begin
Win32Check(CreatePipe(hReadStdout, hWriteStdout,
@InheritHandleSecurityAttributes, 0));
try
si := Default (TStartupInfo);
si.cb := SizeOf(TStartupInfo);
si.dwFlags := STARTF_USESTDHANDLES;
si.hStdOutput := hWriteStdout;
si.hStdError := hWriteStdout;
Win32Check(CreateProcess(nil, PChar(Command + ' ' + Parameters), nil, nil,
True, CREATE_NO_WINDOW, nil, nil, si, pi));
try
while True do
begin
WaitRes := WaitForSingleObject(pi.hProcess, Timeout);
Win32Check(WaitRes <> WAIT_FAILED);
while True do
begin
Win32Check(GetFileSizeEx(hReadStdout, FileSize));
if FileSize = 0 then
begin
break;
end;
Win32Check(ReadFile(hReadStdout, AnsiBuffer, SizeOf(AnsiBuffer) - 1,
BytesRead, nil));
if BytesRead = 0 then
begin
break;
end;
AnsiBuffer[BytesRead] := #0;
OemToAnsi(AnsiBuffer, AnsiBuffer);
if Assigned(Output) then
begin
Output(string(AnsiBuffer));
end;
end;
if WaitRes = WAIT_OBJECT_0 then
begin
break;
end;
end;
finally
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
end;
finally
CloseHandle(hReadStdout);
CloseHandle(hWriteStdout);
end;
end;
procedure DoOutput(Text: string);
begin
Write(Text);
end;
procedure Main;
begin
Execute('ping', 'stackoverflow.com -t', 100, DoOutput);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
关于delphi - 执行DOS程序并动态获取输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25723807/
在MS-DOS中,如果输入dir *.pdf,我将在目录中获取所有PDF文件。除了PDF文件,有什么方法可以获取所有内容?像dir !*.pdf一样? 谢谢! 最佳答案 我认为findstr有一个/v
我们如何在 DOS 中实现递归目录列表? 我正在 DOS 中寻找一个命令或脚本,它可以为我提供类似于 Unix 中的 ls -R 命令的递归目录列表。 最佳答案 您可以使用: dir /s 如果您需要
当我使用 ren "C:\folder\file""C:\folder\file.txt" 出现错误“命令的语法不正确。” 但是如果我 CD 到文件夹并使用 ren "file""file.txt"
比如,我能不能做 回显 3 + 5 并得到 8? 是否可以使用日期进行计算? 最佳答案 您可以使用set/a 来计算数学表达式: set /a x=3+5 echo %x% 编辑:这是一行: @for
我正在寻找一个 DOS 脚本来删除根目录中的所有文件和子目录,但根目录中的一组批处理文件 (*.bat) 除外。任何 DOS 运动员都知道一种简单的方法来做到这一点? 更新 谢谢大家的帮助。这就是我现
如何在目录及其子目录中搜索文件并以简洁的格式显示文件名及其创建时间。 我尝试了dir sam.csv/b/s/a-d 但是不起作用。 输出应该如下所示 c:\Data\Sam.txt 10/10/20
我有一个在并发 DOS 3.1 上运行的软件,我使用 QEMU 5.1 对其进行模拟。 在此程序中,有多个打印数据的选项。问题是到达我的主机的数据与发送的数据不对应。 启动qemu的命令: qemu-
我有一个在并发 DOS 3.1 上运行的软件,我使用 QEMU 5.1 对其进行模拟。 在此程序中,有多个打印数据的选项。问题是到达我的主机的数据与发送的数据不对应。 启动qemu的命令: qemu-
在 C 中,我如何写入特定的内存位置,例如视频内存 b800,在 DOS 下(真正的 DOS,MS DOS 6.22) 我知道 C 没有内置任何东西可以做到这一点,但可能有一些特定于平台的东西,例如可
我有一个大约 15 年前购买的非常古老的应用程序,它由 5 个 .exe 文件组成,用于存储患者的个人资料和信息。问题是该应用程序被编程为在特定计算机上运行。 由于我对破解知之甚少,我尝试使用 win
这个问题已经有答案了: How to redirect stderr to null in cmd.exe (1 个回答) 已关闭 4 年前。 我想抑制在 DOS 下运行的脚本的输出,类似于 *nix
我想从 MATLAB 在 dos 中执行一个批处理文件,并立即将控制权返回给 MATLAB。但是,我想在不打开 dos 窗口的情况下执行此操作(或者,至少,让 dos 窗口在最后消失)。 如果我这样格
最初... 我在 10 年前(大学)开始用 C 编程。我使用的 IDE 是 Turbo C++ IDE。 我所有的 c 程序都是 16 位的。 内存模型:巨大。 图形:4 位(16 色)。 图形驱动:
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 11 年前关闭。 Improve this
我需要一个批处理文件中的脚本,当我运行它时,它会将我昨天的日期放入一个变量中。包括 3 月 1 日等条件(根据年份可能是 2 月 28 日或 29 日) 最佳答案 假设您的意思是 ms-dos 批处理
我有一个可以做几件事的批处理文件。如果其中一个失败,我想退出整个程序。例如: @echo off type foo.txt 2>> error.txt >> success.txt mkdir bob
我正在尝试编写一个批处理脚本,将多个 css 文件合并到一个文件中。到目前为止,我已经想出了这个...... # Set start folders & files set fn1=filename.
我有不同的文件夹,例如:a、b、c 等,每个文件夹都有不同的文件,例如:x、y、z 等。 文件 x,y,z 位于每个文件夹中。有没有办法使用单个命令从不同文件夹复制每个文件?我希望结果是所有文件夹中的
我需要获取命令行输出的第一行而不是所有行,例如,如果我给 C:\Temp> dir 我只需要显示第一行, 11/15/2012 06:58 PM
如何使用 dos 批处理文件命令将日期设置为当前日期。 最佳答案 如果您需要在批处理文件中使用当前日期,则变量 %date% 具有当前日期: echo %date% 23/02/2010 它使用您计算
我是一名优秀的程序员,十分优秀!