2008-11-28 4 views
10

Я использую беспроводную карту 3G некоторое время, и каждый раз, когда я подключаюсь, мой антивирус запускает обновления.Обнаружение активации интернет-соединения с Delphi

Мне интересно, какой набор функций Win32 API, который я могу использовать для получения уведомления или запроса о событии подключения к Интернету?

И есть ли уже набор портированных заголовков для Delphi?

+1

Определить подключение к Интернету? Что такое * интернет? – 2008-11-28 15:57:58

+0

Я бы подумал, что это будет сетевой интерфейс, но я действительно не знаю, как Антивирус заражает его. – 2008-11-28 16:28:09

ответ

19

Я работал над проектом для запуска скрипта входа пользователя, когда он подключал нашу сеть через VPN. Для этого я написал вспомогательную единицу, которая извлекает информацию об адаптере и сохраняет ее в простой записи.

я затем настроить до уведомления реестра see here for how to do that in Delphi

Уведомление реестра был на HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces. Это событие уведомления срабатывает каждый раз, когда Windows получает новый IP-адрес или вносит какие-либо изменения в информацию о соединениях адаптеров. Когда это событие было запущено, я вызвал функцию (в приведенном ниже коде), чтобы получить обновленную информацию об адаптере. Я сравнил эту новую информацию с ранее записанной информацией ... что я должен был сохранить предыдущий запрос информации о адаптере, чтобы узнать, изменилось ли что-то.

Во всяком случае, вот мой помощник блок:

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 ansichar; 
    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 ansichar; 
    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. 

Чтобы использовать это устройство из другого блока, я создал следующую функцию, которая заполняется пользовательский типа, который называется TAdapterInfo (объявленной в моем основном блоке):

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; 

На совершенно сторона не e, я также использовал этот блок и почти точно такой же код, чтобы создать дубликат ifconfig -a, который can be found on github. Я в основном делал это как упражнение в обучении себя тому, как выполнить эту задачу.

3

Посмотрите на InternetGetConnectedState в WinINet.

Некоторые приложения могут также опросить известный сервер и ничего не делать, пока не получат действительное соединение.

12
uses WinInet; 

function IsConnected: boolean; 
const 
    // local system uses a modem to connect to the Internet. 
    INTERNET_CONNECTION_MODEM  = 1; 
    // local system uses a local area network to connect to the Internet. 
    INTERNET_CONNECTION_LAN  = 2; 
    // local system uses a proxy server to connect to the Internet. 
    INTERNET_CONNECTION_PROXY  = 4; 
    // local system's modem is busy with a non-Internet connection. 
    INTERNET_CONNECTION_MODEM_BUSY = 8; 

var 
    dwConnectionTypes : DWORD; 
begin 
    dwConnectionTypes := INTERNET_CONNECTION_MODEM + 
         INTERNET_CONNECTION_LAN + 
         INTERNET_CONNECTION_PROXY; 
    Result := InternetGetConnectedState(@dwConnectionTypes,0); 
end; 
+0

Yup. Это то, что я использую. Я не уверен, что его 100% -ная надежность. – lkessler 2008-12-01 20:42:06

+0

Это не на 100% надежный. – Mick 2009-02-19 15:19:13

2

Вот пример того, как использовать вспомогательный блок. Это из небольшого проекта, который я написал для эмуляции «ifconfig -a». Это консольный проект приложения.

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 
    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.