Всё началось с простого вопроса: как через WinApi в Delphi работать с сетевыми адаптерами, например включить или отключить сетевой интерфейс, узнать или изменить IP-адрес, проверить наличие Wi-Fi и т.д.? Быстрый гуглинг вывел на данный раздел MSDN: IP Helper
Пока разбирался, написал несколько простейший примеров использования основных функций, которые в данной статье и представлены.
Внимание! В Delphi XE3 для работы с представленными далее сетевым API необходимо подключить библиотеки Winapi.IpHlpApi, Winapi.Winsock2, Winapi.IpTypes и Winapi.IpRtrMib , в которых содержатся необходимые для работы типы и функции.
program ipconfig;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Variants,
System.Classes,
Winapi.Windows,
Winapi.Messages,
Winapi.IpHlpApi,
Пока разбирался, написал несколько простейший примеров использования основных функций, которые в данной статье и представлены.
Внимание! В Delphi XE3 для работы с представленными далее сетевым API необходимо подключить библиотеки Winapi.IpHlpApi, Winapi.Winsock2, Winapi.IpTypes и Winapi.IpRtrMib , в которых содержатся необходимые для работы типы и функции.
Функция GetAdaptersInfo
Извлекает информацию о сетевых адаптерах в системе. Следует помнить, что эта функция работает только с IPv4, поэтому не рекомендуется её использовать в Windows XP и старше.
Т.к. почитать описание вы можете и по ссылке, перейду к примеру на Delphi XE3.
Данная программа выведет список всех сетевых адаптеров:
Данная программа выведет список всех сетевых адаптеров:
program ipconfig;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Variants,
System.Classes,
Winapi.Windows,
Winapi.Messages,
Winapi.IpHlpApi,
Winapi.IpRtrMib
Winapi.IpTypes,
Web.Win.Sockets;
const
// Типы адаптеров
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_TYPE_WIRELESS = 71;
var
IFs, pAdapt: PIP_ADAPTER_INFO;
Err, AdapterInfoSize: Cardinal;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
//перезапускаем интерфейс:
AdapterInfoSize:=0;
Err:=GetAdaptersInfo(nil, AdapterInfoSize);
if (Err<>0) and (Err<>ERROR_BUFFER_OVERFLOW) then
begin
writeln('Error');
exit;
end;
//Получить информацию об устройствах.
Ifs := PIP_ADAPTER_INFO(GlobalAlloc(GPTR, AdapterInfoSize));
GetAdaptersInfo(IFs, AdapterInfoSize);
pAdapt := IFs;
while pAdapt<>nil do
begin
case pAdapt.Type_ of
MIB_IF_TYPE_ETHERNET: writeln('Ethernet adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_TOKENRING: writeln('Token Ring adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_FDDI: writeln('FDDI adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_PPP: writeln('PPP adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_LOOPBACK: writeln('Loopback adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_SLIP: writeln('Slip adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_OTHER: writeln('Other adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_WIRELESS: writeln('Wireless adapter '+pAdapt.AdapterName)
Winapi.IpTypes,
Web.Win.Sockets;
const
// Типы адаптеров
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_TYPE_WIRELESS = 71;
var
IFs, pAdapt: PIP_ADAPTER_INFO;
Err, AdapterInfoSize: Cardinal;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
//перезапускаем интерфейс:
AdapterInfoSize:=0;
Err:=GetAdaptersInfo(nil, AdapterInfoSize);
if (Err<>0) and (Err<>ERROR_BUFFER_OVERFLOW) then
begin
writeln('Error');
exit;
end;
//Получить информацию об устройствах.
Ifs := PIP_ADAPTER_INFO(GlobalAlloc(GPTR, AdapterInfoSize));
GetAdaptersInfo(IFs, AdapterInfoSize);
pAdapt := IFs;
while pAdapt<>nil do
begin
case pAdapt.Type_ of
MIB_IF_TYPE_ETHERNET: writeln('Ethernet adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_TOKENRING: writeln('Token Ring adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_FDDI: writeln('FDDI adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_PPP: writeln('PPP adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_LOOPBACK: writeln('Loopback adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_SLIP: writeln('Slip adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_OTHER: writeln('Other adapter '+pAdapt.AdapterName);
MIB_IF_TYPE_WIRELESS: writeln('Wireless adapter '+pAdapt.AdapterName)
else writeln('Other adapter '+pAdapt.AdapterName);
end;
pAdapt := pAdapt.Next;
end;
GlobalFree(Cardinal(IFs));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
end;
pAdapt := pAdapt.Next;
end;
GlobalFree(Cardinal(IFs));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
Функция GetAdaptersAddresses
Данная функция возвращает подробную информацию о сетевых адаптерах: адреса, имена, тип и т.д. и т.п., структура выходной записи имеет более 30 полей. Особенно приятно что функция в отличии от предыдущей возвращает и friendlyname - "человеческое" имя сетевого адаптера, которое мы можем видеть в списке сетевых подключений в виндовс. Итак, пример, которые возвращает список всех человеческих имен всех адаптеров:
procedure GetAdaptersAddressesTest;
const
WORKING_BUFFER_SIZE = 15000;
MAX_ITERATION = 3;
var
dwSize: Cardinal;
dwRetVal: Cardinal;
pAddresses, pCurrAdress: PIP_ADAPTER_ADDRESSES;
outbuffr: integer;
_p: Pointer;
iteration: Integer;
begin
dwSize:=0;
dwRetVal:=0;
iteration:=0;
outbuffr:= WORKING_BUFFER_SIZE;
_p:= @outbuffr;
repeat
pAddresses:=PIP_ADAPTER_ADDRESSES(GlobalAlloc(GPTR,WORKING_BUFFER_SIZE));
dwRetVal:=GetAdaptersAddresses(AF_UNSPEC,0,nil,pAddresses,_p);
if dwRetVal=ERROR_BUFFER_OVERFLOW then
begin
GlobalFree(cardinal(pAddresses));
pAddresses:=NIL;
end
else break;
Inc(iteration);
until (dwRetVal=ERROR_BUFFER_OVERFLOW) and (iteration<=MAX_ITERATION);
if dwRetVal=NO_ERROR then
begin
pCurrAdress:=pAddresses;
while pCurrAdress<>nil do
begin
Writeln(pCurrAdress.FriendlyName);
pCurrAdress:=pCurrAdress.Next;
end;
GlobalFree(cardinal(pCurrAdress));
end;
GlobalFree(cardinal(pAddresses));
end;
const
WORKING_BUFFER_SIZE = 15000;
MAX_ITERATION = 3;
var
dwSize: Cardinal;
dwRetVal: Cardinal;
pAddresses, pCurrAdress: PIP_ADAPTER_ADDRESSES;
outbuffr: integer;
_p: Pointer;
iteration: Integer;
begin
dwSize:=0;
dwRetVal:=0;
iteration:=0;
outbuffr:= WORKING_BUFFER_SIZE;
_p:= @outbuffr;
repeat
pAddresses:=PIP_ADAPTER_ADDRESSES(GlobalAlloc(GPTR,WORKING_BUFFER_SIZE));
dwRetVal:=GetAdaptersAddresses(AF_UNSPEC,0,nil,pAddresses,_p);
if dwRetVal=ERROR_BUFFER_OVERFLOW then
begin
GlobalFree(cardinal(pAddresses));
pAddresses:=NIL;
end
else break;
Inc(iteration);
until (dwRetVal=ERROR_BUFFER_OVERFLOW) and (iteration<=MAX_ITERATION);
if dwRetVal=NO_ERROR then
begin
pCurrAdress:=pAddresses;
while pCurrAdress<>nil do
begin
Writeln(pCurrAdress.FriendlyName);
pCurrAdress:=pCurrAdress.Next;
end;
GlobalFree(cardinal(pCurrAdress));
end;
GlobalFree(cardinal(pAddresses));
end;
Функции GetIfEntry и GetIfTable
GetIfTable служит для получения списка сетевых интерфейсов (не путать с адаптерами!). А GetIfEntry для подробной информации о конкретном интерфейсе;
Пример на процедуры на Delphi XE3, которая получает список всех интерфейсов и выводит имя каждого:
procedure GetIfEntryTest;
var
// Объявляем и инициализируем переменные
pMibIfRow: PMIB_IFROW;
ifTable: PMIB_IFTABLE;
dwSize: Cardinal;
dwRetVal: Cardinal;
str: array [0..255] of char;
i,j: integer;
begin
dwSize:=0;
dwRetVal:=0;
// Выделяем память для указателей
pMibIfRow:= PMIB_IFROW(GlobalAlloc(GPTR, SizeOf(MIB_IFROW)));
ifTable:= PMIB_IFTABLE(GlobalAlloc(GPTR, SizeOf(MIB_IFTABLE)));
dwSize:=SizeOf(MIB_IFTABLE);
// Перед вызовом GetIfEntry мы вызовем GetIfTable чтобы убедиться
// что тут есть что получать
// Сделаем инициализационный вызов GetIfTable, чтобы получить
// необходимый размер в dwSize
if GetIfTable(nil, dwSize, False)= ERROR_INSUFFICIENT_BUFFER then
begin
GlobalFree(Cardinal(iftable));
ifTable:= PMIB_IFTABLE(GlobalAlloc(GPTR, dwSize));
end;
// Делаем второй вызов GetIfTable для получения актуальной информации
// которую мы хотим.
dwRetVal:=GetIfTable(ifTable, dwSize, False);
if dwRetVal=NO_ERROR then
begin
if ifTable.dwNumEntries>0 then
begin
for j := 1 to ifTable.dwNumEntries do
begin
pMibIfRow.dwIndex:=j;
dwRetVal:=GetIfEntry(pMibIfRow);
if dwRetVal = NO_ERROR then
begin
write(pMibIfRow.dwIndex);
for i:=0 to 255 do
str[i]:=chr(pMibIfRow.bDescr[i]);
Writeln(str);
end
else begin
writeln('Ошибка GetIfEntry failed');
//Тут вы можете использовать FormatMessage чтобы
//понять почему вылезла ошибка
end;
end;
end
else begin
writeln('Ошибка GetIfTable');
end;
end;
GlobalFree(Cardinal(pMibIfRow));
GlobalFree(Cardinal(ifTable));
end;
Дання функция задаёт параметры сетевого интерфейса.В качестве входного параметра служит переменная типа _MIB_IFROW. Этот тип описывает структуру сетевого интерфейса, аналогичную тому, указатель на которую использует функция GetIfEntry. Т.е PMIB_IFROW = ^_MIB_IFROW.
var
// Объявляем и инициализируем переменные
pMibIfRow: PMIB_IFROW;
ifTable: PMIB_IFTABLE;
dwSize: Cardinal;
dwRetVal: Cardinal;
str: array [0..255] of char;
i,j: integer;
begin
dwSize:=0;
dwRetVal:=0;
// Выделяем память для указателей
pMibIfRow:= PMIB_IFROW(GlobalAlloc(GPTR, SizeOf(MIB_IFROW)));
ifTable:= PMIB_IFTABLE(GlobalAlloc(GPTR, SizeOf(MIB_IFTABLE)));
dwSize:=SizeOf(MIB_IFTABLE);
// Перед вызовом GetIfEntry мы вызовем GetIfTable чтобы убедиться
// что тут есть что получать
// Сделаем инициализационный вызов GetIfTable, чтобы получить
// необходимый размер в dwSize
if GetIfTable(nil, dwSize, False)= ERROR_INSUFFICIENT_BUFFER then
begin
GlobalFree(Cardinal(iftable));
ifTable:= PMIB_IFTABLE(GlobalAlloc(GPTR, dwSize));
end;
// Делаем второй вызов GetIfTable для получения актуальной информации
// которую мы хотим.
dwRetVal:=GetIfTable(ifTable, dwSize, False);
if dwRetVal=NO_ERROR then
begin
if ifTable.dwNumEntries>0 then
begin
for j := 1 to ifTable.dwNumEntries do
begin
pMibIfRow.dwIndex:=j;
dwRetVal:=GetIfEntry(pMibIfRow);
if dwRetVal = NO_ERROR then
begin
write(pMibIfRow.dwIndex);
for i:=0 to 255 do
str[i]:=chr(pMibIfRow.bDescr[i]);
Writeln(str);
end
else begin
writeln('Ошибка GetIfEntry failed');
//Тут вы можете использовать FormatMessage чтобы
//понять почему вылезла ошибка
end;
end;
end
else begin
writeln('Ошибка GetIfTable');
end;
end;
GlobalFree(Cardinal(pMibIfRow));
GlobalFree(Cardinal(ifTable));
end;
Функция SetIfEntry
Дання функция задаёт параметры сетевого интерфейса.В качестве входного параметра служит переменная типа _MIB_IFROW. Этот тип описывает структуру сетевого интерфейса, аналогичную тому, указатель на которую использует функция GetIfEntry. Т.е PMIB_IFROW = ^_MIB_IFROW.
Пригодится. Гуглю инфу, чтобы написать свою версию Tele2-оболочки 4G-модема. А то у них там индикатор мелкий и показывает только суммарный трафик за за месяц (а нужно за сутки, за определённый интервал и т.д.)
ОтветитьУдалить