delphi winapi wininet internet-connection

Detecta una activación de conexión a Internet con Delphi



winapi wininet (4)

He estado usando una tarjeta inalámbrica 3G durante un tiempo y cada vez que me conecto, mi antivirus activa las actualizaciones.

Me pregunto, ¿cuál es el conjunto de funciones de la API de Win32 que puedo utilizar para recibir notificaciones o consultar sobre el evento de una conexión a Internet?

¿Y ya hay un conjunto de encabezados portados para Delphi?


Mire InternetGetConnectedState en WinINet.

Algunas aplicaciones también pueden sondear un servidor conocido y no hacer nada hasta que obtengan una conexión válida.


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;


Aquí hay un ejemplo práctico de cómo usar la unidad auxiliar. Es de un pequeño proyecto que escribí para emular "ifconfig -a". Este es un proyecto de aplicación de consola.

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.


Trabajé en un proyecto para ejecutar un script de inicio de sesión de un usuario cada vez que conectaban nuestra red a través de VPN. Para hacer esto, escribí una unidad auxiliar que recupera la información del adaptador y la almacena en un registro simple.

Luego configuré una notificación de registro, mire aquí cómo hacerlo en Delphi

La notificación de registro estaba en HKLM/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters/Interfaces . Este evento de notificación se activa cada vez que Windows obtiene una nueva dirección IP o realiza cualquier tipo de cambio en la información de conexión de un adaptador. Cuando se desencadenó este evento, llamé a la función (en el código siguiente) para recuperar información actualizada sobre el adaptador. Comparé esta nueva información con mi información previamente grabada ... lo que significa que tuve que guardar la consulta previa de información del adaptador para saber si algo había cambiado.

De todos modos, aquí está mi unidad de ayuda:

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.

Para usar esta unidad desde otra unidad, creé la siguiente función, que TAdapterInfo un tipo personalizado llamado TAdapterInfo (declarado en mi unidad principal):

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;

En una nota totalmente lateral, también usé esta unidad y casi el mismo código exacto para crear un duplicado de ifconfig -a , que se puede encontrar en github . Principalmente lo hice como un ejercicio para enseñarme a mí mismo cómo lograr esta tarea.