获取有关已安装网络适配器的信息

Posted

技术标签:

【中文标题】获取有关已安装网络适配器的信息【英文标题】:Get information about the installed network adapters 【发布时间】:2013-08-22 11:02:40 【问题描述】:

我在 Windows XP sp3 上使用 Delphi XE2 Update 4

我希望从已安装的网络适配器中获取尽可能多的信息,特别是广播 ip。

为此,我使用了来自 Jan Schulz 的这段代码,我得到了 from this article。

单位:

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.

调用示例:

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;

代码显然可以工作,但是它只返回一个网络接口,即环回 (127.0.0.0),它也应该返回我的网络专用接口。

在这部分代码中,它总是只返回一个可用的接口:

NoOfInterfaces := NoOfBytesReturned Div SizeOf (Interface_Info);

要在 XE2 上工作,我必须更改使用的字符串 (AnsiString)。

我也尝试过使用 Winsock2 单元,也尝试过使用 IdWinSock2 和那里的 API 调用。

在所有情况下,API 都有效并且只返回环回接口。

使用delphi编写的另一个实用程序,我可以得到一个这个列表,并且列出了本地IP 192.168.0.112,但是这个源代码并不好用。

我的问题是:怎么了?

【问题讨论】:

Loopback 实际上是 127.0.0.1。你的目标是什么?获取广播IP地址? 我的目标是从我的电脑连接的网络中获取广播 IP,例如 192.168.0.100。我知道它可以有很多 IP,但其中一个是我的本地网络。 这些答案能解决你的问题吗? 【参考方案1】:

根据 Remy Lebeau 的建议并帮助记录这个线程,我在 delphi 中找到了这个源代码,用 XP 和 W7 进行了测试,它使用 GetAdaptersInfo() 提供了信息。

感谢 Brad Prendergast original post 更新由 Markus Humm final version

我添加了子网掩码报告,以便像我这样的新手清楚信息的存储位置:

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;

【讨论】:

此代码没有为pAdapterInfo 分配足够的内存。如果GetAdaptersInfo() 报告ERROR_BUFFER_OVERFLOW 错误,您需要重新分配pAdapterInfo。而AdapterInfo 变量并没有用于任何有用的事情,所以你可以去掉它。【参考方案2】:

Jan Schulz 的代码在正确转换为对 unicode 友好的 Delphi 时可以正常工作。

我做了一些更正:

正如TOndrej 所指出的,char 必须在需要时转换为AnsiChar。在这种情况下,这只发生在SockAddr_Gen记录的Padding字段中,这不仅是在搞砸记录,还会导致SizeOf(Interface_Info)和随后的NoOfInterfaces返回错误的结果。由于它不是真正的字符,因此最好将其定义为byte

删除了用于保存inet_ntoa 调用结果的PChars,并直接分配TNetworkInterface 字符串字段。

Strings in TNetworkInterface 很好,因为它们不会传递给任何 api 调用。此外,ComputerName 被传递给 GetComputerName api,它需要 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.

【讨论】:

+1 但我更喜欢 SockAddr_Gen 的真实定义。一个不使用打包并使用变体记录的联合。 现在很明显,我错误地将代码更新为 Unicode。此处提供的此功能按上述方式工作,现在检测到我计算机中的所有接口,并提供正确的 IP。【参考方案3】:

不管怎样,如果您需要特定适配器的广播 IP,您可以改用 SIO_GET_BROADCAST_ADDRESS

话虽如此,非 Winsock 的解决方案是改用 GetAdaptersInfo()GetAdaptersAddresses()。这样,您不必创建SOCKET 来获取信息,您可以同时枚举 IPv4 和 IPv6 适配器,以及 Winsock 无法识别的其他适配器。

对于GetAdaptersInfo()IP_ADAPTER_INFO.IpAddressList 列表包含 IPv4 IP 和子网掩码(在 XP+ 上,单向适配器包含在输出中,但您可以使用 GetUniDirectionalAdapterInfo() 将它们过滤掉)。

对于GetAdaptersAddresses()IP_ADAPTER_ADDRESSES.FirstUnicastAddress 列表包含 IPv4 和 IPv6 IP,以及 Vista+ 上的 IPv4 子网掩码。对于 XP 和更早版本,您可以使用 GetIpAddrTable() 检索 IPv4 子网掩码并将它们与来自 GetAdaptersAddresses() 的 IPv4 IP 匹配。

一旦有了 IPv4 IP 和子网掩码,计算其广播 IP 就非常简单:

BroadcastIP := (IP and SubnetMask) or (not SubnetMask);

【讨论】:

我找不到太多关于使用这些 API 调用的源代码示例,所以我有一个我测试并发布作为帮助文档的答案,但不要涵盖您的所有建议 @eelias:如果你从SVN或镜像下载最新的Indy 10源代码,IdStackWindows.pas中的TIdStackWindows.AddLocalAddressesToList()方法演示了这些API函数(代码目前已注释掉,但完全如果您在第 320 行启用 $DEFINE USE_IPHLPAPI 语句,则工作代码)。 (在当前来源中似乎已启用) @MarcovandeVoort:是的,IPHLPAPI 逻辑现在默认启用,并且已经有一段时间了。【参考方案4】:

由于您已将 String 声明更改为 AnsiString,同时将 Char 声明更改为 AnsiChar。

【讨论】:

【参考方案5】:

支持 Delphi 10.2 Tokyo 的更新。

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;

【讨论】:

【参考方案6】:

更新以修复在循环链表时覆盖 pAdapterInfo 指针

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

;

【讨论】:

以上是关于获取有关已安装网络适配器的信息的主要内容,如果未能解决你的问题,请参考以下文章

vb.net 第一节 获取本机网络适配器的信息 GetAdaptersInfo

如何在 linux/Mac OSX 中获取网络适配器统计信息?

如何获取网络适配器索引?

应用程序的网络功能

IOException:网络适配器无法建立连接[重复]

获取设备列表