4

I am using Delphi XE2 Update 4 on Windows XP sp3

I am looking to get max possible information from installed network adapters, specially the broadcast ip.

For that I used this code from Jan Schulz that I got from this article.

Unit:

Unit USock;

Interface

Uses Windows, Winsock;

{ Unit to identify the network interfaces
  This code requires at least Win98/ME/2K, 95 OSR 2 or NT service pack #3
  as WinSock 2 is used (WS2_32.DLL) }


// Constants found in manual on non-officially documented M$ Winsock functions
Const SIO_GET_INTERFACE_LIST = $4004747F;
      IFF_UP                 = $00000001;
      IFF_BROADCAST          = $00000002;
      IFF_LOOPBACK           = $00000004;
      IFF_POINTTOPOINT       = $00000008;
      IFF_MULTICAST          = $00000010;


Type SockAddr_Gen          = Packed Record
                               AddressIn             : SockAddr_In;
                               Padding               : Packed Array [0..7] of Char;
                             end;

     Interface_Info        = Record
                               iiFlags               : u_Long;
                               iiAddress             : SockAddr_Gen;
                               iiBroadcastAddress    : SockAddr_Gen;
                               iiNetmask             : SockAddr_Gen;
                             end;

     tNetworkInterface     = Record
                               ComputerName          : String;
                               AddrIP                : String;
                               SubnetMask            : String;
                               AddrNet               : String;
                               AddrLimitedBroadcast  : String;
                               AddrDirectedBroadcast : String;
                               IsInterfaceUp         : Boolean;
                               BroadcastSupport      : Boolean;
                               IsLoopback            : Boolean;
                             end;

     tNetworkInterfaceList = Array of tNetworkInterface;


Function WSAIoctl (aSocket              : TSocket;
                   aCommand             : DWord;
                   lpInBuffer           : PChar;
                   dwInBufferLen        : DWord;
                   lpOutBuffer          : PChar;
                   dwOutBufferLen       : DWord;
                   lpdwOutBytesReturned : LPDWord;
                   lpOverLapped         : Pointer;
                   lpOverLappedRoutine  : Pointer) : Integer; stdcall; external 'WS2_32.DLL';

Function GetNetworkInterfaces (Var aNetworkInterfaceList : tNetworkInterfaceList): Boolean;



Implementation

Function GetNetworkInterfaces (Var aNetworkInterfaceList : tNetworkInterfaceList): Boolean;
// Returns a complete list the of available network interfaces on a system (IPv4)
// Copyright by Dr. Jan Schulz, 23-26th March 2007
// This version can be used for free and non-profit projects. In any other case get in contact
// Written with information retrieved from MSDN
// www.code10.net
Var aSocket             : TSocket;
    aWSADataRecord      : WSAData;
    NoOfInterfaces      : Integer;
    NoOfBytesReturned   : u_Long;
    InterfaceFlags      : u_Long;
    NameLength          : DWord;
    pAddrIP             : SockAddr_In;
    pAddrSubnetMask     : SockAddr_In;
    pAddrBroadcast      : Sockaddr_In;
    pIPString           : PChar;
    pSubnetMaskString   : PChar;
    pLimBroadcastString : PChar;
    pNetAddrString      : PChar;
    pDirBroadcastString : PChar;
    DirBroadcastDummy   : In_Addr;
    NetAddrDummy        : In_Addr;
    Buffer              : Array [0..30] of Interface_Info;
    i                   : Integer;
Begin
  Result := False;
  SetLength (aNetworkInterfaceList, 0);

  // Startup of old the WinSock
  // WSAStartup ($0101, aWSADataRecord);

  // Startup of WinSock2
  WSAStartup(MAKEWORD(2, 0), aWSADataRecord);

  // Open a socket
  aSocket := Socket (AF_INET, SOCK_STREAM, 0);

  // If impossible to open a socket, not worthy to go any further
  If (aSocket = INVALID_SOCKET) THen Exit;

  Try
    If WSAIoCtl (aSocket, SIO_GET_INTERFACE_LIST, NIL, 0,
                 @Buffer, 1024, @NoOfBytesReturned, NIL, NIL) <> SOCKET_ERROR THen
    Begin
      NoOfInterfaces := NoOfBytesReturned  Div SizeOf (Interface_Info);
      SetLength (aNetworkInterfaceList, NoOfInterfaces);

      // For each of the identified interfaces get:
      For i := 0 to NoOfInterfaces - 1 do
      Begin

        With aNetworkInterfaceList[i] do
        Begin

          // Get the name of the machine
          NameLength := MAX_COMPUTERNAME_LENGTH + 1;
          SetLength (ComputerName, NameLength)  ;
          If Not Windows.GetComputerName (PChar (Computername), NameLength) THen ComputerName := '';

          // Get the IP address
          pAddrIP                  := Buffer[i].iiAddress.AddressIn;
          pIPString                := inet_ntoa (pAddrIP.Sin_Addr);
          AddrIP                   := pIPString;

          // Get the subnet mask
          pAddrSubnetMask          := Buffer[i].iiNetMask.AddressIn;
          pSubnetMaskString        := inet_ntoa (pAddrSubnetMask.Sin_Addr);
          SubnetMask               := pSubnetMaskString;

          // Get the limited broadcast address
          pAddrBroadcast           := Buffer[i].iiBroadCastAddress.AddressIn;
          pLimBroadcastString      := inet_ntoa (pAddrBroadcast.Sin_Addr);
          AddrLimitedBroadcast     := pLimBroadcastString;

          // Calculate the net and the directed broadcast address
          NetAddrDummy.S_addr      := Buffer[i].iiAddress.AddressIn.Sin_Addr.S_Addr;
          NetAddrDummy.S_addr      := NetAddrDummy.S_addr And Buffer[i].iiNetMask.AddressIn.Sin_Addr.S_Addr;
          DirBroadcastDummy.S_addr := NetAddrDummy.S_addr Or Not Buffer[i].iiNetMask.AddressIn.Sin_Addr.S_Addr;

          pNetAddrString           := inet_ntoa ((NetAddrDummy));
          AddrNet                  := pNetAddrString;

          pDirBroadcastString      := inet_ntoa ((DirBroadcastDummy));
          AddrDirectedBroadcast    := pDirBroadcastString;

          // From the evaluation of the Flags we receive more information
          InterfaceFlags           := Buffer[i].iiFlags;

          // Is the network interface up or down ?
          If (InterfaceFlags And IFF_UP) = IFF_UP THen IsInterfaceUp := True
                                                  Else IsInterfaceUp := False;

          // Does the network interface support limited broadcasts ?
          If (InterfaceFlags And IFF_BROADCAST) = IFF_BROADCAST THen BroadcastSupport := True
                                                                Else BroadcastSupport := False;

          // Is the network interface a loopback interface ?
          If (InterfaceFlags And IFF_LOOPBACK) = IFF_LOOPBACK THen IsLoopback := True
                                                              Else IsLoopback := False;
        end;
      end;
    end;
  Except
    Result := False;
  end;

  // Cleanup the mess
  CloseSocket (aSocket);
  WSACleanUp;
  Result := True;
end;

end.

Example call:

uses USock; 

Procedure TForm1.Button1Click(Sender: TObject);
Var i                 : Integer;
    aNetInterfaceList : tNetworkInterfaceList;
Begin
  If (GetNetworkInterfaces (aNetInterfaceList)) THen
  Begin
    Memo1.Clear;
    Memo1.Lines.Add (DateTimeToStr (Now)+ ' : ');

    For i := 0 to High (aNetInterfaceList) do
    Begin
      Memo1.Lines.Add ('');
      Memo1.Lines.Add ('#                          : ' + IntToStr(i));
      Memo1.Lines.Add ('Name                       : ' + aNetInterfaceList[i].ComputerName);
      Memo1.Lines.Add ('IP-Address                 : ' + aNetInterfaceList[i].AddrIP);
      Memo1.Lines.Add ('Subnet mask                : ' + aNetInterfaceList[i].SubnetMask);
      Memo1.Lines.Add ('Net address                : ' + aNetInterfaceList[i].AddrNet);
      Memo1.Lines.Add ('Limited broadcast address  : ' + aNetInterfaceList[i].AddrLimitedBroadcast);
      Memo1.Lines.Add ('Directed Broadcast address : ' + aNetInterfaceList[i].AddrDirectedBroadcast);
      Memo1.Lines.Add ('Interface up               : ' + BoolToStr (aNetInterfaceList[i].IsInterfaceUp, True));
      Memo1.Lines.Add ('Broadcast supported        : ' + BoolToStr (aNetInterfaceList[i].BroadcastSupport, True));
      Memo1.Lines.Add ('Loopback interface         : ' + BoolToStr (aNetInterfaceList[i].IsLoopback, True));
      Memo1.Lines.Add ('');
    end;
  end;
end;

The code apparently works, however it only return one network interface, the loopback (127.0.0.0), and it should return my network private interface also.

On this part of the code it always return only one interface available:

NoOfInterfaces := NoOfBytesReturned Div SizeOf (Interface_Info);

To work on XE2 I had to change the string used (AnsiString).

I have also tried using Winsock2 unit, and also tried using IdWinSock2 and the API calls from there.

On all cases the APIs worked and returned only the loopback interface.

Using another utility written on delphi I could get a this list, and the local IP 192.168.0.112 got listed, however this source code is not easy to use.

My question is: what is wrong?

Jan Doggen
  • 8,799
  • 13
  • 70
  • 144
Eduardo Elias
  • 1,742
  • 1
  • 22
  • 49

6 Answers6

5

Following Remy Lebeau sugestion and help documenting this thread I found this source code in delphi, tested with XP and W7, that brings the information using GetAdaptersInfo().

Credits to Brad Prendergast original post updated by Markus Humm final version

I have added the subnet mask reporting to make clear to newbies like me where the information is stored:

uses IpHlpApi, IpTypes;

procedure RetrieveLocalAdapterInformation(strings: TStrings);
var
  pAdapterInfo, pTempAdapterInfo: PIP_ADAPTER_INFO;
  AdapterInfo: IP_ADAPTER_INFO;
  BufLen: DWORD;
  Status: DWORD;
  strMAC: String;
  i: Integer;
begin
  strings.Clear;

  BufLen:= sizeof(AdapterInfo);
  pAdapterInfo:= @AdapterInfo;

  Status:= GetAdaptersInfo(nil, BufLen);
  pAdapterInfo:= AllocMem(BufLen);
  try
    Status:= GetAdaptersInfo(pAdapterInfo, BufLen);

    if (Status <> ERROR_SUCCESS) then
      begin
        case Status of
          ERROR_NOT_SUPPORTED:
            strings.Add('GetAdaptersInfo is not supported by the operating ' +
                        'system running on the local computer.');
          ERROR_NO_DATA:
            strings.Add('No network adapter on the local computer.');
        else
            strings.Add('GetAdaptersInfo failed with error #' + IntToStr(Status));
        end;
        Dispose(pAdapterInfo);
        Exit;
      end;

    while (pAdapterInfo <> nil) do
      begin
        strings.Add('Description: ' + pAdapterInfo^.Description);
        strings.Add('Name: ' + pAdapterInfo^.AdapterName);

        strMAC := '';
        for I := 0 to pAdapterInfo^.AddressLength - 1 do
            strMAC := strMAC + '-' + IntToHex(pAdapterInfo^.Address[I], 2);

        Delete(strMAC, 1, 1);
        strings.Add('MAC address: ' + strMAC);
        strings.Add('IP address: ' + pAdapterInfo^.IpAddressList.IpAddress.S);
        strings.Add('IP subnet mask: ' + pAdapterInfo^.IpAddressList.IpMask.S);
        strings.Add('Gateway: ' + pAdapterInfo^.GatewayList.IpAddress.S);
        strings.Add('DHCP enabled: ' + IntTOStr(pAdapterInfo^.DhcpEnabled));
        strings.Add('DHCP: ' + pAdapterInfo^.DhcpServer.IpAddress.S);
        strings.Add('Have WINS: ' + BoolToStr(pAdapterInfo^.HaveWins,True));
        strings.Add('Primary WINS: ' + pAdapterInfo^.PrimaryWinsServer.IpAddress.S);
        strings.Add('Secondary WINS: ' + pAdapterInfo^.SecondaryWinsServer.IpAddress.S);

        pTempAdapterInfo := pAdapterInfo;
        pAdapterInfo:= pAdapterInfo^.Next;
      if assigned(pAdapterInfo) then Dispose(pTempAdapterInfo);
    end;
  finally
    Dispose(pAdapterInfo);
  end;
end;
Eduardo Elias
  • 1,742
  • 1
  • 22
  • 49
  • This code is not allocating enough memory for `pAdapterInfo`. You need to reallocate `pAdapterInfo` if `GetAdaptersInfo()` reports an `ERROR_BUFFER_OVERFLOW` error. And the `AdapterInfo` variable is not used for anything useful, so you can get rid of it. – Remy Lebeau Oct 08 '14 at 23:20
4

Jan Schulz's code works fine when properly converted to unicode-friendly Delphi.

I've done some corrections:

  • As TOndrej has pointed, char must be converted to AnsiChar when needed. In this case, this only occurs in the Padding field of the SockAddr_Gen record, which was not only screwing the record, but also causing SizeOf(Interface_Info), and subsequently NoOfInterfaces, to return a wrong result. Since it's not really a character, it is better to define it as a byte.

  • Dropped PChars used to hold results of inet_ntoa calls, and assigning TNetworkInterface string fields directly.

  • Strings in TNetworkInterface are fine, because they are not passed to any api calls. Also, ComputerName is passed to GetComputerName api, which expects a PWideChar/PChar.


Unit USock;

Interface

Uses Windows, Winsock;


{ Unit to identify the network interfaces
  This code requires at least Win98/ME/2K, 95 OSR 2 or NT service pack #3
  as WinSock 2 is used (WS2_32.DLL) }


// Constants found in manual on non-officially documented M$ Winsock functions
Const SIO_GET_INTERFACE_LIST = $4004747F;
      IFF_UP                 = $00000001;
      IFF_BROADCAST          = $00000002;
      IFF_LOOPBACK           = $00000004;
      IFF_POINTTOPOINT       = $00000008;
      IFF_MULTICAST          = $00000010;


Type SockAddr_Gen          = Packed Record
                               AddressIn             : SockAddr_In;
                               Padding               : Packed Array [0..7] of Byte;
                             end;

     Interface_Info        = Record
                               iiFlags               : u_Long;
                               iiAddress             : SockAddr_Gen;
                               iiBroadcastAddress    : SockAddr_Gen;
                               iiNetmask             : SockAddr_Gen;
                             end;

     tNetworkInterface     = Record
                               ComputerName          : String;
                               AddrIP                : String;
                               SubnetMask            : String;
                               AddrNet               : String;
                               AddrLimitedBroadcast  : String;
                               AddrDirectedBroadcast : String;
                               IsInterfaceUp         : Boolean;
                               BroadcastSupport      : Boolean;
                               IsLoopback            : Boolean;
                             end;

     tNetworkInterfaceList = Array of tNetworkInterface;


Function WSAIoctl (aSocket              : TSocket;
                   aCommand             : DWord;
                   lpInBuffer           : Pointer;
                   dwInBufferLen        : DWord;
                   lpOutBuffer          : Pointer;
                   dwOutBufferLen       : DWord;
                   lpdwOutBytesReturned : LPDWord;
                   lpOverLapped         : Pointer;
                   lpOverLappedRoutine  : Pointer) : Integer; stdcall; external 'WS2_32.DLL';

Function GetNetworkInterfaces (Var aNetworkInterfaceList : tNetworkInterfaceList): Boolean;


implementation


Function GetNetworkInterfaces (Var aNetworkInterfaceList : tNetworkInterfaceList): Boolean;
// Returns a complete list the of available network interfaces on a system (IPv4)
// Copyright by Dr. Jan Schulz, 23-26th March 2007
// This version can be used for free and non-profit projects. In any other case get in contact
// Written with information retrieved from MSDN
// www.code10.net
Var aSocket             : TSocket;
    aWSADataRecord      : WSAData;
    NoOfInterfaces      : Integer;
    NoOfBytesReturned   : u_Long;
    InterfaceFlags      : u_Long;
    NameLength          : DWord;
    pAddrIP             : SockAddr_In;
    pAddrSubnetMask     : SockAddr_In;
    pAddrBroadcast      : Sockaddr_In;
    DirBroadcastDummy   : In_Addr;
    NetAddrDummy        : In_Addr;
    Buffer              : Array [0..30] of Interface_Info;
    i                   : Integer;
Begin
  Result := False;
  SetLength (aNetworkInterfaceList, 0);

  // Startup of old the WinSock
  // WSAStartup ($0101, aWSADataRecord);

  // Startup of WinSock2
  WSAStartup(MAKEWORD(2, 0), aWSADataRecord);

  // Open a socket
  aSocket := Socket (AF_INET, SOCK_STREAM, 0);

  // If impossible to open a socket, not worthy to go any further
  If (aSocket = INVALID_SOCKET) THen Exit;

  Try
    If WSAIoCtl (aSocket, SIO_GET_INTERFACE_LIST, NIL, 0,
                 @Buffer, 1024, @NoOfBytesReturned, NIL, NIL) <> SOCKET_ERROR THen
    Begin
      NoOfInterfaces := NoOfBytesReturned  Div SizeOf (Interface_Info);
      SetLength (aNetworkInterfaceList, NoOfInterfaces);

      // For each of the identified interfaces get:
      For i := 0 to NoOfInterfaces - 1 do
      Begin

        With aNetworkInterfaceList[i] do
        Begin

          // Get the name of the machine
          NameLength := MAX_COMPUTERNAME_LENGTH + 1;
          SetLength (ComputerName, NameLength)  ;
          If Not GetComputerName (PChar (Computername), NameLength) THen ComputerName := '';

          // Get the IP address
          pAddrIP                  := Buffer[i].iiAddress.AddressIn;
          AddrIP                   := string(inet_ntoa (pAddrIP.Sin_Addr));

          // Get the subnet mask
          pAddrSubnetMask          := Buffer[i].iiNetMask.AddressIn;
          SubnetMask               := string(inet_ntoa (pAddrSubnetMask.Sin_Addr));

          // Get the limited broadcast address
          pAddrBroadcast           := Buffer[i].iiBroadCastAddress.AddressIn;
          AddrLimitedBroadcast     := string(inet_ntoa (pAddrBroadcast.Sin_Addr));

          // Calculate the net and the directed broadcast address
          NetAddrDummy.S_addr      := Buffer[i].iiAddress.AddressIn.Sin_Addr.S_Addr;
          NetAddrDummy.S_addr      := NetAddrDummy.S_addr And Buffer[i].iiNetMask.AddressIn.Sin_Addr.S_Addr;
          DirBroadcastDummy.S_addr := NetAddrDummy.S_addr Or Not Buffer[i].iiNetMask.AddressIn.Sin_Addr.S_Addr;

          AddrNet                  := string(inet_ntoa ((NetAddrDummy)));
          AddrDirectedBroadcast    := string(inet_ntoa ((DirBroadcastDummy)));

          // From the evaluation of the Flags we receive more information
          InterfaceFlags           := Buffer[i].iiFlags;

          // Is the network interface up or down ?
          If (InterfaceFlags And IFF_UP) = IFF_UP THen IsInterfaceUp := True
                                                  Else IsInterfaceUp := False;

          // Does the network interface support limited broadcasts ?
          If (InterfaceFlags And IFF_BROADCAST) = IFF_BROADCAST THen BroadcastSupport := True
                                                                Else BroadcastSupport := False;

          // Is the network interface a loopback interface ?
          If (InterfaceFlags And IFF_LOOPBACK) = IFF_LOOPBACK THen IsLoopback := True
                                                              Else IsLoopback := False;
        end;
      end;
    end;
  Except
    //Result := False;
  end;

  // Cleanup the mess
  CloseSocket (aSocket);
  WSACleanUp;
  Result := True;
end;

end.
Community
  • 1
  • 1
JRL
  • 3,363
  • 24
  • 36
  • +1 But I'd prefer a real definition for SockAddr_Gen. One that did not use packed and used a variant record for the union. – David Heffernan Aug 22 '13 at 12:45
  • 1
    It is clear now that I wrongly updated the code to Unicode. This function, as provided here, works as mentioned and detected all the interfaces in my computer now, giving the right IPs. – Eduardo Elias Aug 22 '13 at 18:32
3

For what its worth, if you need the broadcast IP for a specific adapter, you can use SIO_GET_BROADCAST_ADDRESS instead.

With that said, a non-Winsock solution would be to use GetAdaptersInfo() or GetAdaptersAddresses() instead. This way, you don't have to create a SOCKET to get the info, you can enumerate both IPv4 and IPv6 adapters at the same time, as well as other adapters that Winsock does not recognize.

For GetAdaptersInfo(), the IP_ADAPTER_INFO.IpAddressList list contains IPv4 IPs and Subnet masks (on XP+, uni-directional adapters are included in the output, but you can use GetUniDirectionalAdapterInfo() to filter them out).

For GetAdaptersAddresses(), the IP_ADAPTER_ADDRESSES.FirstUnicastAddress list contains both IPv4 and IPv6 IPs, and IPv4 Subnet masks on Vista+. For XP and earlier, you can use GetIpAddrTable() to retrieve IPv4 Subnet masks and match them to the IPv4 IPs from GetAdaptersAddresses().

Once you have an IPv4 IP and Subnet mask, calculating its Broadcast IP is very simple:

BroadcastIP := (IP and SubnetMask) or (not SubnetMask);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I could not find much source code example on using these API calls, so I have got one that I tested and posted as answer to help documenting, however do not cover all your suggestion – Eduardo Elias Aug 22 '13 at 20:09
  • 3
    @eelias: If you download the latest Indy 10 source code from SVN or mirror, the `TIdStackWindows.AddLocalAddressesToList()` method in `IdStackWindows.pas` demonstrates these API functions (the code is currently commented out, but it is fully working code if you enable the `{$DEFINE USE_IPHLPAPI}` statement on line 320). – Remy Lebeau Aug 22 '13 at 21:13
  • (in current sources it seems to be enabled) – Marco van de Voort Mar 29 '16 at 10:50
  • @MarcovandeVoort: yes, the IPHLPAPI logic is now enabled by default, and has been for awhile. – Remy Lebeau Mar 29 '16 at 16:19
1

As you have changed String declarations to AnsiString, also change Char declarations to AnsiChar.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
1

Update for Delphi 10.2 Tokyo supported.

procedure TForm4.RetrieveLocalAdapterInformation;
var
  pAdapterInfo: PIP_ADAPTER_INFO;
  AdapterInfo: IP_ADAPTER_INFO;
  BufLen: DWORD;
  Status: DWORD;
  strMAC: String;
  i: Integer;

  strings: TStrings;
begin
  strings:= Tstringlist.create;
  strings.Clear;

  BufLen:= sizeof(AdapterInfo);
  pAdapterInfo:= @AdapterInfo;

  Status:= GetAdaptersInfo(nil, BufLen);
  pAdapterInfo:= AllocMem(BufLen);
  try
    Status:= GetAdaptersInfo(pAdapterInfo, BufLen);

    if (Status <> ERROR_SUCCESS) then
      begin
        case Status of
          ERROR_NOT_SUPPORTED:
            strings.Add('GetAdaptersInfo is not supported by the operating ' +
                        'system running on the local computer.');
          ERROR_NO_DATA:
            strings.Add('No network adapter on the local computer.');
        else
            strings.Add('GetAdaptersInfo failed with error #' + IntToStr(Status));
        end;
        Dispose(pAdapterInfo);
        Exit;
      end;

    while (pAdapterInfo <> nil) do
      begin
      memo1.Lines.Add('');
         memo1.Lines.Add('Description: ------------------------' + pAdapterInfo^.Description);
         memo1.Lines.Add('Name: ' + pAdapterInfo^.AdapterName);

        strMAC := '';
        for I := 0 to pAdapterInfo^.AddressLength - 1 do
            strMAC := strMAC + '-' + IntToHex(pAdapterInfo^.Address[I], 2);

        Delete(strMAC, 1, 1);
         memo1.Lines.Add('MAC address: ' + strMAC);
         memo1.Lines.Add('IP address: ' + pAdapterInfo^.IpAddressList.IpAddress.S);
         memo1.Lines.Add('IP subnet mask: ' + pAdapterInfo^.IpAddressList.IpMask.S);
         memo1.Lines.Add('Gateway: ' + pAdapterInfo^.GatewayList.IpAddress.S);
         memo1.Lines.Add('DHCP enabled: ' + IntTOStr(pAdapterInfo^.DhcpEnabled));
         memo1.Lines.Add('DHCP: ' + pAdapterInfo^.DhcpServer.IpAddress.S);
         memo1.Lines.Add('Have WINS: ' + BoolToStr(pAdapterInfo^.HaveWins,True));
         memo1.Lines.Add('Primary WINS: ' + pAdapterInfo^.PrimaryWinsServer.IpAddress.S);
         memo1.Lines.Add('Secondary WINS: ' + pAdapterInfo^.SecondaryWinsServer.IpAddress.S);

        pAdapterInfo:= pAdapterInfo^.Next;
    end;
  finally
    Dispose(pAdapterInfo);
    strings.free;
  end;
end;

procedure TForm4.Button1Click(Sender: TObject);
begin
   RetrieveLocalAdapterInformation//
end;
Charin
  • 11
  • 1
1

Updated to fix overwrite of pAdapterInfo pointer while looping the linked list

procedure TForm4.RetrieveLocalAdapterInformation;
var
  pAdapterInfo: PIP_ADAPTER_INFO; // Linked list of adapters
  pAdapter: PIP_ADAPTER_INFO; // Single adapter
  BufLen: DWORD;
  Status: DWORD;
  strMAC: String;
  i: Integer;
begin
  memo1.Clear;

  // Make an initial call to GetAdaptersInfo to get the necessary size
  // of the linked list
  GetAdaptersInfo(nil, BufLen);
  pAdapterInfo := AllocMem(BufLen);
  try
    Status := GetAdaptersInfo(pAdapterInfo, BufLen);

    if (Status <> ERROR_SUCCESS) then
    begin
      case Status of
        ERROR_NOT_SUPPORTED:
          memo1.Lines.Add('GetAdaptersInfo is not supported by the operating ' +
                      'system running on the local computer.');
        ERROR_NO_DATA:
          memo1.Lines.Add('No network adapter on the local computer.');
      else
        memo1.Lines.Add('GetAdaptersInfo failed with error #' + IntToStr(Status));
      end;

      Exit;
    end;

    pAdapter := pAdapterInfo;

    while (pAdapter <> nil) do
    begin
      memo1.Lines.Add('');
      memo1.Lines.Add('Description: ------------------------' + pAdapter^.Description);
      memo1.Lines.Add('Name: ' + pAdapter^.AdapterName);

      strMAC := '';
      for I := 0 to pAdapter^.AddressLength - 1 do
        strMAC := strMAC + '-' + IntToHex(pAdapter^.Address[I], 2);

      Delete(strMAC, 1, 1);
      memo1.Lines.Add('MAC address: ' + strMAC);
      memo1.Lines.Add('IP address: ' + pAdapter^.IpAddressList.IpAddress.S);
      memo1.Lines.Add('IP subnet mask: ' + pAdapter^.IpAddressList.IpMask.S);
      memo1.Lines.Add('Gateway: ' + pAdapter^.GatewayList.IpAddress.S);
      memo1.Lines.Add('DHCP enabled: ' + IntToStr(pAdapter^.DhcpEnabled));
      memo1.Lines.Add('DHCP: ' + pAdapter^.DhcpServer.IpAddress.S);
      memo1.Lines.Add('Have WINS: ' + BoolToStr(pAdapter^.HaveWins,True));
      memo1.Lines.Add('Primary WINS: ' + pAdapter^.PrimaryWinsServer.IpAddress.S);
      memo1.Lines.Add('Secondary WINS: ' + pAdapter^.SecondaryWinsServer.IpAddress.S);

      pAdapter := pAdapter^.Next;
    end;
  finally
    FreeMem(pAdapterInfo);
  end;
end

;

  • I get many errors trying out your code sample. What modules are you using for this? – mfa Oct 12 '22 at 03:00