Get information about the installed network adapters

前端 未结 5 1152
无人共我
无人共我 2020-12-28 11:23

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.

Fo

相关标签:
5条回答
  • 2020-12-28 11:34

    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.
    
    0 讨论(0)
  • 2020-12-28 11:42

    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);
    
    0 讨论(0)
  • 2020-12-28 11:51

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

    0 讨论(0)
  • 2020-12-28 11:53

    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;
    
    0 讨论(0)
  • 2020-12-28 11:57

    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;
    
    0 讨论(0)
提交回复
热议问题