超级问题:如何捕获dos窗口的输入输出流(200分)

  • 主题发起人 主题发起人 haoyi
  • 开始时间 开始时间
利用Win32API的CreateProcess函数可以重定向一个控制台程序的输出,
所以我们可以用一个PIPE管道来读取控制台输出,显示在Windows程序中。

一个不很完美的例子:
...
TForm1 = class(TForm)
...
Memo1 : TMemo; ;// 用来显示命令行结果
Button1: TButton; // 按下后执行命令
Edit1: TEdit; // 输入想要执行的命令
...

procedure TForm1.Button1Click(Sender: TObject);
var
; si: TStartupInfo;
; pi: TProcessInformation;
; rh,wh: THandle;
; Stream: TStream;
; Buffer: array[0..8192] of char;
; rc: DWord;
begin
; // 创建管道
; if CreatePipe(rh,wh,nil,8192) then
; begin
; ; FillChar(si,SizeOf(si),0);
; ; si.dwFlags:=STARTF_USESTDHANDLES; // 指定进程使用StdOupt重定位功能
; ; si.hStdOutput:=wh; // 指定进程的标准输出到管道的写端口
; ; // 创建进程
; ; if CreateProcess(nil,PChar(Edit1.Text),nil,nil,false,
; ; ; DETACHED_PROCESS,nil,nil,si,pi) then
; ; begin
; ; ; // 创建内存流
; ; ; Stream:=TMemoryStream.Create;
; ; ; repeat
; ; ; ; // 查询管道缓冲区内可读的字节数到rc
; ; ; ; if PeekNamedPipe(rh,nil,0,nil,@rc,nil) and (rc>0) then
; ; ; ; begin
; ; ; ; ; // 读管道缓冲区
; ; ; ; ; ReadFile(rh,Buffer,rc,rc,nil);
; ; ; ; ; // 写入内存流
; ; ; ; ; Stream.Write(Buffer,rc);
; ; ; ; end;
; ; ; // 当被调用进程结束且管道中无剩余数据时结束循环
; ; ; until (WaitForSingleObject(pi.hProcess,0)=WAIT_OBJECT_0) and (bs=0);
; ; ; // 读内存流到指定的显示Memo控件中
; ; ; Stream.Position:=0;
; ; ; Memo1.Lines.LoadFromStream(Stream);
; ; ; Stream.Free;
; ; end;
; ; // 关闭管道端口
; ; CloseHandle(rh);
; ; CloseHandle(wh);
; end;
end;
另外用PIPE的好处在于,子进程一边执行中,主进程可以同时获得子进程的输出而
不必等到子进程结束。当然本例中的情况并非如此。但是你只要改一改在ReadFile
后直接将Buffer里的内容加到Memo1的内容后面即可实现。
 
一个例子运行 'chkdsk.exe c:/' 并且 显示其输出结果到 Memo 中!

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;

调用实例:
RunDosInMemo('chkdsk.exe c:/',Memo1);
 
to YB_unique大侠!
谢谢上次您的帮忙,小第改了一下。下面是ping localhost结果保存到b.txt中,但那个localhost
参数还是没能从a.txt中读取。能提示一下吗?我再改改。再次感谢大侠的热心帮忙!
to haoyi,这里很多东西可以删除,你试试吧!
procedure TForm1.Button3Click(Sender: TObject);
var
startupinfo:tstartupinfo;
processinfo:tprocessinformation;
SecAtrrs:TSecurityAttributes;
hInputFile,hOutputFile,hAppThread,hAppProcess:THandle;
mok:boolean;
pcommandline:pchar;
oldcursor:tcursor;
pstr:pchar;
pstr2:pchar;
begin
oldcursor:=screen.Cursor;
screen.Cursor:=crHourGlass;
hinputfile:=0;
houtputfile:=0;
happthread:=0;
happprocess:=0;
if not fileexists('d:/delphi/practice/a.txt') then
hinputfile:=filecreate('d:/delphi/practice/a.txt')
else
hinputfile:=fileopen('d:/delphi/practice/a.txt',fmopenread);
if not fileexists('d:/delphi/practice/b.txt') then
begin
filecreate('d:/delphi/practice/b.txt');
houtputfile:=fileopen('d:/delphi/practice/b.txt',fmopenwrite);
end
else
begin
pstr:=pchar('d:/delphi/practice/b.txt');
pstr2:=pchar('d:/delphi/practice/a.txt');
FillChar(SecAtrrs, SizeOf(SecAtrrs), #0);
; ; SecAtrrs.nLength ; ; ; ; ; ; ;:= SizeOf(SecAtrrs);
; ; SecAtrrs.lpSecurityDescriptor := nil;
; ; SecAtrrs.bInheritHandle ; ; ; := TRUE;
hOutputFile := CreateFile(
; ; ; ;pstr, ; ; ; ; ; ; ; ; ; ; ; ; { pointer to name of the file }
; ; ; ;GENERIC_READ or GENERIC_WRITE, ; ; ; { access (read-write) mode }
; ; ; ;FILE_SHARE_READ or FILE_SHARE_WRITE, { share mode }
; ; ; ;@SecAtrrs, ; ; ; ; ; ; ; ; ; ; ; ; ; { pointer to security attributes }
; ; ; ;CREATE_ALWAYS, ; ; ; ; ; ; ; ; ; ; ; { how to create }
; ; ; ;FILE_ATTRIBUTE_NORMAL
; ; ; ;or FILE_FLAG_WRITE_THROUGH, ; ; ; ; ;{ file attributes }
; ; ; ;0 ); ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; { handle to file with attrs to copy }
; ; // filecr
;hinputfile:=CreateFile(
; ; ; ;pstr2, ; ; ; ; ; ; ; ; ; ; ; ; { pointer to name of the file }
; ; ; ;GENERIC_READ or GENERIC_WRITE, ; ; ; { access (read-write) mode }
; ; ; ;FILE_SHARE_READ or FILE_SHARE_WRITE, { share mode }
; ; ; ;@SecAtrrs, ; ; ; ; ; ; ; ; ; ; ; ; ; { pointer to security attributes }
; ; ; ;CREATE_ALWAYS, ; ; ; ; ; ; ; ; ; ; ; { how to create }
; ; ; ;FILE_ATTRIBUTE_NORMAL
; ; ; ;or FILE_FLAG_WRITE_THROUGH, ; ; ; ; ;{ file attributes }
; ; ; ;0 );
end;
fillchar(startupinfo,sizeof(startupinfo),#0);
startupinfo.cb:=sizeof(startupinfo);
StartupInfo.hStdInput:=GetStdHandle(STD_INPUT_HANDLE);
startupinfo.hStdInput:=hinputfile;
startupinfo.hStdOutput:=houtputfile;
startupinfo.hStdError:=houtputfile;
startupinfo.wShowWindow:=sw_hide;
StartupInfo.dwFlags:=STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
pcommandline:='ping localhost';
mok:=createprocess(nil,pcommandline,nil,nil,true,HIGH_PRIORITY_CLASS,nil,nil
,startupinfo,processinfo);
if mok then
begin
WaitforSingleObject(processinfo.hProcess,INFINITE);
hAppProcess:=ProcessInfo.hProcess;
hAppThread:=ProcessInfo.hThread;
end;
closehandle(happprocess);
closehandle(happthread);
closehandle(hinputfile);
closehandle(houtputfile);
screen.Cursor:=oldcursor;
end;
 
后退
顶部