🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.delphi.nativeapi.win32
1 messages
1 total messages Started by concept0399 Mon, 14 Jul 2008 20:50
"ifconfig -a" in Delphi --- or, how to query NIC's in Delphi
#193
Author: concept0399
Date: Mon, 14 Jul 2008 20:50
455 lines
13930 bytes
I had a need to retrieve information about adapters, and as a way to
teach myself how to do this I wrote a utility that mimics the linux/
unix utility ifconfig. More accurately, it mimics calling "ifconfig -
a". I am providing my code below, in the event that someone else may
find it useful.

I tried to write it in a way that this project can be easily adapted
for other projects that need to retrieve NIC information. I store all
NIC information in what I call 'TAdapterInfo', which is really just an
array of records. This allows you to fill this array with NIC
information, and then use it any way that you'd like.

I compiled this with Delphi 2007, however it should work in earlier
versions. It requires no additional code. It's just 2 files and it is
a console application.


////////////////////////////////////////////////////////////////////////
//
//  uAdapterInfo.pas
//
//

unit uAdapterInfo;

interface

uses
  Classes,
  SysUtils;

const
  MAX_INTERFACE_NAME_LEN = $100;
  ERROR_SUCCESS   = 0;
  MAXLEN_IFDESCR  = $100;
  MAXLEN_PHYSADDR = 8;

  MIB_IF_OPER_STATUS_NON_OPERATIONAL = 0;
  MIB_IF_OPER_STATUS_UNREACHABLE = 1;
  MIB_IF_OPER_STATUS_DISCONNECTED = 2;
  MIB_IF_OPER_STATUS_CONNECTING  = 3;
  MIB_IF_OPER_STATUS_CONNECTED   = 4;
  MIB_IF_OPER_STATUS_OPERATIONAL = 5;

  MIB_IF_TYPE_OTHER    = 1;
  MIB_IF_TYPE_ETHERNET = 6;
  MIB_IF_TYPE_TOKENRING = 9;
  MIB_IF_TYPE_FDDI     = 15;
  MIB_IF_TYPE_PPP      = 23;
  MIB_IF_TYPE_LOOPBACK = 24;
  MIB_IF_TYPE_SLIP     = 28;

  MIB_IF_ADMIN_STATUS_UP      = 1;
  MIB_IF_ADMIN_STATUS_DOWN    = 2;
  MIB_IF_ADMIN_STATUS_TESTING = 3;

  _MAX_ROWS_ = 20;
  ANY_SIZE   = 1;


type
  MIB_IFROW = record
    wszName:    array[0 .. (MAX_INTERFACE_NAME_LEN * 2 - 1)] of char;
    dwIndex:    longint;
    dwType:     longint;
    dwMtu:      longint;
    dwSpeed:    longint;
    dwPhysAddrLen: longint;
    bPhysAddr:  array[0 .. (MAXLEN_PHYSADDR - 1)] of byte;
    dwAdminStatus: longint;
    dwOperStatus: longint;
    dwLastChange: longint;
    dwInOctets: longint;
    dwInUcastPkts: longint;
    dwInNUcastPkts: longint;
    dwInDiscards: longint;
    dwInErrors: longint;
    dwInUnknownProtos: longint;
    dwOutOctets: longint;
    dwOutUcastPkts: longint;
    dwOutNUcastPkts: longint;
    dwOutDiscards: longint;
    dwOutErrors: longint;
    dwOutQLen:  longint;
    dwDescrLen: longint;
    bDescr:     array[0 .. (MAXLEN_IFDESCR - 1)] of char;
  end;

type
  MIB_IPADDRROW = record
    dwAddr:      longint;
    dwIndex:     longint;
    dwMask:      longint;
    dwBCastAddr: longint;
    dwReasmSize: longint;
    unused1:     word;
    unused2:     word;
  end;

type
  _IfTable = record
    nRows: longint;
    ifRow: array[1.._MAX_ROWS_] of MIB_IFROW;
  end;

type
  _IpAddrTable = record
    dwNumEntries: longint;
    table: array[1..ANY_SIZE] of MIB_IPADDRROW;
  end;



function GetIfTable(pIfTable: Pointer; var pdwSize: longint;
  bOrder: longint): longint; stdcall;
function GetIpAddrTable(pIpAddrTable: Pointer; var pdwSize: longint;
  bOrder: longint): longint; stdcall;

function Get_if_type(iType: integer): string;
function Get_if_admin_status(iStatus: integer): string;
function Get_if_oper_status(iStatus: integer): string;


implementation

function GetIfTable; stdcall; external 'IPHLPAPI.DLL';
function GetIpAddrTable; stdcall; external 'IPHLPAPI.DLL';

function Get_if_type(iType: integer): string;
var
  sResult: string;
begin
  sResult := 'UNKNOWN';
  case iType of
    1: sResult   := 'Other';
    6: sResult   := 'Ethernet';
    9: sResult   := 'Tokenring';
    15: sResult  := 'FDDI';
    23: sResult  := 'PPP';
    24: sResult  := 'Local loopback';
    28: sResult  := 'SLIP';
    37: sResult  := 'ATM';
    71: sResult  := 'IEEE 802.11';
    131: sResult := 'Tunnel';
    144: sResult := 'IEEE 1394 (Firewire)';
  end;

  Result := sResult;
end;

function Get_if_admin_status(iStatus: integer): string;
var
  sResult: string;
begin
  sResult := 'UNKNOWN';

  case iStatus of
    1: sResult := 'UP';
    2: sResult := 'DOWN';
    3: sResult := 'TESTING';
  end;

  Result := sResult;
end;

function Get_if_oper_status(iStatus: integer): string;
var
  sResult: string;
begin
  sResult := 'UNKNOWN';

  case iStatus of
    0: sResult := 'NON_OPERATIONAL';
    1: sResult := 'UNREACHABLE';
    2: sResult := 'DISCONNECTED';
    3: sResult := 'CONNECTING';
    4: sResult := 'CONNECTED';
    5: sResult := 'OPERATIONAL';
  end;

  Result := sResult;
end;

end.






////////////////////////////////////////////////////////////////////////
//
//  ifconfig.dpr
//
//
program ifconfig;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes,
  Winsock,
  uAdapterInfo in 'uAdapterInfo.pas';

type
  TAdapterInfo = array of record
    dwIndex:    longint;
    dwType:     longint;
    dwMtu:      longint;
    dwSpeed:    extended;
    dwPhysAddrLen: longint;
    bPhysAddr:  string;
    dwAdminStatus: longint;
    dwOperStatus: longint;
    dwLastChange: longint;
    dwInOctets: longint;
    dwInUcastPkts: longint;
    dwInNUcastPkts: longint;
    dwInDiscards: longint;
    dwInErrors: longint;
    dwInUnknownProtos: longint;
    dwOutOctets: longint;
    dwOutUcastPkts: longint;
    dwOutNUcastPkts: longint;
    dwOutDiscards: longint;
    dwOutErrors: longint;
    dwOutQLen:  longint;
    dwDescrLen: longint;
    bDescr:     string;
    sIpAddress: string;
    sIpMask:    string;
  end;




  function Get_EthernetAdapterDetail(var AdapterDataFound:
TAdapterInfo): boolean;
  var
    pIfTable: ^_IfTable;
    pIpTable: ^_IpAddrTable;
    ifTableSize, ipTableSize: longint;
    tmp:      string;
    i, j, k, m: integer;
    ErrCode:  longint;
    sAddr, sMask: in_addr;
    IPAddresses, IPMasks: TStringList;
    sIPAddressLine, sIPMaskLine: string;
    bResult:  boolean;
  begin
    bResult  := True; //default return value
    pIfTable := nil;
    pIpTable := nil;

    IPAddresses := TStringList.Create;
    IPMasks     := TStringList.Create;

    try
      // First: just get the buffer size.
      // TableSize returns the size needed.
      ifTableSize := 0; // Set to zero so the GetIfTabel function
      // won't try to fill the buffer yet,
      // but only return the actual size it needs.
      GetIfTable(pIfTable, ifTableSize, 1);
      if (ifTableSize < SizeOf(MIB_IFROW) + Sizeof(longint)) then
      begin
        bResult := False;
        Result := bResult;
        Exit; // less than 1 table entry?!
      end;

      ipTableSize := 0;
      GetIpAddrTable(pIpTable, ipTableSize, 1);
      if (ipTableSize < SizeOf(MIB_IPADDRROW) + Sizeof(longint)) then
      begin
        bResult := False;
        Result := bResult;
        Exit; // less than 1 table entry?!
      end;

      // Second:
      // allocate memory for the buffer and retrieve the
      // entire table.
      GetMem(pIfTable, ifTableSize);
      ErrCode := GetIfTable(pIfTable, ifTableSize, 1);

      if ErrCode <> ERROR_SUCCESS then
      begin
        bResult := False;
        Result := bResult;
        Exit; // OK, that did not work.
        // Not enough memory i guess.
      end;

      GetMem(pIpTable, ipTableSize);
      ErrCode := GetIpAddrTable(pIpTable, ipTableSize, 1);

      if ErrCode <> ERROR_SUCCESS then
      begin
        bResult := False;
        Result := bResult;
        Exit;
      end;

      for k := 1 to pIpTable^.dwNumEntries do
      begin
        sAddr.S_addr := pIpTable^.table[k].dwAddr;
        sMask.S_addr := pIpTable^.table[k].dwMask;

        sIPAddressLine := Format('0x%8.8x',
[(pIpTable^.table[k].dwIndex)]) +
          '=' + Format('%s', [inet_ntoa(sAddr)]);
        sIPMaskLine    := Format('0x%8.8x',
[(pIpTable^.table[k].dwIndex)]) +
          '=' + Format('%s', [inet_ntoa(sMask)]);

        IPAddresses.Add(sIPAddressLine);
        IPMasks.Add(sIPMaskLine);
      end;

      SetLength(AdapterDataFound, pIfTable^.nRows); //initialize the
array or records
      for i := 1 to pIfTable^.nRows do
        try
          //if pIfTable^.ifRow[i].dwType=MIB_IF_TYPE_ETHERNET then
          //begin
          m := i - 1;
          AdapterDataFound[m].dwIndex := 4;//
(pIfTable^.ifRow[i].dwIndex);
          AdapterDataFound[m].dwType := (pIfTable^.ifRow[i].dwType);
          AdapterDataFound[m].dwIndex := (pIfTable^.ifRow[i].dwIndex);
          AdapterDataFound[m].sIpAddress :=
            IPAddresses.Values[Format('0x%8.8x',
[(pIfTable^.ifRow[i].dwIndex)])];
          AdapterDataFound[m].sIpMask :=
            IPMasks.Values[Format('0x%8.8x',
[(pIfTable^.ifRow[i].dwIndex)])];
          AdapterDataFound[m].dwMtu := (pIfTable^.ifRow[i].dwMtu);
          AdapterDataFound[m].dwSpeed := (pIfTable^.ifRow[i].dwSpeed);
          AdapterDataFound[m].dwAdminStatus :=
(pIfTable^.ifRow[i].dwAdminStatus);
          AdapterDataFound[m].dwOperStatus :=
(pIfTable^.ifRow[i].dwOperStatus);
          AdapterDataFound[m].dwInUcastPkts :=
(pIfTable^.ifRow[i].dwInUcastPkts);
          AdapterDataFound[m].dwInNUcastPkts :=
(pIfTable^.ifRow[i].dwInNUcastPkts);
          AdapterDataFound[m].dwInDiscards :=
(pIfTable^.ifRow[i].dwInDiscards);
          AdapterDataFound[m].dwInErrors :=
(pIfTable^.ifRow[i].dwInErrors);
          AdapterDataFound[m].dwInUnknownProtos :=
(pIfTable^.ifRow[i].dwInUnknownProtos);
          AdapterDataFound[m].dwOutNUcastPkts :=
(pIfTable^.ifRow[i].dwOutNUcastPkts);
          AdapterDataFound[m].dwOutUcastPkts :=
(pIfTable^.ifRow[i].dwOutUcastPkts);
          AdapterDataFound[m].dwOutDiscards :=
(pIfTable^.ifRow[i].dwOutDiscards);
          AdapterDataFound[m].dwOutErrors :=
(pIfTable^.ifRow[i].dwOutErrors);
          AdapterDataFound[m].dwOutQLen :=
(pIfTable^.ifRow[i].dwOutQLen);
          AdapterDataFound[m].bDescr := (pIfTable^.ifRow[i].bDescr);

          tmp := '';
          for j := 0 to pIfTable^.ifRow[i].dwPhysAddrLen - 1 do
          begin
            if Length(tmp) > 0 then
              tmp := tmp + '-' + format('%.2x',
[pIfTable^.ifRow[i].bPhysAddr[j]])
            else
              tmp := tmp + format('%.2x',
[pIfTable^.ifRow[i].bPhysAddr[j]]);
          end;

          if Length(tmp) > 0 then
          begin
            AdapterDataFound[m].bPhysAddr := tmp;
          end;
        except
          bResult := False;
          Result := bResult;
          Exit;
        end;
    finally
      if Assigned(pIfTable) then
      begin
        FreeMem(pIfTable, ifTableSize);
      end;

      FreeAndNil(IPMasks);
      FreeAndNil(IPAddresses);
    end;

    Result := bResult;
  end;



var
  AdapterData: TAdapterInfo;
  i: integer;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    WriteLn('');
    if Get_EthernetAdapterDetail(AdapterData) then
    begin
      for i := 0 to Length(AdapterData) - 1 do
      begin
        WriteLn(Format('0x%8.8x', [AdapterData[i].dwIndex]));
        WriteLn('"' + AdapterData[i].bDescr + '"');
        Write(Format(#9 + 'Link encap: %s ',
[Get_if_type(AdapterData[i].dwType)]));

        if Length(AdapterData[i].bPhysAddr) > 0 then
          Write('HWaddr: ' + AdapterData[i].bPhysAddr);

        Write(#13 + #10 + #9 + 'inet addr:' +
AdapterData[i].sIpAddress);
        WriteLn(' Mask: ' + AdapterData[i].sIpMask);
        WriteLn(Format(#9 + 'MTU: %d Speed:%.2f Mbps',
[AdapterData[i].dwMtu,
          (AdapterData[i].dwSpeed) / 1000 / 1000]));
        Write(#9 + 'Admin status:' +
Get_if_admin_status(AdapterData[i].dwAdminStatus));
        WriteLn(' Oper status:' +
Get_if_oper_status(AdapterData[i].dwOperStatus));
        WriteLn(#9 + Format('RX packets:%d dropped:%d errors:%d unkown:
%d',
          [AdapterData[i].dwInUcastPkts +
AdapterData[i].dwInNUcastPkts,
          AdapterData[i].dwInDiscards, AdapterData[i].dwInErrors,
          AdapterData[i].dwInUnknownProtos]));
        WriteLn(#9 + Format('TX packets:%d dropped:%d errors:%d
txqueuelen:%d',
          [AdapterData[i].dwOutUcastPkts +
AdapterData[i].dwOutNUcastPkts,
          AdapterData[i].dwOutDiscards, AdapterData[i].dwOutErrors,
          AdapterData[i].dwOutQLen]));

        WriteLn('');
      end;
    end
    else
    begin
      WriteLn(#13+#10+'*** Error retrieving adapter information');
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads