15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Получение IP-адреса и маски для всех сетевых интерфейсов.

Автор: Giannis Sampaziotis

Существует множество методов получения IP адреса компьютера. Но данный пример представляет наиболее корректный способ получения всех адресов, сетевых масок, broadcast адресов и статусов для всех интерфейсов включая циклический 127.0.0.1 - требует WinSock 2.

Совместимость: Delphi 3.х (или выше)

Это завершённый Delphi компонент. Для его использования достаточно вызвать :

   EnumInterfaces(var s string): Boolean;

которая вернёт строку, разделённую CRLF и содержащую всё, нужную нам информацию.

--------------------------------------------------------------------

unit USock;

interface

uses Windows, Winsock;

{

  Если Вы поместите строку результатов в wide TMEMO (в его свойство memo.lines.text)
  то никаких результатов не увидите.

  Тестировалось на Win98/ME/2K, 95 OSR 2 и NT service
  pack #3 , потому что используется WinSock 2 (WS2_32.DLL)

}

function EnumInterfaces(var sInt: string): Boolean;

{ функция WSAIOCtl импортируется из Winsock 2.0 - Winsock 2 доступен }
{ только в Win98/ME/2K и 95 OSR2, NT srv pack #3 }

function WSAIoctl(s: TSocket; cmd: DWORD; lpInBuffer: PCHAR; dwInBufferLen:
  DWORD;
  lpOutBuffer: PCHAR; dwOutBufferLen: DWORD;
  lpdwOutBytesReturned: LPDWORD;
  lpOverLapped: POINTER;
  lpOverLappedRoutine: POINTER): Integer; stdcall; external 'WS2_32.DLL';

{ Константы взятые из заголовка C файлов }

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;
    filler: packed array[0..7] of char;
  end;

type INTERFACE_INFO = packed record
    iiFlags: u_long; // Флаги интерфейса
    iiAddress: sockaddr_gen; // Адрес интерфейса
    iiBroadcastAddress: sockaddr_gen; // Broadcast адрес
    iiNetmask: sockaddr_gen; // Маска подсети
  end;

implementation

{-------------------------------------------------------------------

1. Открываем WINSOCK
2. Создаём сокет
3. Вызываем WSAIOCtl для доступа к сетевым интерфейсам
4. Для каждого интерфейса, получаем IP, MASK, BROADCAST, статус
5. Разделяем строку символом CRLF 
6. Конец :)

--------------------------------------------------------------------}

function EnumInterfaces(var sInt: string): Boolean;
var s: TSocket;
  wsaD: WSADATA;
  NumInterfaces: Integer;
  BytesReturned, SetFlags: u_long;
  pAddrInet: SOCKADDR_IN;
  pAddrString: PCHAR;
  PtrA: pointer;
  Buffer: array[0..20] of INTERFACE_INFO;
  i: Integer;
begin
  result := true;                                // Инициализируем переменную
  sInt := '';

  WSAStartup($0101, wsaD);                      // Запускаем WinSock
                                                // Здесь можно дабавить различные обработчики ошибки :)

  s := Socket(AF_INET, SOCK_STREAM, 0);          // Открываем сокет
  if (s = INVALID_SOCKET) then exit;

  try                                            // Вызываем WSAIoCtl
    PtrA := @bytesReturned;
    if (WSAIoCtl(s, SIO_GET_INTERFACE_LIST, nil, 0, @Buffer, 1024, PtrA, nil,
      nil)
      <> SOCKET_ERROR)
      then
    begin                                        // Если OK, то определяем количество существующих интерфейсов

      NumInterfaces := BytesReturned div SizeOf(INTERFACE_INFO);

      for i := 0 to NumInterfaces - 1 do        // Для каждого интерфейса
      begin
        pAddrInet := Buffer[i].iiAddress.addressIn;            // IP адрес
        pAddrString := inet_ntoa(pAddrInet.sin_addr);
        sInt := sInt + ' IP=' + pAddrString + ',';
        pAddrInet := Buffer[i].iiNetMask.addressIn;            // Маска подсети
        pAddrString := inet_ntoa(pAddrInet.sin_addr);
        sInt := sInt + ' Mask=' + pAddrString + ',';
        pAddrInet := Buffer[i].iiBroadCastAddress.addressIn;  // Broadcast адрес
        pAddrString := inet_ntoa(pAddrInet.sin_addr);
        sInt := sInt + ' Broadcast=' +  pAddrString + ',';

        SetFlags := Buffer[i].iiFlags;
        if (SetFlags and IFF_UP) = IFF_UP then
          sInt := sInt + ' Interface UP,'                    // Статус интерфейса up/down
        else
          sInt := sInt + ' Interface DOWN,';

        if (SetFlags and IFF_BROADCAST) = IFF_BROADCAST then  // Broadcasts
          sInt := sInt + ' Broadcasts supported,'              // поддерживает или
        else                                                  // не поддерживается
          sInt := sInt + ' Broadcasts NOT supported,';

        if (SetFlags and IFF_LOOPBACK) = IFF_LOOPBACK then    // Циклический или
          sInt := sInt + ' Loopback interface'
        else
          sInt := sInt + ' Network interface';                  // нормальный

        sInt := sInt + #13#10;                                // CRLF между каждым интерфейсом
      end;
    end;
  except
  end;
//
// Закрываем сокеты
//
  CloseSocket(s);
  WSACleanUp;
  result := false;
end;

end.