DELPHI CreatePipe 方法读取一个DOS窗口返回的数值。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DELPHI CreatePipe 方法读取一个DOS窗口返回的数值。相关的知识,希望对你有一定的参考价值。

就好比我用DELPHI的WINEXEC创建了一个PING xx.xx.xx.xx -t的命令,然后用管道技术将结果取回存入变量供我分析。

最好能给写成一个 procedure,我直接调用就可以了,哈哈。
写入文件再读出方式无效,因为文本会被另一进程占用,DELPHI读取时会报错,所以才会想到用管道。

能给个现成的例子是最好不过的。

只要管道形式的,其他存为文本方式答案一律忽略。

通过管道技术就可以读取到DOS窗口的返回。

写过一个单元文件可以取到,代码如下:

unit mylib;

interface

uses
  Windows, ShellAPI;
  function GetDosOutput(CommandLine: string): string;

implementation

function GetDosOutput(CommandLine: string): string;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array [0 .. 255] of AnsiChar;
  BytesRead: Cardinal;
  Handle: Boolean;
begin
  Result := \'\';
  with SA do
  begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
  try
    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 stdin
      hStdOutput := StdOutPipeWrite;
      hStdError := StdOutPipeWrite;
    end;
    Handle := CreateProcess(nil, PChar(\'cmd /c \' + CommandLine), nil, nil,
      True, 0, nil, nil, SI, PI);
    CloseHandle(StdOutPipeWrite);
    if Handle then
      try
        repeat
          WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
          if BytesRead > 0 then
          begin
            Buffer[BytesRead] := #0;
            Result := Result + Buffer;
          end;
        until not WasOK or (BytesRead = 0);
        WaitForSingleObject(PI.hProcess, INFINITE);
      finally
        CloseHandle(PI.hThread);
        CloseHandle(PI.hProcess);
      end;
  finally
    CloseHandle(StdOutPipeRead);
  end;
end;

end.

测试代码:

procedure TForm1.btn1Click(Sender: TObject);
begin
  mmo1.Text:= GetDosOutput(\'ping www.baidu.com\');
end;

执行效果:

参考技术A 考虑使用dos命令直接将结果写入文件,然后操作文件即可

比如PING xx.xx.xx.xx >>1.txt
参考技术B if WinExec('cmd.exe /c ping 192.168.0.1 >f:\ping.txt',sw_hide)>31 then
begin
Sleep(5000);//等待文件生成
Memo1.Lines.LoadFromFile('f:\ping.txt');
end;
参考技术C function AnsiToWide(var aAString: AnsiString): string;

var

temp: string;

count: Integer;

begin

count := Length(aAString);

SetLength(temp, count);

MultiByteToWideChar(CP_ACP, 0, PAnsiChar(aAString), count, PChar(temp), count);

Result := temp;

end;

function RunProgram(aExecutablePath, aArguments: string): string;

var

buffer: array[0..4095] of AnsiChar;

bufferStr: AnsiString;

sa: TSecurityAttributes;

hReadPipe, hWritePipe: THandle;

si: TStartupInfo;

pi: TProcessInformation;

dwExitCode: DWORD;

dwSize, dwRead, dwTemp: DWORD;

begin

FillChar(sa, SizeOf(sa), 0);

sa.nLength := SizeOf(sa);

sa.lpSecurityDescriptor := nil;

sa.bInheritHandle := True;

if CreatePipe(hReadPipe, hWritePipe, @sa, SizeOf(sa)) then

begin

FillChar(si, SizeOf(si), 0);

si.cb := SizeOf(si);

si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;

si.wShowWindow := SW_HIDE;

si.hStdInput := hReadPipe;

si.hStdOutput := hWritePipe;

si.hStdError := hWritePipe;

if (Length(aArguments) > 0) and (aArguments[1] <> ' ') then

begin

aArguments := ' ' + aArguments;

end;

if CreateProcess(PChar(aExecutablePath), PChar(aArguments), nil, nil, True, 0, nil, nil, si, pi) then

begin

while True do

begin

if GetExitCodeProcess(pi.hProcess, dwExitCode) then

begin

if dwExitCode <> STILL_ACTIVE then Break;

if PeekNamedPipe(hReadPipe, nil, 0, nil, @dwSize, nil) then

begin

dwTemp := 0;

while dwTemp < dwSize do

begin

FillChar(buffer, dwSize + 2, 0);

if ReadFile(hReadPipe, buffer, dwSize, dwRead, nil) then

begin

Inc(dwTemp, dwRead);

bufferStr := buffer;

Result := Result + AnsiToWide(bufferStr);

end

else

Break;

end;

end

else

Break;

Sleep(10);

end

else

Break;

end;

CloseHandle(pi.hThread);

CloseHandle(pi.hProcess);

end;

CloseHandle(hReadPipe);

CloseHandle(hWritePipe);

end;

end;

a = RunProgram('C:\Windows\system32\ping.exe', '-t 192.168.0.1')

delphi2010下通过
参考技术D procedure GetDosRes(Que:String; var Res:string);
const
CUANTOBUFFER = 2000;
var
Seguridades :TSecurityAttributes;
PaLeer,PaEscribir :THandle;
start :TStartUpInfo;
ProcessInfo :TProcessInformation;
Buffer :Pchar;
BytesRead :DWord;
CuandoSale :DWord;
begin
with Seguridades do
begin
nlength := SizeOf(TSecurityAttributes);
binherithandle := true;
lpsecuritydescriptor := nil;
end;
if Createpipe(PaLeer,PaEscribir,@Seguridades,0) then
begin
Buffer := AllocMem(CUANTOBUFFER + 1);
try
FillChar(Start,Sizeof(Start),#0);
start.cb := SizeOf(start);
start.hStdOutput := PaEscribir;
start.hStdInput := PaLeer;
start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
start.wShowWindow := SW_HIDE;
if CreateProcess(nil,PChar(Que),@Seguridades,@Seguridades,true,NORMAL_PRIORITY_CLASS,nil, nil,start,ProcessInfo)
then
begin
repeat
CuandoSale := WaitForSingleObject( ProcessInfo.hProcess,100);
Application.ProcessMessages;
until (CuandoSale <> WAIT_TIMEOUT);
Res := '';
repeat
BytesRead := 0;
ReadFile(PaLeer,Buffer[0],CUANTOBUFFER,BytesRead,nil);
Buffer[BytesRead] := #0;
OemToAnsi(Buffer,Buffer);
Res := Res + String(Buffer);
until (BytesRead < CUANTOBUFFER);
end;
finally
FreeMem(Buffer);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
CloseHandle(PaLeer);
CloseHandle(PaEscribir);
end;
end;
end;

调用
var
s :string;
begin
GetDosRes('Ping www.baidu.com',s);
showmessage(s);
end;本回答被提问者采纳

在子进程处于活动状态时读取子进程的输出

【中文标题】在子进程处于活动状态时读取子进程的输出【英文标题】:read child process's output while it is alive 【发布时间】:2014-01-17 14:49:11 【问题描述】:

我用

创建了两个管道
saAttr.bInheritHandle = TRUE; 
...
CreatePipe(&childStdOut_Rd, &childStdOut_Wr, &saAttr, 0);
CreatePipe(&childStdErr_Rd, &childStdErr_Wr, &saAttr, 0);

然后我用下一个 STARTUPINFO 创建了子进程:

                        STARTUPINFO si;
                        ZeroMemory(&si, sizeof(si));
                        si.cb = sizeof(STARTUPINFO);
                        si.dwFlags     = STARTF_USESHOWWINDOW;
                        si.wShowWindow = SW_MINIMIZE;
                        si.hStdError   = childStdErr_Wr;
                        si.hStdOutput  = childStdOut_Wr;
                        si.hStdInput   = INVALID_HANDLE_VALUE;
                        si.dwFlags    |= STARTF_USESTDHANDLES;

然后关闭父进程中的写句柄: CloseHandle(childStdErr_Wr); CloseHandle(childStdOut_Wr);

我等待子进程完成

WaitForSingleObject(pi.hProcess, INFINITE);

当我在 MSDN 上阅读时,我可以读取 chil 进程的标准输出:

for (;;) 
 
    BOOL bSuccess = ReadFile(childStdOut_Rd, chBuf, bufsize, &dwRead, NULL);
    if(!bSuccess || dwRead == 0) break; 

    bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
    if (!bSuccess) break; 
 

问:但是我必须把代码放在哪里才能读取孩子的输出?


为什么我不能用这些管道读取 cout 和 printf?

【问题讨论】:

【参考方案1】:

我猜是这样的..

ChildProcess -- main.cpp

#include <iostream>
#include <windows.h>


int main()

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (!hOut)
        return 0;

    DWORD WriteCount = 0;
    char Buffer[1024] = 0;

    strcat(&Buffer[0], "Hello? Momma?!");
    int Length = strlen(Buffer);

    for (int i = 0; i < 10; ++i)
    
        if (!WriteFile(hOut, Buffer, Length, &WriteCount, 0))
            break;
    

    return 0;

ParentProcess -- main.cpp

#include <iostream>
#include <windows.h>

void RedirectIO(HANDLE &hRead, HANDLE &hWrite)

    SECURITY_ATTRIBUTES attr;
    ZeroMemory(&attr, sizeof(attr));
    attr.nLength = sizeof(attr);
    attr.bInheritHandle = true;

    CreatePipe(&hRead, &hWrite, &attr, 0);
    SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);


bool CreateChild(std::string CommandLine, DWORD WaitTime, HANDLE hInRead, HANDLE hOutWrite)

    STARTUPINFO SI;
    PROCESS_INFORMATION PI;
    ZeroMemory(&SI, sizeof(SI));
    ZeroMemory(&PI, sizeof(PI));

    SI.cb = sizeof(SI);
    SI.hStdError = hOutWrite;
    SI.hStdInput = hInRead;
    SI.hStdOutput = hOutWrite;
    SI.dwFlags |= STARTF_USESTDHANDLES;

    bool success = CreateProcess(0, const_cast<char*>(CommandLine.c_str()), 0, 0, true, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, 0, 0, &SI,&PI);

    if (success)
    
        WaitForSingleObject(PI.hProcess, WaitTime);
        CloseHandle(PI.hProcess);
        CloseHandle(PI.hThread);
    

    return success;


int main()

    HANDLE hRead = nullptr;
    HANDLE hWrite = nullptr;

    RedirectIO(hRead, hWrite);
    CreateChild("C:/Users/School/Desktop/ChildProcess/bin/Debug/ChildProcess.exe", INFINITE, nullptr, hWrite);

    DWORD ReadCount = 0;
    char Buffer[1024] = 0;

    std::string data = std::string();

    while(true)
    
        if (!ReadFile(hRead, Buffer, sizeof(Buffer) / sizeof(char), &ReadCount, 0))
            break;

        if (!ReadCount) break;

        Buffer[ReadCount] = '\0';
        data.append(&Buffer[0], ReadCount);
        std::cout<<"Read From Child:\n\n"<<data<<"\n";
    

    return 0;

它应该打印Hello? Momma?! 10 次。另一个选择是将读数放在WaitForSingleObject 之后,这样您就不会立即关闭进程,并且可以继续与它通信。甚至可能创建一个线程并在该线程中读取,或者让线程产生进程并读取.. 由您决定。

【讨论】:

以上是关于DELPHI CreatePipe 方法读取一个DOS窗口返回的数值。的主要内容,如果未能解决你的问题,请参考以下文章

delphi创建文件和读取.ini文件怎么写

DELPHI中逐行读取并复制

在 Windows 中创建匿名管道

delphi中,如何读取一个目录中的所有文件?在线等……

delphi 读取xml

在子进程处于活动状态时读取子进程的输出