Search code examples
lazaruswindows-consolefpc

Console application never returns when ran with TProcess


I am using Windows Server 2008 and I want to get the DNS Server. So I tought that the fastest way should be executing ipconfig and then parsing it's output using TProcess.

I have came up with this code :

  var
  proces : TProcess;
  begin
  ...
  proces := TProcess.Create(nil);
  proces.Executable := 'ipconfig';
  proces.Options := proces.Options + [poWaitOnExit,poUsePipes];
  try
  proces.Execute;
  except
        proces.Free;
  end;
  SetLength(rez,proces.Output.NumBytesAvailable);
  proces.Output.Read(rez[1],proces.Output.NumBytesAvailable);
  ShowMessage(rez);

The code works but after I manually close the console window.I have tried poNoConsole but still the same result, the process ipconfig remains active in taskmanager.

Why isn't the console application ipconfig terminating ? If I run it it exits after spitting stdout information.

Is it my configuration? Is it a bug ? Help! thanks :)


Solution

  • Since ipconfig can generate a lot of output, don't try to read it in one go, use the Reading large output method from the wiki.

    The next iteration of FPC (2.6.2) will have a bunch of runcommand procedures that instrument tprocess for a series of common cases and return the output in a single string.

    Note API solutions are also possible:

    {$mode delphi}
    
    uses  JwaIpExport, JwaIpRtrMib, JwaIpTypes,jwawinerror,classes,jwaiphlpapi;
    
    procedure GetDNSServers(AList: TStringList);
    var
      pFI: PFixed_Info;
      pIPAddr: PIPAddrString;
      OutLen: Cardinal;
    begin
      AList.Clear;
      OutLen := SizeOf(TFixedInfo);
      GetMem(pFI, SizeOf(TFixedInfo));
      try
        if GetNetworkParams(pFI, OutLen) = ERROR_BUFFER_OVERFLOW then
        begin
          ReallocMem(pFI, OutLen);
          if GetNetworkParams(pFI, OutLen) <> NO_ERROR then Exit;
        end;
        // If there is no network available there may be no DNS servers defined
        if pFI^.DnsServerList.IpAddress.s[0] = #0 then Exit;
        // Add first server
        AList.Add(pFI^.DnsServerList.IpAddress.s);
        // Add rest of servers
        pIPAddr := pFI^.DnsServerList.Next;
        while Assigned(pIPAddr) do
        begin
          AList.Add(pIPAddr^.IpAddress.s);
          pIPAddr := pIPAddr^.Next;
        end;
      finally
        FreeMem(pFI);
      end;
    end;
    
    var v : TStringList; 
        s : string;
    begin
     v:=tstringlist.create;
     getdnsservers(v);
     for s in v do writeln(s);   // this probably requires 2.6+
     v.free;
    end.