Немного объясню значение полей time и idle_time. Что означает когда сессия не активна? Представьте, вы к примеру открыли какой-то ресурс на удаленной машине, просто посмотреть, что в нем находится (к примеру имена файлов). В то время когда вы ничего не делаете, не копируете, не запускаете, не открываете файлы, сессия не активна, она ждет ваших действий. Как только вы начинаете копировать файл (опять же к примеру) с удаленной машины, сессия становится активной до окончания копирования.
Обратите внимание на поле key структуры TSessionInfo50, оно содержит уникальный идентификатор при помощи которого мы сможем завершить сессию. MSDN советует сохранить значение этого поля во временной переменной, что мы и сделаем. Создадим в разделе public массив SessionCloseKey: array [0..512] of SmallInt; В нем мы будем хранить все ключи для закрытия сессий в Windows 9x-Me. Тут очень интересный момент. Если вы посмотрите на тип key то заметите что он является Cardinal (unsigned long), а массив для хранения ключей я сделал с типом SmallInt (Short). Дело в том, что в функции NetSessionDel, которую мы рассмотрим чуть позже, значение, в которое мы должны будем передать ключ для закрытия сессии, имеет тип SmallInt (Short). Я так и не понял почему это так, либо недосмотр программистов Microsoft, либо это они просто так шутят ;).
Теперь добавим на форму ListView и назовем его lwSessions. Перейдем в режим редактирования и создадим пять колонок со следующими значениями Caption - Cname, UserName, Num_Opens, Time, Idle_Time. Соответственно вы поняли что в них будут отображаться имя компьютера, имя пользователя, кол-во открытых файлов, активное и неактивное время полученных нами сессий. Заметьте что активное и неактивное время сессий будет даваться нам в виде кол-ва секунд (тип Cardinal). Предлагаю написать небольшую функцию, задача которой будет преобразовывать кол-во секунд в более привычную форму отображения.
function TMainForm.CardinalToTimeStr(Value:Cardinal):String; var d,h,m,s: Real; begin d:=0; h:=0; m:=0; s:=Value; if s > 59 then begin m:=int(s / 60); s:=s-(m*60); end; if m > 59 then begin h:=int(m/60); m:=m-(h*60); end; if h > 23 then begin d:=int(h/24); h:=h-(d*24); end; Result:=''; if (d>0) then Result:=Result+floattostr(d)+' d. '; if (h<9) then Result:=Result+'0'+floattostr(h)+':' else Result:=Result+floattostr(h)+':'; if (m<9) then Result:=Result+'0'+floattostr(m)+':' else Result:=Result+floattostr(m)+':'; if (s<9) then Result:=Result+'0'+floattostr(s) else Result:=Result+floattostr(s); end;
Теперь добавим на форму кнопку и назовем ее btnGetSessions. Не забудьте добавить объявления функций и структур (про переименование функции для NT помните?). Вот сам код получения текущих сессий:
procedure TMainForm.btnGetSessionsClick(Sender: TObject); var OS: Boolean; FLibHandle : THandle; SessionInfo50: array [0..512] of TSessionInfo50; SessionInfo502 : PSessionInfo502Array; TotalEntries,EntriesReadNT: DWORD; EntriesRead,TotalAvial: Word; i:integer; begin lvSessions.Items.Clear; if not IsNT(OS) then Close; //Выясняем тип системы if OS then begin //Код для NT FLibHandle := LoadLibrary('NETAPI32.DLL'); if FLibHandle = 0 then Exit; @NetSessionEnumNT := GetProcAddress(FLibHandle, 'NetSessionEnum'); if not Assigned(NetSessionEnumNT) then begin FreeLibrary(FLibHandle); Exit; end; SessionInfo502 := nil; if NetSessionEnumNT(nil,nil,nil,502,@SessionInfo502,DWORD(-1),@entriesreadNT, @totalentries, nil)=0 then for i:=0 to EntriesReadNT-1 do begin with lvSessions.Items.Add do //Заполнение данными из структуры begin Caption := string(SessionInfo502^[i].sesi502_cname); //Имя компьютера SubItems.Add(SessionInfo502^[i].sesi502_username); //Имя пользователя SubItems.Add(IntToStr(SessionInfo502^[i].sesi502_num_opens)); //Открытых ресурсов SubItems.Add(CardinalToTimeStr(SessionInfo502^[i].Sesi502_Time)); //Время активное SubItems.Add(CardinalToTimeStr(SessionInfo502^[i].sesi502_idle_time)); //Время не активное end; end; end else begin //Код для Windows 9x-Me FLibHandle := LoadLibrary('SVRAPI.DLL'); if FLibHandle <> 0 then Exit; @NetSessionEnum := GetProcAddress(FLibHandle, 'NetSessionEnum'); if not Assigned(NetSessionEnum) then begin FreeLibrary(FLibHandle); Exit; end; if NetSessionEnum (nil,50,@SessionInfo50,SizeOf(SessionInfo50),@EntriesRead,@TotalAvial) = 0 then for i:=0 to EntriesRead-1 do begin with lvSessions.Items.Add do //Заполнение данными из структуры begin Caption := string(SessionInfo50[i].Sesi50_cname); //Имя компьютера SubItems.Add(SessionInfo50[i].Sesi50_username); //Имя пользователя SubItems.Add(IntToStr(SessionInfo50[i].sesi50_num_opens)); //Открытых ресурсов SubItems.Add(CardinalToTimeStr(SessionInfo50[i].Sesi50_Time)); //Время активное SubItems.Add(CardinalToTimeStr(SessionInfo50[i].sesi50_idle_time)); //Время не активное SessionCloseKey[i]:= SessionInfo50[i].sesi50_key; //Уникальный идентификатор для закрытия end; end; end; FreeLibrary(FLibHandle); end;
Обратите внимание на то, как я сохраняю ключи для закрытия сессий. Я их просто заношу в массив в том порядке, в каком были получены сами сессии. Это сделано для простоты. Если в списке, отображающем наши сессии, не применять сортировки, то порядковый номер выделенной для закрытия сессии и ее идентификатор в массиве совпадут.
Завершение сессий
Ну что же, теперь настало время рассмотреть механизм завершения открытых сессий. Для этого мы будем использовать функцию NetSessionDel.
Объявление функции для 9х - Ме Windows:
var NetSessionDel:function( pszServer : PChar; PszClientName : PChar; SReserved : SmallInt):DWORD; stdcall;
Параметры:
pszServer - должен содержать имя удаленного компьютера на котором должна
выполнится функция, если завершается сессия у себя то данному параметру нужно
присвоить NIL.
pszClientName - должен содержать имя клиента чья сессия завершается
sReserved - должен содержать уникальный ключ для завершения сессии (тот
который мы получили предыдущей функцией)
Объявление функции для Windows NT:
var NetSessionDel:function( ServerName, UncClientName, Username :PWChar):DWORD; stdcall;
Параметры:
ServerName - должен содержать имя удаленного компьютера на котором должна
выполнится функция, если завершается сессия у себя то данному параметру нужно
присвоить NIL.
uncClientName - должен содержать имя клиента чья сессия завершается, если
параметр NIL, завершатся все сессии указанные в параметре username
username - должен содержать имя пользователя чья сессия завершается, если
параметр NIL, завершатся все сессии указанные в параметре uncClientName
Как вы можете заметить, никаких структур данные функции не используют. Напишем процедуру которая будет завершать выбранную нами в lvSessions сессию по имени клиента. Для этого поместите на форму еще одну кнопку и назовите ее btnCloseSession. При нажатии на эту кнопку мы будем искать выделенную сессию и брать значение находящееся в колонке CName, к полученному нами значению прибавим '\\' (в варианте для NT, в варианте для 9x-Me оставим как есть) и передадим в качестве второго параметра функции. В качестве третьего параметра в версии кода для NT передадим NIL, а в версии кода для Windows 9x-Me тот самый уникальный ключ, сохраненный нами ранее в массиве. Он будет находится по номеру соответствующему порядковому номеру сессии в lvSessions (если вы конечно не применяли сортировку). Вот как этот код выглядит:
procedure TMainForm.btnCloseSessionClick(Sender: TObject); var OS: Boolean; FLibHandle : THandle; CNameNT: PWideChar; CName9x: PAnsiChar; Key:SmallInt; i: Integer; begin if not IsNT(OS) then Close; //Выясняем тип системы if not Assigned(lvSessions.Selected) then Exit; i:= lvSessions.Selected.Index; //Определяем номер выбранной сессии if OS then begin FLibHandle := LoadLibrary('NETAPI32.DLL'); if FLibHandle = 0 then Exit; @NetSessionDelNT := GetProcAddress(FLibHandle, 'NetSessionDel'); if not Assigned(NetSessionDelNT) then begin FreeLibrary(FLibHandle); Exit; end; //Преобразуем данные в требуемый вид CNameNT := PWChar(WideString('\\'+lvSessions.Items.Item[i].Caption)); NetSessionDelNT(nil,CNameNT,nil); end else begin FLibHandle := LoadLibrary('SVRAPI.DLL'); if FLibHandle = 0 then Exit; @NetSessionDel := GetProcAddress(FLibHandle, 'NetSessionDel'); if not Assigned(NetSessionDel) then begin FreeLibrary(FLibHandle); Exit; end; //Преобразуем данные в требуемый вид CName9x := PAnsiChar(lvSessions.Items.Item[i].Caption); key := SessionCloseKey[i]; //Берем ключ из массива NetSessionDel(nil,CName9x,Key); end; FreeLibrary(FLibHandle); end;
Думаю комментировать здесь нечего, поэтому сразу переходим к третьей части статьи.
Получение списка открытых файлов
Теперь я приведу способ получения списка открытых файлов на компьютере. Для этого рассмотрим функцию NetFileEnum.
Объявление функции для 9х - Ме Windows:
var NetFileEnum:function( pszServer, pszBasePath : PChar; sLevel : DWORD; pbBuffer : Pointer; cbBuffer : DWORD; pcEntriesRead, pcTotalAvail : Pointer):Integer; stdcall;
Параметры:
pszServer - должен содержать имя удаленного компьютера на котором должна
выполнится функция, если смотрим у себя то данному параметру нужно присвоить
NIL.
pszBasePath - должен содержать каталог открытые файлы из которого мы хотим
посмотреть, если мы хотим просмотреть все открытые файлы параметру нужно
присвоить NIL.
sLevel - должен содержать идентификатор структуры.
pbBuffer - должен содержать указатель на массив структур.
cbBuffer - должен содержать размер структуры.
pcEntriesRead - указатель на переменную содержащую общее кол-во структур
pcTotalAvial - не используется
Объявление функции для Windows NT:
var NetFileEnum:function( servername, basepath, username : PWChar; level : DWORD; bufptr : Pointer; prefmaxlen : DWORD; entriesread, totalentries, resume_handle : LPDWORD):DWORD; stdcall;
Параметры:
ServerName - должен содержать имя удаленного компьютера на котором должна
выполнится функция, если смотрим у себя то данному параметру нужно присвоить
NIL.
BasePath - должен содержать каталог открытые файлы из которого мы хотим
посмотреть, если мы хотим просмотреть все открытые файлы параметру нужно
присвоить NIL.
UserName - содержит указатель на строку содержащую имя пользователя о котором
мы хотим получить информацию, если нужно просмотреть всё, параметру нужно
присвоить NIL.
Level - должен содержать идентификатор структуры.
Bufptr - должен содержать адрес указателя на массив структур.
Prefmaxlen - должен содержать максимальную длину возвращенных данных в байтах,
если не ставить ограничение то данному параметру нужно присвоить DWORD(-1)
Entriesread - должен содержать указатель на переменную в которую запишется
количество общих ресурсов доступных на данный момент.
Totalentries - не используется
Resume_handle - не используется, должен быть NIL
Существует три типа структур использующихся функцией:
FILE_INFO_2 - используется под Windows NT
FILE_INFO_3 - используется под Windows NT
file_info_50 - используется под Windows 9x-Me
Рассмотрим две из них:
Структура file_info_50:
Описание структуры:
type TFileInfo50 = packed record fi50_id : Cardinal; fi50_permissions : WORD; fi50_num_locks : WORD; fi50_pathname : PChar; fi50_username : PChar; fi50_sharename : PChar; end;
Поля:
Fi50_id - Содержит идентификационный номер открытого файла
Fi50_permissions - Содержит уровень доступа с которым открыт файл (см. MSDN)
Fi50_num_locks - содержит кол-во блокировок файла (см. MSDN)
Fi50_pathname - содержит полный путь к открытому файлу
Fi50_username - содержит имя пользователя или компьютера открывшего файл (см.
MSDN)
Fi50_sharename - содержит имя общего ресурса в котором находится открытый файл
Структура FILE_INFO_3
Описание структуры:
type TFileInfo3 = packed record fi3_id : DWORD; fi3_permissions : DWORD; fi3_num_locks : DWORD; fi3_pathname : PWChar; fi3_username : PWChar; end; PFileInfo3 = ^TFileInfo3; TFileInfo3Array = array[0..512] of TFileInfo3; PFileInfo3Array = ^TFileInfo3Array;
Поля:
Fi3_id - Содержит идентификационный номер открытого файла
Fi3_permissions - Содержит уровень доступа с которым открыт файл (см. MSDN)
Fi3_num_locks - содержит кол-во блокировок файла (см. MSDN)
Fi3_pathname - содержит полный путь к открытому файлу
Fi3_username - содержит имя пользователя или компьютера открывшего файл (см.
MSDN)
Не поленитесь и посмотрите в MSDN о всех отмеченых полях, я не буду рассматривать их подробно, так как нам они не понадобятся. Продолжим написание кода. Добавьте на форму ListView с именем lvFiles и создайте на нем три колонки с названиями ID, PathName, UserName. Также добавьте кнопку и назовите ее btnGetFiles. Не забудьте добавить обьявления функций и структуры в интерфейсную часть. Теперь напишем код который покажет нам список открытых файлов на нашем компьютере. Вот он:
procedure TMainForm.btnGetFilesClick(Sender: TObject); var OS: Boolean; FLibHandle : THandle; FileInfoNT: PFileInfo3Array; FileInfo9x: array [0..512] of TFileInfo50; TotalEntries,EntriesReadNT: DWORD; EntriesRead,TotalAvial: Word; i:integer; begin lvfiles.Items.Clear; if not IsNT(OS) then Close; //Выясняем тип системы if OS then begin //Код для NT FLibHandle := LoadLibrary('NETAPI32.DLL'); if FLibHandle = 0 then Exit; @NetFileEnumNT := GetProcAddress(FLibHandle, 'NetFileEnum'); if not Assigned(NetFileEnumNT) then begin FreeLibrary(FLibHandle); Exit; end; FileInfoNT := nil; if NetFileEnumNT(nil,nil,nil,3,@FileInfoNT,DWORD(-1),@entriesreadNT, @totalentries, nil)=0 then for i:=0 to EntriesReadNT-1 do begin with lvFiles.Items.Add do //Заполнение данными из структуры begin Caption := string(IntToStr(FileInfoNT^[i].fi3_id)); //Идентификатор SubItems.Add(FileInfoNT^[i].fi3_pathname); //Путь к файлу SubItems.Add(FileInfoNT^[i].fi3_username); //Имя пользователя end; end; end else begin //Код для Windows 9x-Me FLibHandle := LoadLibrary('SVRAPI.DLL'); if FLibHandle = 0 then Exit; @NetFileEnum := GetProcAddress(FLibHandle, 'NetFileEnum'); if not Assigned(NetFileEnum) then begin FreeLibrary(FLibHandle); Exit; end; if NetFileEnum (nil, nil,50,@FileInfo9x,SizeOf(FileInfo9x),@EntriesRead,@TotalAvial) = 0 then for i:=0 to EntriesRead-1 do begin with lvFiles.Items.Add do //Заполнение данными из структуры begin Caption := string(IntToStr(FileInfo9x[i].fi50_id)); //Идентификатор SubItems.Add(FileInfo9x[i].fi50_pathname); //Путь к файлу SubItems.Add(FileInfo9x[i].fi50_username); //Имя пользователя end; end; end; FreeLibrary(FLibHandle); end;
Без комментариев :)
Закрытие открытого файла
Теперь рассмотрим функции NetFileClose и NetFileClose2, при помощи которых мы будем закрывать открытые по сети файлы.
Функция NetFileClose2 - используется только в Windows 9x-Me
var NetFileClose2:function( pszServer :PChar; UlFileId :LongWord):DWORD; stdcall;
Поля:
pszServer - должен содержать имя удаленного компьютера, если закрываем у себя
то данному параметру нужно присвоить NIL.
UlFileId - должен содержать уникальный идентификатор открытого файла
Функция NetFileClose - используется только в Windows NT
var NetFileClose:function( ServerName :PWideChar; FileId :DWORD):DWORD; stdcall;
Поля:
ServerName - должен содержать имя удаленного компьютера, если закрываем у себя
то данному параметру нужно присвоить NIL.
FileId - должен содержать уникальный идентификатор открытого файла
Как вы видите с этими функциями все предельно просто, в качестве первого параметра передадим NIL (закрывает у себя), в качестве второго, идентификатор файла отображающийся в поле ID. Поместите на форму кнопку, измените ее имя на btnCloseFile, не забудьте добавить объявления функций (для NT переименовывать не надо). Вот пример кода:
procedure TMainForm.btnCloseFileClick(Sender: TObject); var OS: Boolean; FLibHandle : THandle; i: Integer; begin if not IsNT(OS) then Close; //Выясняем тип системы if not Assigned(lvFiles.Selected) then Exit; i:= lvFiles.Selected.Index; //Определяем номер выбранного файла if OS then begin //Код для NT FLibHandle := LoadLibrary('NETAPI32.DLL'); if FLibHandle = 0 then Exit; @NetFileClose := GetProcAddress(FLibHandle, 'NetFileClose'); if not Assigned(NetFileClose) then begin FreeLibrary(FLibHandle); Exit; end; NetFileClose(nil,StrToInt(lvFiles.Items.Item[i].Caption)); //Закрываем end else begin //Код для Windows 9x-Me FLibHandle := LoadLibrary('SVRAPI.DLL'); if FLibHandle = 0 then Exit; @NetFileClose2 := GetProcAddress(FLibHandle, 'NetFileClose2'); if not Assigned(NetFileClose2) then begin FreeLibrary(FLibHandle); Exit; end; NetFileClose2(nil,StrToInt(lvFiles.Items.Item[i].Caption)); //Закрываем end; FreeLibrary(FLibHandle); end;
Этот код также оставлю без комментариев.
Определение входящего и исходящего трафика
Вот мы и подобрались к заключительной части статьи. Часто (практически всегда) можно услышать советы использовать собственноручно написанный прокси - сервер для определения трафика сети (чего там скрывать, и сам этим грешу, не охота объяснять по 15 раз на день прописные истины ;) Узнать трафик можно и не используя прокси - сервер. Для этого достаточно использовать всего лишь одну функцию библиотеки IPHLPAPI.DLL, которая поставляется со всеми версиями Windows. Её то мы и рассмотрим:
Объявление функции (все версии Windows):
var GetIfTable:function( pIfTable: PMibIfTable; pdwSize : PULONG; bOrder : Boolean ): DWORD; stdcall;
Параметры:
pIfTable - должен содержать указатель на структуру
pdwSize - должен содержать размер структуры
bOrder - указывает, нужна ли сортировка в возвращаемом массиве
В качестве первого параметра функция использует указатель на структуру, вот само описание структуры
type TMibIfTable = packed record dwNumEntries : DWORD; Table : TMibIfArray; end; PMibIfTable = ^ TMibIfTable;
Поля:
dwNumEntries - определяет размерность массива представленного вторым
параметром
Table - является массивом структур
Структура сама по себе крайне неинформативна, нас интересует второе ее поле, также представляющее собой структуру, даю её описание:
type TMibIfRow = packed record wszName : array[0..255] of WideChar; dwIndex : DWORD; dwType : DWORD; dwMtu : DWORD; dwSpeed : DWORD; dwPhysAddrLen : DWORD; bPhysAddr : array[0..7] of Byte; dwAdminStatus : DWORD; dwOperStatus : DWORD; dwLastChange : DWORD; dwInOctets : DWORD; dwInUcastPkts : DWORD; dwInNUCastPkts : DWORD; dwInDiscards : DWORD; dwInErrors : DWORD; dwInUnknownProtos : DWORD; dwOutOctets : DWORD; dwOutUCastPkts : DWORD; dwOutNUCastPkts : DWORD; dwOutDiscards : DWORD; dwOutErrors : DWORD; dwOutQLen : DWORD; dwDescrLen : DWORD; bDescr : array[0..255] of Char; end; TMibIfArray = array [0..512] of TMibIfRow; PMibIfRow = ^TMibIfRow; PmibIfArray = ^TmibIfArray;
Поля:
wszName - Указатель на строку содержащую имя интерфейса
dwIndex - Определяет индекс интерфейса
dwType - Определяет тип интерфейса (см. MSDN)
dwMtu - Определяет максимальную скорость передачи
dwSpeed - Определяет текущую скорость передачи в битах в секунду
dwPhysAddrLen - Определяет длину адреса содержащегося в bPhysAddr
bPhysAddr - Содержит физический адрес интерфейса (если проще то его, немного
видоизмененный, МАС адрес)
dwAdminStatus - Определяет активность интерфейса
dwOperStatus - Содержит текущий статус интерфейса (см. MSDN)
dwLastChange - Содержит последний измененный статус
dwInOctets - Содержит количество байт принятых через интерфейс
dwInUcastPkts - Содержит количество направленных пакетов принятых интерфейсом
dwInNUCastPkts - Содержит количество ненаправленных пакетов принятых
интерфейсом (включая Броадкаст и т.п.)
dwInDiscards - Содержит количество забракованных входящих пакетов (даже если
они не содержали ошибки)
dwInErrors - Содержит количество входящих пакетов содержащих ошибки
dwInUnknownProtos - Содержит количество забракованных входящих пакетов со
структурой неизвестного протокола
dwOutOctets - Содержит количество байт отправленных интерфейсом
dwOutUCastPkts - Содержит количество направленных пакетов отправленных
интерфейсом
dwOutNUCastPkts- Содержит количество ненаправленных пакетов отправленных
интерфейсом (включая Броадкаст и т.п.)
dwOutDiscards- Содержит количество забракованных исходящих пакетов (даже если
они не содержали ошибки)
dwOutErrors- Содержит количество исходящих пакетов содержащих ошибки
dwOutQLen - Содержит длину очереди данных
dwDescrLen - Содержит размер массива bDescr
bDescr - Содержит описание интерфейса
Как вы видите в этой структуре содержится уйма информации, которую мы и будем использовать (часть её ;) Заметьте, интерфейсом является не обязательно некое физическое устройство (например, сетевая карта), но на этом я останавливаться не буду. Если кому-то это интересно, посмотрите, что об этом говорит MSDN.
Итак, добавьте на форму ListView, назовем его lvTraffic, создайте в ней четыре колонки со следующими именами (Caption) - bDescr, bPhysAddr (MAC), dwInOctets и dwOutOctets. В них мы будем выводить наименование интерфейса, его МАС адрес, общее кол-во принятых и отправленных байт. Добавьте описания структур и функции в интерфейсную часть модуля. Примечание, если вы добавляете структуры в том виде, в каком они даны, поменяйте очередность их объявления, т.е. TMibIfRow должна быть объявлена первой. Теперь добавьте на форму таймер, он будет отвечать за ежесекундное обновление информации о трафике, назовем его tmrTraffic. Вот сам код определения текущего входящего - исходящего трафика:
procedure TMainForm.tmrTrafficTimer(Sender: TObject); // Вспомогательная функция, преобразующая МАС адрес к "нормальному" виду //Определяем специальный тип, чтобы можно было передать в функцию массив type TMAC = array [0..7] of Byte; //В качестве первого значения массив, второе значение, размер данных в массиве function GetMAC(Value: TMAC; Length: DWORD): String; var i: Integer; begin if Length = 0 then Result := '00-00-00-00-00-00' else begin Result := ''; for i:= 0 to Length -2 do Result := Result + IntToHex(Value[i],2)+'-'; Result := Result + IntToHex(Value[Length-1],2); end; end; //Сама процедура var FLibHandle : THandle; Table : TMibIfTable; i : Integer; Size : Integer; begin tmrTraffic.Enabled := False; //Приостанавливаем на всякий случай таймер lvTraffic.Items.BeginUpdate; lvTraffic.Items.Clear; //Очищаем список FLibHandle := LoadLibrary('IPHLPAPI.DLL'); //Загружаем библиотеку if FLibHandle = 0 then Exit; @GetIfTable := GetProcAddress(FLibHandle, 'GetIfTable'); if not Assigned(GetIfTable) then begin FreeLibrary(FLibHandle); Close; end; Size := SizeOf(Table); if GetIfTable(@Table, @Size, False ) = 0 then //Выполняем функцию for i:= 0 to Table.dwNumEntries-1 do begin with lvTraffic.Items.Add do begin //Выводим результаты Caption := String(Table.Table[i].bDescr); //Наименование интерфейса SubItems.Add(GetMAC(TMAC(Table.Table[i].bPhysAddr), Table.Table[i].dwPhysAddrLen)); //MAC адрес SubItems.Add(IntToStr(Table.Table[i].dwInOctets)); //Всего принято байт SubItems.Add(IntToStr(Table.Table[i].dwOutOctets)); //Всего отправлено байт end; end; lvTraffic.Items.EndUpdate; FreeLibrary(FLibHandle); tmrTraffic.Enabled := True; //Не забываем активировать таймер end;
Заметьте, я определяю новый тип данных TMAC для передачи массива, в котором содержится сам MAC адрес в функцию для преобразования его в более привычный вид. Обратите внимания на код TMAC(Table.Table[i].bPhysAddr), это передача массива, обязательно нужно указать, что массив передается как тип TMAC, в противном случае компилятор выдаст ошибку несовместимости типов.
Вот кажется и все, что я хотел вам рассказать. Поэкспериментируйте с данным кодом, я раскрыл не все возможности приведенных мной функций. Дерзайте ;)
В заключение хочу сказать. Вся информация была получена в результате тщательного изучения MSDN и выяснением особо острых моментов под С#. Если у вас возникнут какие либо вопросы по статье, сперва посмотрите как это реализовано в прилагаемой к статье программе. Не стесняйтесь пройтись по коду под отладкой. Посмотрите также сам MSDN. Кстати некоторые (и что самое удивительное не один и тот же человек) присылали мне письма с вопросом, что такое MSDN. Отвечаю: MSDN - сокращение от MicroSoft Developer Network, огромная база содержащая практически всю (если не всю) информацию о продуктах компании Microsoft. Распространяется обычно на трех - четырех компакт дисках, или доступна в интернете по адресу http://msdn.microsoft.com/
Код проверялся под следующими системами: Windows 98, Windows 98 SE, Windows Me, Windows NT 4.0 Server, Windows 2000 Professional, Windows 2000 Server и Windows XP Professional.
Код совместим с Delphi 5.0 Professional, Delphi 6.0 Enterprise SP1, Delphi 7.0 Enterprise (остальных версий Delphi просто не оказалось в наличии :)
Отдельно хочется выразить благодарность Анатолию Подгорецкому и Игорю Шевченко за время потраченное на изучение статьи и указание на допущенные мной ошибки.
С уважением, Александр (Rouse_) Багель
e-mail: rouse79@yandex.ru
ICQ: 170677708