如何得到一个控制台程序的输出内容?(200分)

R

roc

Unregistered / Unconfirmed
GUEST, unregistred user!
如有一控制台程序ccc.exe
运行时要带参数几个
ccc.exe -a -b -c c:/a.txt d:/a.txt
在控制台输出内容
xxxxxx
xxxxxxx
xxxxxxx
如何在delphi程序中得输出内容。
同时能不能控制程序调用ccc.exe时中断运行,直到ccc.exe结束才恢复运行,取结果。
 

interface

uses
Controls, Windows, SysUtils, Forms;

function GetDosOutput(const CommandLine:string): string;

implementation

function GetDosOutput(const CommandLine:string): string;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of Char;
BytesRead: Cardinal;
WorkDir, Line: String;
begin
Application.ProcessMessages;
with SA do
begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
// create pipe for standard output redirection
CreatePipe(StdOutPipeRead, // read handle
StdOutPipeWrite, // write handle
@SA, // security attributes
0 // number of bytes reserved for pipe - 0
default
);
try
// Make child process use StdOutPipeWrite as standard out,
// and make sure it does not show on screen.
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect std
input
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;

// launch the command line compiler
WorkDir := ExtractFilePath(CommandLine);
WasOK := CreateProcess(nil, PChar(CommandLine), nil, nil, True, 0, nil,
PChar(WorkDir), SI, PI);

// Now that the handle has been inherited, close write to be safe.
// We don't want to read or write to it accidentally.
CloseHandle(StdOutPipeWrite);
// if process could be created then handle its output
if not WasOK then
raise Exception.Create('Could not execute command line!')
else
try
// get all output until dos app finishes
Line := '';
repeat
// read block of characters (might contain carriage returns and
line feeds)
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);

// has anything been read?
if BytesRead > 0 then
begin
// finish buffer to PChar
Buffer[BytesRead] := #0;
// combine the buffer with the rest of the last run
Line := Line + Buffer;
end;
until not WasOK or (BytesRead = 0);
// wait for console app to finish (should be already at this point)
WaitForSingleObject(PI.hProcess, INFINITE);
finally
// Close all remaining handles
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
finally
result:=Line;
CloseHandle(StdOutPipeRead);
end;
end;


end.
 
不行,运行报:Could not execute command line!
可我的command在dos窗口下可用。
 
最简单的,你可以用
winexec('ccc.exe -a -b -c c:/a.txt d:/a.txt >c:/result.txt',sw_hide);
输出内容应该在result.txt里面,我用控制台程序输出结果这样都没问题。
这里有一段跟楼上类似,我用过好使。
procedure RunDosInMemo(DosApp:String;AMemo:TMemo);
const
ReadBuffer = 2400;
var
Security : TSecurityAttributes;
ReadPipe,WritePipe : THandle;
start : TStartUpInfo;
ProcessInfo : TProcessInformation;
Buffer : Pchar;
BytesRead : DWord;
Apprunning : DWord;
begin
With Security do begin
nlength := SizeOf(TSecurityAttributes);
binherithandle := true;
lpsecuritydescriptor := nil;
end;
if Createpipe (ReadPipe, WritePipe,
@Security, 0) then begin
Buffer := AllocMem(ReadBuffer + 1);
FillChar(Start,Sizeof(Start),#0);
start.cb := SizeOf(start);
start.hStdOutput := WritePipe;
start.hStdInput := ReadPipe;
start.dwFlags := STARTF_USESTDHANDLES +
STARTF_USESHOWWINDOW;
start.wShowWindow := SW_HIDE;
if CreateProcess(nil,
PChar(DosApp),
@Security,
@Security,
true,
NORMAL_PRIORITY_CLASS,
nil,
nil,
start,
ProcessInfo)
then
begin
repeat
Apprunning := WaitForSingleObject
(ProcessInfo.hProcess,100);
Application.ProcessMessages;
until (Apprunning <> WAIT_TIMEOUT);
Repeat
BytesRead := 0;
ReadFile(ReadPipe,Buffer[0],
ReadBuffer,BytesRead,nil);
Buffer[BytesRead]:= #0;
OemToAnsi(Buffer,Buffer);
AMemo.Text := AMemo.text + String(Buffer);
until (BytesRead < ReadBuffer);
end;
FreeMem(Buffer);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ReadPipe);
CloseHandle(WritePipe);
end;
end;

等程序运行结束你可以参考这里。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1198693
 
老大,你试过没有
winexec('ccc.exe -a -b -c c:/a.txt d:/a.txt >c:/result.txt',sw_hide);
根本不能重定向,没用result.txt生成,如果在dos窗口可以重定向。
 
To bubble
这段代码为什么在dos命令没有返回值的情况下(如命令正常结束),就会令程序当掉?
。。。。。。
until (Apprunning <> WAIT_TIMEOUT);
Repeat
BytesRead := 0;
ReadFile(ReadPipe,Buffer[0],
ReadBuffer,BytesRead,nil); //就是这句话,如是Dos命令能正常运行结束,运行这句话程序就当机
如是dos命令出错,程序不但能很好的运行,dos命令的出错信息也能输出,这是什么原因?
Buffer[BytesRead]:= #0;
OemToAnsi(Buffer,Buffer);
AMemo.Text := AMemo.text + String(Buffer);
until (BytesRead < ReadBuffer);
。。。。
大哥,这是什么原因?
 
对不起,我从来没出现过你说的情况,帮不了你.
那么你可以做个判断,如果没有返回值
或者作为一个线程延时超过timeout就终止。
 
我调试了很长时间,一个变量一个变量在两种情况下比较结果是:
如果DOS命令有错误的话,则BytesRead=3,ReadFile(...)这个Function就能正常执行,
如果DOS命令是正常结束,则BytesRead=5,则ReadFile(...)这个Function就不能正常执行。
这个BytesRead的值是做什么(我查了API,但具体做什么),为何会不一样。现在我的处理方式
是:
.....
until (Apprunning <> WAIT_TIMEOUT);
Repeat
if (BytesRead = 3) then //加上的判断。DOS命令有错误返回。
begin
BytesRead := 0;
ReadFile(ReadPipe,Buffer[0],
ReadBuffer,BytesRead,nil);
Buffer[BytesRead]:= #0;
OemToAnsi(Buffer,Buffer);
AMemo.Text := AMemo.text + String(Buffer);
end
else //BytesRead = 5,Dos命令正常执行。
{do other and exit}
until (BytesRead < ReadBuffer);
.....
这样勉强凑合着还能用,这是什么原因呢,大哥。?:)
 
顶部