bianbian coding life

便便代码人生: 关注技术, 翻译文档, 偶尔动动手

[原] 改进的DOS命令输出重定向到文本框(TMemo)内

Posted by bianbian on 2007-08-17 02:44

本文Tags: , , ,

虽然是Delphi的,都是调用的WinAPI,C++也可参考。
原理就是管道(Pipe),自己的程序可以Create管道出来,让CreateProcess的子程序能继承自己程序里的管道,替代子程序的标准输入输出。
这样DOS程序对stdout输出的内容就输出到自己程序建立的管道里来了,也就能对其进行读取操作,从而完成重定向到文本框(实时显示)。

基本上Delphi世界里流行的都是DFW上的那个重定向代码,我进行了改进:
1)原来那个代码只能截取输出结果,但是没有换行的整理,要是直接Add到Memo里会杂乱不堪(因为循环取到的内容有可能含有 \r 或 \n,这时候直接Add就有了两行)。
我加上了换行符的处理,Add行的时候按实际的换行进行处理,这样和DOS窗口输出就一致了。
2)原来那个代码没有和Memo绑定,还得自己写Memo操作部分
我加上了Memo作为参数,这样直接调用就省事了。

使用的时候只要 CmdExecAndView(”命令”, memo) 即可。

下面是改进后的代码,欢迎交流:

  1. procedure CmdExecAndView(FileName: string; memo: TMemo);
  2.   procedure _AddInfo(mmInfo:TMemo; S: string; var line: string);
  3.   var
  4.     i, p: Integer;
  5.   begin
  6.     if mmInfo.Lines.Count > 800 then
  7.       mmInfo.Lines.Clear;
  8.     //去掉 \r
  9.     for i := 0 to Length(S) - 1 do
  10.       if S[i] = #13 then S[i] := ' ';
  11.     line := line + S;
  12.     // \n 断行
  13.     p := Pos(#10, line);
  14.     if p > 0 then
  15.     begin
  16.       // \n 前面的加入一行,后面的留到下次
  17.       mmInfo.Lines.Add(Copy(line, 1, p - 1));
  18.       line := Copy(line, p + 1, Length(line) - p);
  19.     end;
  20.   end;
  21. var
  22.   hReadPipe, hWritePipe: THandle;
  23.   si: STARTUPINFO;
  24.   lsa: SECURITY_ATTRIBUTES;
  25.   pi: PROCESS_INFORMATION;
  26.   cchReadBuffer: DWORD;
  27.   ph: PChar;
  28.   fname: PChar;
  29.   line: string;
  30. begin
  31.   fname := allocmem(1024);
  32.   ph := AllocMem(1024);
  33.   lsa.nLength := sizeof(SECURITY_ATTRIBUTES);
  34.   lsa.lpSecurityDescriptor := nil;
  35.   lsa.bInheritHandle := True;
  36.   if CreatePipe(hReadPipe, hWritePipe, @lsa, 0) = false then
  37.     Exit;
  38.   fillchar(si, sizeof(STARTUPINFO), 0);
  39.   si.cb := sizeof(STARTUPINFO);
  40.   si.dwFlags := (STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW);
  41.   si.wShowWindow := SW_HIDE;
  42.   si.hStdOutput := hWritePipe;
  43.   si.hStdError := hWritePipe;
  44.   StrPCopy(fname, FileName);
  45.   if CreateProcess(nil, fname, nil, nil, true, 0, nil, nil, si, pi) = False then
  46.   begin
  47.     FreeMem(ph);
  48.     FreeMem(fname);
  49.     Exit;
  50.   end;
  51.   CloseHandle(hWritePipe);
  52.   while (true) do
  53.   begin
  54.     if not PeekNamedPipe(hReadPipe, ph, 1, @cchReadBuffer, nil, nil) then break;
  55.     if cchReadBuffer <> 0 then
  56.     begin
  57.       if ReadFile(hReadPipe, ph^, 512, cchReadBuffer, nil) = false then break;
  58.       ph[cchReadbuffer] := chr(0);
  59.       _AddInfo(memo, ph, line);
  60.     end
  61.     else if (WaitForSingleObject(pi.hProcess, 0) = WAIT_OBJECT_0) then break;
  62.     Application.ProcessMessages;
  63.     Sleep(200);
  64.   end;
  65.   ph[cchReadBuffer] := chr(0);
  66.   _AddInfo(memo, ph, line);
  67.   CloseHandle(hReadPipe);
  68.   CloseHandle(pi.hThread);
  69.   CloseHandle(pi.hProcess);
  70.   FreeMem(ph);
  71.   FreeMem(fname);
  72. end;
标签: , , ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

3 Responses to “[原] 改进的DOS命令输出重定向到文本框(TMemo)内”

  1. Sunshow Says:

    你终于全文输出了。。。

  2. melice Says:

    好像你的换行处理有问题,像
    CmdExecAndView(’ipconfig’,memo1) ,这个就只会出一行出来。

  3. bianbian Says:

    有些命令的输出捕捉不到,很奇怪。

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

(required)