有一定挑战性:代码中执行一个命令行exe文件,这个exe文件在控制台输出的字符串,有什么办法可以获得吗?

时间:2022-03-23 17:40:20
比如a.exe,执行后的结果是在控制台输出一行字符串:
C:>a.exe回车
Hello World!
有办法在代码中得到这个Hello World字符串?

16 个解决方案

#1


执行dos命令的控件,用获取CMD返回结果的,不知道这样可以不?

不懂我说什吗的可以看看这个:
http://www.2ccc.com/article.asp?articleid=5448

#2


doscommand控件
不过有发现bug

#3


谢谢两位朋友。
sz_haitao你好,你提到的doscommand控件发现bug,是哪方面的?很严重吗?

#4


不算严重

一般使用也足够了

#5


多谢,我一般使用两个功能,一个是获取控制台的输出,一个是判断是否执行完毕。

#6


CSDN搜索一下

#7


引用 5 楼 appleibm 的回复:
多谢,我一般使用两个功能,一个是获取控制台的输出,一个是判断是否执行完毕。


doscommand支持调用者即时取得exe返回的每一行,某些应用需要这个特性

#8


创建进程时设置标准输出管道,然后读取即可

#9


function TForm1.GetCMD(cmd : String): String;
var
  readhdl,writehdl : DWORD;
  sa : TSecurityAttributes;
  stifo : _STARTUPINFOA;
  pinfo : _PROCESS_INFORMATION;
  tmbuff : array [0..254] of char;
  readlen : DWORD;
begin
  Result := '';
  sa.nLength := sizeof(TSecurityAttributes);
  sa.bInheritHandle := TRUE;
  sa.lpSecurityDescriptor := nil;
  if not CreatePipe(readhdl,writehdl,@sa,0) then exit;
  GetStartupInfo(stifo);
  stifo.hStdOutput := writehdl;
  stifo.hStdError := writehdl;
  stifo.wShowWindow := SW_Hide;
  stifo.dwFlags := STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES;
  if CreateProcess(nil,PChar('cmd.exe /C ' + cmd),nil,nil,true,0,nil,nil,stifo,pinfo) then
    begin
      WaitForSingleObject(pinfo.hProcess,INFINITE);
      WriteFile(writehdl,'@#@#@',5,readlen,nil);
      CloseHandle(writehdl);
      readlen := 254;
      while readlen = 254 do
        begin
          ReadFile(readhdl,tmbuff,254,readlen,nil);
          if readlen <> 254 then
            tmbuff[readlen-5] := Chr(0)
          else
            tmbuff[readlen-1] := Chr(0);
          Result := Result + String(tmbuff);
        end;
    end;
  CloseHandle(readhdl);
end;

#10


E:\>dir >a.txt   打开cmd.exe,输入此句可以显示E盘根目录文件和目录信息,并存储在E盘的a.txt中。

楼主你这问题也算有一定挑战性?你试试E:\>a.exe >a.txt  再说吧!

才给这20分, 明显是你对问题不够重视嘛,我回答都没有动力了。

#11


该回复于2011-05-05 08:59:28被版主删除

#12


procedure CmdExecAndView(FileName: string; memo: TMemo);
function Replace(Dest, SubStr, Str: string): string;
var
  Position: Integer;
begin
  while Pos(SubStr, Dest) > 0 do
  begin
    Position := Pos(SubStr, Dest);
    Delete(Dest, Position, Length(SubStr));
    Insert(Str, Dest, Position);
    Delete(Dest,1,(Pos('ms',Dest)-10));
    Delete(Dest,(Pos('ms',Dest)+2),20);
  end;
  Result := Dest;
end;


procedure _AddInfo(mmInfo:TMemo; S: string; var line: string;ip:string;sc:string);
var
    i, p: Integer;
    stext:string;
begin

    if mmInfo.Lines.Count > 800 then
      mmInfo.Lines.Clear;        //去掉 \r

    for i := 0 to Length(S) - 1 do
      if S[i] = #13 then S[i] := ' ';
    line := line + S;
    // \n 断行
    p := Pos(#10, line);
    if p > 0 then
    begin
    stext:=Copy(line, 1, p - 1);
      // \n 前面的加入一行,后面的留到下次
    if Pos(Trim(ip),stext)>0 then    mmInfo.Lines.Add(Replace(stext,Trim(ip),sc));
      line := Copy(line, p + 1, Length(line) - p);
    end;

end;

var
hReadPipe, hWritePipe: THandle;
si: STARTUPINFO;
lsa: SECURITY_ATTRIBUTES;
pi: PROCESS_INFORMATION;
cchReadBuffer: DWORD;
ph: PChar;
fname: PChar;
line: string;
ss:string;
scaption:string;
begin
   ss:='';
   ss:=vpnlist.strings[vpnid];
   Delete(ss,1,Pos('=',ss));
   if Pos(' ',ss)>0 then  ss:=trim(Copy(ss,1,Pos(' ',ss))) ;
   if Length(ss)<7 then Exit;

fname := allocmem(1024);
ph := AllocMem(1024);
lsa.nLength := sizeof(SECURITY_ATTRIBUTES);
lsa.lpSecurityDescriptor := nil;
lsa.bInheritHandle := True;
if CreatePipe(hReadPipe, hWritePipe, @lsa, 0) = false then      Exit;
fillchar(si, sizeof(STARTUPINFO), 0);
si.cb := sizeof(STARTUPINFO);
si.dwFlags := (STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW);
si.wShowWindow := SW_HIDE;
si.hStdOutput := hWritePipe;
si.hStdError := hWritePipe;
StrPCopy(fname, FileName);
if CreateProcess(nil, fname, nil, nil, true, 0, nil, nil, si, pi) = False then
begin
    FreeMem(ph);
    FreeMem(fname);
    Exit;
end;
//dwOwnerPID := Pi.dwProcessId;
CloseHandle(hWritePipe);
while (true) do
begin
  try
  if not PeekNamedPipe(hReadPipe, ph, 1, @cchReadBuffer, nil, nil) then      break;
////如果不这么写,容易出现线程错误
    if cchReadBuffer <> 0 then
    begin
      if ReadFile(hReadPipe, ph^, 8, cchReadBuffer, nil) = false then
      break;
      ph[cchReadbuffer] := chr(0);
       _AddInfo(memo, ph, line,ss,scaption);
    end
    else
    if (WaitForSingleObject(pi.hProcess, 0) = WAIT_OBJECT_0) then
     break;
    Application.ProcessMessages;
     Sleep(2);
  
   except
    break;
   end;
end;
//ph[cchReadBuffer] := chr(0);
//_AddInfo(memo, ph, line,ss,scaption);
CloseHandle(hReadPipe);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
//FreeMem(ph);
FreeMem(fname);
end;

procedure TForm1.pingClick(Sender: TObject);
var
  ss:string;
begin
if ComboBox2.Text<>'' then
begin
Form2.Show;
Form2.Memo1.Clear;
ss:=vpnlist.strings[vpnid];
Delete(ss,1,Pos('=',ss));
CmdExecAndView('ping '+trim(ss)+' -n 10',Form2.Memo1);
end;
end;

我程序里的一段,,自己改改吧

#13


我去试一下

#14


引用 2 楼 sz_haitao 的回复:
doscommand控件
不过有发现bug

谢谢,我使用中发现有内存泄露现象,是有有解决的办法?

#15


引用 9 楼 beiguofengguang 的回复:
function TForm1.GetCMD(cmd : String): String;
var
  readhdl,writehdl : DWORD;
  sa : TSecurityAttributes;
  stifo : _STARTUPINFOA;
  pinfo : _PROCESS_INFORMATION;
  tmbuff : array [0..254] of ch……

谢谢。使用中发现,命令行输出超过一定数量(比如2000byte)死机。另外请教一下:
if readlen <> 254 then
  tmbuff[readlen-5] := Chr(0)
这里的减5是什么意思?不会将控制台的输出字符漏掉?

#16


引用 10 楼 mwy654321 的回复:
E:\>dir >a.txt 打开cmd.exe,输入此句可以显示E盘根目录文件和目录信息,并存储在E盘的a.txt中。

楼主你这问题也算有一定挑战性?你试试E:\>a.exe >a.txt 再说吧!

才给这20分, 明显是你对问题不够重视嘛,我回答都没有动力了。

谢谢你,刚注册的一个ID,以前的ID没分了:(
你的这种方法不正确,因为执行该语句后马上返回,而不是等待执行完毕才返回。

#1


执行dos命令的控件,用获取CMD返回结果的,不知道这样可以不?

不懂我说什吗的可以看看这个:
http://www.2ccc.com/article.asp?articleid=5448

#2


doscommand控件
不过有发现bug

#3


谢谢两位朋友。
sz_haitao你好,你提到的doscommand控件发现bug,是哪方面的?很严重吗?

#4


不算严重

一般使用也足够了

#5


多谢,我一般使用两个功能,一个是获取控制台的输出,一个是判断是否执行完毕。

#6


CSDN搜索一下

#7


引用 5 楼 appleibm 的回复:
多谢,我一般使用两个功能,一个是获取控制台的输出,一个是判断是否执行完毕。


doscommand支持调用者即时取得exe返回的每一行,某些应用需要这个特性

#8


创建进程时设置标准输出管道,然后读取即可

#9


function TForm1.GetCMD(cmd : String): String;
var
  readhdl,writehdl : DWORD;
  sa : TSecurityAttributes;
  stifo : _STARTUPINFOA;
  pinfo : _PROCESS_INFORMATION;
  tmbuff : array [0..254] of char;
  readlen : DWORD;
begin
  Result := '';
  sa.nLength := sizeof(TSecurityAttributes);
  sa.bInheritHandle := TRUE;
  sa.lpSecurityDescriptor := nil;
  if not CreatePipe(readhdl,writehdl,@sa,0) then exit;
  GetStartupInfo(stifo);
  stifo.hStdOutput := writehdl;
  stifo.hStdError := writehdl;
  stifo.wShowWindow := SW_Hide;
  stifo.dwFlags := STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES;
  if CreateProcess(nil,PChar('cmd.exe /C ' + cmd),nil,nil,true,0,nil,nil,stifo,pinfo) then
    begin
      WaitForSingleObject(pinfo.hProcess,INFINITE);
      WriteFile(writehdl,'@#@#@',5,readlen,nil);
      CloseHandle(writehdl);
      readlen := 254;
      while readlen = 254 do
        begin
          ReadFile(readhdl,tmbuff,254,readlen,nil);
          if readlen <> 254 then
            tmbuff[readlen-5] := Chr(0)
          else
            tmbuff[readlen-1] := Chr(0);
          Result := Result + String(tmbuff);
        end;
    end;
  CloseHandle(readhdl);
end;

#10


E:\>dir >a.txt   打开cmd.exe,输入此句可以显示E盘根目录文件和目录信息,并存储在E盘的a.txt中。

楼主你这问题也算有一定挑战性?你试试E:\>a.exe >a.txt  再说吧!

才给这20分, 明显是你对问题不够重视嘛,我回答都没有动力了。

#11


该回复于2011-05-05 08:59:28被版主删除

#12


procedure CmdExecAndView(FileName: string; memo: TMemo);
function Replace(Dest, SubStr, Str: string): string;
var
  Position: Integer;
begin
  while Pos(SubStr, Dest) > 0 do
  begin
    Position := Pos(SubStr, Dest);
    Delete(Dest, Position, Length(SubStr));
    Insert(Str, Dest, Position);
    Delete(Dest,1,(Pos('ms',Dest)-10));
    Delete(Dest,(Pos('ms',Dest)+2),20);
  end;
  Result := Dest;
end;


procedure _AddInfo(mmInfo:TMemo; S: string; var line: string;ip:string;sc:string);
var
    i, p: Integer;
    stext:string;
begin

    if mmInfo.Lines.Count > 800 then
      mmInfo.Lines.Clear;        //去掉 \r

    for i := 0 to Length(S) - 1 do
      if S[i] = #13 then S[i] := ' ';
    line := line + S;
    // \n 断行
    p := Pos(#10, line);
    if p > 0 then
    begin
    stext:=Copy(line, 1, p - 1);
      // \n 前面的加入一行,后面的留到下次
    if Pos(Trim(ip),stext)>0 then    mmInfo.Lines.Add(Replace(stext,Trim(ip),sc));
      line := Copy(line, p + 1, Length(line) - p);
    end;

end;

var
hReadPipe, hWritePipe: THandle;
si: STARTUPINFO;
lsa: SECURITY_ATTRIBUTES;
pi: PROCESS_INFORMATION;
cchReadBuffer: DWORD;
ph: PChar;
fname: PChar;
line: string;
ss:string;
scaption:string;
begin
   ss:='';
   ss:=vpnlist.strings[vpnid];
   Delete(ss,1,Pos('=',ss));
   if Pos(' ',ss)>0 then  ss:=trim(Copy(ss,1,Pos(' ',ss))) ;
   if Length(ss)<7 then Exit;

fname := allocmem(1024);
ph := AllocMem(1024);
lsa.nLength := sizeof(SECURITY_ATTRIBUTES);
lsa.lpSecurityDescriptor := nil;
lsa.bInheritHandle := True;
if CreatePipe(hReadPipe, hWritePipe, @lsa, 0) = false then      Exit;
fillchar(si, sizeof(STARTUPINFO), 0);
si.cb := sizeof(STARTUPINFO);
si.dwFlags := (STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW);
si.wShowWindow := SW_HIDE;
si.hStdOutput := hWritePipe;
si.hStdError := hWritePipe;
StrPCopy(fname, FileName);
if CreateProcess(nil, fname, nil, nil, true, 0, nil, nil, si, pi) = False then
begin
    FreeMem(ph);
    FreeMem(fname);
    Exit;
end;
//dwOwnerPID := Pi.dwProcessId;
CloseHandle(hWritePipe);
while (true) do
begin
  try
  if not PeekNamedPipe(hReadPipe, ph, 1, @cchReadBuffer, nil, nil) then      break;
////如果不这么写,容易出现线程错误
    if cchReadBuffer <> 0 then
    begin
      if ReadFile(hReadPipe, ph^, 8, cchReadBuffer, nil) = false then
      break;
      ph[cchReadbuffer] := chr(0);
       _AddInfo(memo, ph, line,ss,scaption);
    end
    else
    if (WaitForSingleObject(pi.hProcess, 0) = WAIT_OBJECT_0) then
     break;
    Application.ProcessMessages;
     Sleep(2);
  
   except
    break;
   end;
end;
//ph[cchReadBuffer] := chr(0);
//_AddInfo(memo, ph, line,ss,scaption);
CloseHandle(hReadPipe);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
//FreeMem(ph);
FreeMem(fname);
end;

procedure TForm1.pingClick(Sender: TObject);
var
  ss:string;
begin
if ComboBox2.Text<>'' then
begin
Form2.Show;
Form2.Memo1.Clear;
ss:=vpnlist.strings[vpnid];
Delete(ss,1,Pos('=',ss));
CmdExecAndView('ping '+trim(ss)+' -n 10',Form2.Memo1);
end;
end;

我程序里的一段,,自己改改吧

#13


我去试一下

#14


引用 2 楼 sz_haitao 的回复:
doscommand控件
不过有发现bug

谢谢,我使用中发现有内存泄露现象,是有有解决的办法?

#15


引用 9 楼 beiguofengguang 的回复:
function TForm1.GetCMD(cmd : String): String;
var
  readhdl,writehdl : DWORD;
  sa : TSecurityAttributes;
  stifo : _STARTUPINFOA;
  pinfo : _PROCESS_INFORMATION;
  tmbuff : array [0..254] of ch……

谢谢。使用中发现,命令行输出超过一定数量(比如2000byte)死机。另外请教一下:
if readlen <> 254 then
  tmbuff[readlen-5] := Chr(0)
这里的减5是什么意思?不会将控制台的输出字符漏掉?

#16


引用 10 楼 mwy654321 的回复:
E:\>dir >a.txt 打开cmd.exe,输入此句可以显示E盘根目录文件和目录信息,并存储在E盘的a.txt中。

楼主你这问题也算有一定挑战性?你试试E:\>a.exe >a.txt 再说吧!

才给这20分, 明显是你对问题不够重视嘛,我回答都没有动力了。

谢谢你,刚注册的一个ID,以前的ID没分了:(
你的这种方法不正确,因为执行该语句后马上返回,而不是等待执行完毕才返回。