Rileva un'attivazione della connessione Internet con Delphi
-
11-07-2019 - |
Domanda
Uso una scheda wireless 3G da un po 'di tempo e ogni volta che mi collego, il mio antivirus attiva gli aggiornamenti.
Mi chiedo quale sia il set di funzioni dell'API Win32 che posso usare per ricevere notifiche o interrogazioni sull'evento di una connessione Internet in arrivo?
E c'è già una serie di intestazioni portate per Delphi?
Soluzione
Ho lavorato a un progetto per eseguire uno script di accesso di un utente ogni volta che si connettevano alla nostra rete tramite VPN. Per fare ciò, ho scritto un'unità di supporto che recupera le informazioni sull'adattatore e le memorizza in un semplice record.
Ho quindi impostato una notifica di registro, vedi qui per come farlo in Delphi
La notifica del registro era su HKLM \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Parameters \ Interfaces
. Questo evento di notifica viene generato ogni volta che Windows ottiene un nuovo indirizzo IP o apporta qualsiasi tipo di modifica alle informazioni sulla connessione degli adattatori. Quando è stato generato questo evento, ho chiamato la funzione (nel codice seguente) per recuperare informazioni aggiornate sull'adattatore. Ho confrontato queste nuove informazioni con le mie informazioni precedentemente registrate ... il che significa che dovevo salvare la precedente query di informazioni sull'adattatore per sapere se qualcosa era cambiato.
Comunque, ecco la mia unità di supporto:
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.
Per utilizzare questa unità da un'altra unità, ho creato la seguente funzione, che popolava un tipo personalizzato chiamato TAdapterInfo
(dichiarato nella mia unità principale):
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;
In una nota a margine, ho anche usato questa unità e quasi lo stesso codice per creare un duplicato di ifconfig -a
, che può essere trovato su github . L'ho fatto principalmente come un esercizio per insegnare a me stesso come svolgere questo compito.
Altri suggerimenti
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;
Guarda InternetGetConnectedState in WinINet.
Alcune applicazioni potrebbero anche eseguire il polling per un server noto e non fare nulla fino a quando non ottengono una connessione valida.
Ecco un esempio pratico di come utilizzare l'unità di supporto. Viene da un piccolo progetto che ho scritto per emulare "ifconfig -a". Questo è un progetto di applicazione console.
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.