Суббота, 18.05.2024
Королевство Delphi
Главное меню
Статьи
Наш опрос
Нужен форум на сайте?
Всего ответов: 90
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Главная » Статьи » Сеть-интернет » Разные

Мониторинг сетей в Delphi

Вступление:

В этой статье мы рассмотрим некоторые функции, которые предоставят нам возможность контроля локальной сети. Так как материал довольно обширный, я не буду пускаться в отвлеченные рассуждения, и буду давать только самую суть. Обратите внимание на места с подчеркнутым текстом, так как там находятся именно те подводные камни, о которые часто спотыкается неопытный программист. Материал будет даваться по следующему принципу:

  1. Объявление функции (для Windows 9x-Me и Windows NT, 2000, XP)
  2. Краткое объяснение параметров функции
  3. Список структур передаваемых функции
  4. Краткое описание структур (по одной для каждого типа Windows)
  5. Пример вызова функции и обработка результатов

К статье прилагается программа, демонстрирующая совместную работу всех рассматриваемых функций, и её полный исходный код.

Демонстрационная программа

Совет: прочитайте внимательно всю статью, так как те места, которые прокомментированы в начале статьи, я не буду объяснять повторно в ее конце или середине.

Примечание:

  • Все объявления функций и примеры написаны с учетом динамического подключения библиотек.
  • Места указанные мной как "Не используется" - означают, что не используется мной :), т.е. не критичны.
  • Весь код дан только как пример использования функций и не может являться образцом написания программ.

Надеюсь, после прочтение данного материала у вас исчезнут большинство вопросов "Как". Возможно, появятся вопросы "Почему", в этом случае я всегда готов помочь, так как только из-за обилия вопросов "Как" и практически полного отсутствия "Почему", я и взялся за написание этой статьи. ;)

Итак, начнем.


Краткая таблица приведения типов:

А начнем мы с небольшого отступления. Кроме тех функций, которые будут приведены в данной статье, существует еще много полезных, достойных вашего изучения. Есть одно "Но". Описания этих функций даны в MSDN с учетом синтаксиса C++, а не Delphi, я попытаюсь исправить этот недостаток, и приведу небольшую таблицу, цель которой помочь вам в трансляции описания функций и структур на Delphi. Таблица не может претендовать на полноту, возможно я где-то напутал (надеюсь что нет) с диапазоном значений, но основной принцип приведения здесь показан правильно.

C++ Delphi Range
Char ShortInt -128 to 127
- Char 1 ASCII character (0 to 255)
Int, Short SmallInt -32,768 to 32,767
Long Integer / LongInt -2,147,483,647 to 2,147,483,647
Unsigned Char Byte 0 to 255
Unsigned Int / Unsigned Short Word 0 to 65,535
Unsigned Long Cardinal / Longword 0 to 4,294,967,295
Float Single 3.4E-38 TO 3.4E+38
Double Double / Comp 1.7E-308 TO 1.7E+308
Long Double Extended 3.4E-4932 TO 3.4E+4932
Void Pointer N/A -- an untyped pointer
- Boolean True or False
String - a C++ standard object
- String An array of up to 255 ASCII characters
char FAR * Pchar Pointer to a null-terminated string
unsigned short FAR * PWORD Type of pointer
LPWSTR PWideChar Type of pointer
LPTSTR PAnsiChar Type of pointer
Данные действительны для Delphi v7.0

Определение доступных ресурсов

Итак, рассмотрим функции, предоставляющие нам информацию о наших локальных ресурсах и возможность их контроля.
NetShareEnum - при помощи этой функции мы получим данные обо всех своих и чужих общих ресурсах

Объявление функции для Windows 9х - Ме:

var
 NetShareEnum :function (pszServer : PChar; 
 sLevel : Cardinal; 
 pbBuffer : PChar; 
 cbBuffer : Cardinal; 
 pcEntriesRead, 
 pcTotalAvail : Pointer ):DWORD; stdcall;

Параметры:
  pszServer - должен содержать имя удаленного компьютера на котором должна выполнится функция, если выполняем у себя то данному параметру можно присвоить NIL.
  sLevel - должен содержать идентификатор структуры.
  pbBuffer - должен содержать указатель на массив структур.
  cbBuffer - должен содержать размер массива структур.
  pcEntriesRead - должен содержать указатель на переменную в которую запишется количество общих ресурсов доступных на данный момент.
  pcTotalAvail - не используется.

Объявление функции для Windows NT:

var
 NetShareEnum :function (ServerName :PWChar;
 Level :DWORD;
 Bufptr :Pointer;
 Prefmaxlen :DWORD;
 EntriesRead,
 TotalEntries,
 resume_handle:LPDWORD): DWORD; stdcall;

Параметры:
  ServerName - должен содержать имя удаленного компьютера на котором должна выполнится функция, если выполняем у себя то данному параметру можно присвоить NIL.
  Level - должен содержать идентификатор структуры.
  Bufptr - должен содержать адрес указателя на массив структур.
  Prefmaxlen - должен содержать максимальную длину возвращенных данных в байтах, если не ставить ограничение то данному параметру нужно присвоить DWORD(-1)
  EntriesRead - должен содержать указатель на переменную в которую запишется количество общих ресурсов доступных на данный момент.
  TotalEntries - не используется
  Resume_handle - не используется, должен быть NIL

В случае успешного выполнения результат обеих функций равен нулю. Обратите внимание, на то, что функция использующаяся в Windows 9x-Me получает именно указатель на массив структур, в то время как другая функция получает адрес указателя, это критично!!!

Результаты выполнения будут сохранены в массиве структур переданных функции при ее вызове. Существует 6 типов структур передаваемых функции NetShareEnum

  • SHARE_INFO_0 - только Windows NT
  • SHARE_INFO_1 - только Windows NT
  • share_info_1 - только Windows 9х-Ме
  • SHARE_INFO_2 - только Windows NT
  • share_info_50 - только Windows 9х-Ме
  • SHARE_INFO_502 - только Windows NT

Я остановлюсь на двух из них (по одной для каждого типа Windows :)

Структура share_info_50:

Объявление структуры:

type 
 TShareInfo50 = packed record
 shi50_netname : array [0..12] of Char;
 shi50_type : Byte;
 shi50_flags : Word;
 shi50_remark : PChar;
 shi50_path : PChar;
 shi50_rw_password : array [0..8] of Char;
 shi50_ro_password : array [0..8] of Char;
 end;

Поля:
  shi50_netname - содержит строку содержащую сетевое имя ресурса
  shi50_type - определяет тип ресурса (подробнее в MSDN)
  shi50_flags - содержит информацию о правах доступа к ресурсу
  shi50_remark - указатель на строку содержащую необязательный комментарий к ресурсу
  shi50_path - содержит локальное расположение ресурса
  shi50_rw_password - содержит пароль на запись - чтение
  shi50_ro_password - содержит пароль на чтение

Реально получить значение двух последних полей можно только при получении информации о своём компьютере, в остальных случаях они остаются пустыми.

Структура SHARE_INFO_2:

Объявление структуры:

type 
 TShareInfo2 = packed record
 shi2_netname : PWChar;
 shi2_type : DWORD;
 shi2_remark : PWChar;
 shi2_permissions : DWORD;
 shi2_max_uses : DWORD;
 shi2_current_uses : DWORD;
 shi2_path : PWChar;
 shi2_passwd : PWChar;
 end;
 PShareInfo2 = ^TShareInfo2;
 TShareInfo2Array = array [0..512] of TShareInfo2;
 PShareInfo2Array = ^TShareInfo2Array;

Поля:
  shi2_netname - Содержит указатель на строку содержащую имя ресурса
  shi2_type - определяет тип ресурса (подробнее в MSDN)
  shi2_remark - указатель на строку содержащую необязательный комментарий к ресурсу
  shi2_permissions - содержит информацию о правах доступа к ресурсу
  shi2_max_uses - определяет максимальное кол-во подключений к ресурсу
  shi2_current_uses - определяет кол-во текущих подключений
  shi2_path - содержит указатель на строку содержащую локальное расположение ресурса
  shi2_passwd - содержит указатель на строку содержащую пароль

Итак, теперь у вас есть вся информация для написания первой программы. Создадим новый проект. Добавим на форму два элемента - ListBox, назовем его lbxShares и Button, назовем ее btnGetShares. В интерфейсную часть модуля добавим описания структур и функций, так, как они были даны выше. Единственное отличие функцию для NT мы назовем NetShareEnumNT, для того чтобы не было двух одинаковых функций с разными параметрами. У вас должно получится что-то вроде этого:

unit Main;

interface

uses ...;

type
 TMainForm = class(TForm)
 lbxShares: TListBox;
 btnGetShares: TButton;
 private
 { Private declarations }
 public
 { Public declarations }
 end;

type 
 TShareInfo50 = packed record
 ...
 end;

type TShareInfo2 = packed record
 ...
 end;
 PShareInfo2 = ...

var
 NetShareEnumNT:function (...): DWORD; stdcall;
 NetShareEnum:function (...): DWORD; stdcall;

var
 MainForm: TMainForm;

Implementation

{$R *.dfm}

end.

Теперь реализуем вызов функций. Первоначально нам нужно определится, под какой системой мы работаем, чтобы узнать какую часть кода (для NT или нет) использовать в данный момент. Для этого напишем небольшую функцию, которая и будет определять тип системы.

function TMainForm.IsNT(var Value: Boolean): Boolean;
var Ver: TOSVersionInfo;
 BRes: Boolean;
begin
 Ver.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
 BRes := GetVersionEx(Ver);
 if not BRes then
 begin
 Result := False;
 Exit;
 end else
 Result := True; 
 case Ver.dwPlatformId of
 VER_PLATFORM_WIN32_NT : Value := True; //Windows NT - подходит
 VER_PLATFORM_WIN32_WINDOWS : Value := False; //Windows 9x-Me - подходит
 VER_PLATFORM_WIN32s : Result := False; //Windows 3.x - не подходит
 end;
end;

Если данная функция вернула результат True, значит, определение версии системы прошло успешно, и тип системы будет храниться в переменной Value (True - значит NT, False - 9x, Me), в противном случае определение типа системы неудачно или система является Windows 3.x, в этом случае придется завершить выполнение программы. Данная функция будет у нас практически самой главной, так как она будет указывать нашей программе какую часть кода исполнять. Теперь обратите внимание, наши функции только объявлены, но за ними не закреплено никакого исполняемого кода. Если бы мы использовали статическое связывание и заранее определили библиотеки и имена библиотечных функций, гарантированно получили бы в процессе выполнения ошибку, так как библиотека SVRAPI отсутствует в Windows NT, а NETAPI32 отсутствует в Windows 9x-Me. Для этого мы должны после определения типа системы загрузить требуемую библиотеку, и уже только после этого связать наши функции с библиотечными.

Итак, наши действия: определяем, тип системы, загружаем требуемую библиотеку, получаем адреса функций и выполняем функцию.

procedure TMainForm.btnGetSharesClick(Sender: TObject);
var
 i:Integer;
 FLibHandle : THandle; 
 ShareNT : PShareInfo2Array; //<= Перемеменные
 entriesread,totalentries:DWORD; //<= для Windows NT
 Share : array [0..512] of TShareInfo50; //<= Переменные
 pcEntriesRead,pcTotalAvail:Word; //<= для Windows 9x-Me
 OS: Boolean;
begin
 lbxShares.Items.Clear;
 if not IsNT(OS) then Close; //Определяем тип системы

 if OS then begin //Код для NT
 FLibHandle := LoadLibrary('NETAPI32.DLL'); //Загружаем библиотеку
 if FLibHandle = 0 then Exit;
 //Связываем функцию
 @NetShareEnumNT := GetProcAddress(FLibHandle,'NetShareEnum');
 if not Assigned(NetShareEnumNT) then //Проверка
 begin
 FreeLibrary(FLibHandle);
 Exit; 
 end;
 ShareNT := nil; //Очищаем указатель на массив структур
 //Вызов функции
 if NetShareEnumNT(nil,2,@ShareNT,DWORD(-1),
 @entriesread,@totalentries,nil) <> 0 then 
 begin //Если вызов неудачен выгружаем библиотеку
 FreeLibrary(FLibHandle);
 Exit;
 end;
 if entriesread > 0 then //Обработка результатов
 for i:= 0 to entriesread - 1 do 
 lbxShares.Items.Add(String(ShareNT^[i].shi2_netname));

 end else begin //Код для 9х-Ме
 FLibHandle := LoadLibrary('SVRAPI.DLL'); //Загружаем библиотеку
 if FLibHandle = 0 then Exit;
 //Связываем функцию
 @NetShareEnum := GetProcAddress(FLibHandle,'NetShareEnum'); 
 if not Assigned(NetShareEnum) then //Проверка
 begin
 FreeLibrary(FLibHandle);
 Exit; 
 end;
 if NetShareEnum(nil,50,@Share,SizeOf(Share),
 @pcEntriesRead,@pcTotalAvail) <> 0 then //Вызов функции
 begin //Если вызов неудачен выгружаем библиотеку
 FreeLibrary(FLibHandle);
 Exit;
 end;
 if pcEntriesRead > 0 then //Обработка результатов
 for i:= 0 to pcEntriesRead - 1 do 
 lbxShares.Items.Add(String(Share[i].shi50_netname));
 end;
 FreeLibrary(FLibHandle); //Не забываем выгрузить библиотеку
end;

При выполнении этого кода ListBox заполнится названиями общих ресурсов, которые берутся из массива структур переданных функции. Как вы поняли, массив заполняется в результате выполнения функции. Немного модифицировав код (см. описание структур) вы получите комментарии к ресурсу, пароли, пути к папкам общих ресурсов и т.д. Вы можете заметить, при возникновении ошибок, я просто завершал работу процедуры оператором Exit. Это сделано только для того, чтобы не загромождать код обработчиками, в реальной программе такое, естественно, не допустимо.

Примечание: обычно в NT используются функции NetApiBufferAllocate и NetApiBufferFree - при помощи них выделяется и освобождается память под массив структур. Я вам показал немного другое объявление структуры TShareInfo2Array = array [0..512] of TShareInfo2; Здесь память уже выделена. Я предпочитаю пользоваться именно таким объявлением структуры, поэтому эти функции в данной статье рассмотрены не будут. При желании вы можете посмотреть в MSDN принцип их использования.


Закрытие локального ресурса

Получать список общих ресурсов вы научились. Теперь рассмотрим функцию NetShareDel которая позволит нам закрыть выбранный общий ресурс.

Обьявление функции для 9х - Ме Windows:

var
 NetShareDel:function (pszServer, 
 pszNetName :PChar; 
 usReserved :Word ): DWORD; stdcall;

Параметры:   ServerName - должен содержать имя удаленного компьютера, если закрываем свои ресурсы то данному параметру нужно присвоить NIL.
  NetName - указатель на строку содержащую имя закрываемого ресурса
  Reserved - не используется, должен быть равен нулю

Как вы заметили, обе функции не используют никаких структур. Нас интересует только второй параметр, содержащий имя закрываемого ресурса (подробнее по остальным параметрам см. MSDN). В качестве имени передается не путь к ресурсу, а именно имя ресурса которое мы определили при помощи кода данного выше. В случае успешного выполнения функций, их результат будет равен нулю. Итак, добавим к нашей программе еще одну кнопку и назовем ее btnCloseShares. Обработчик этой кнопки будет содержать код, определяющий текущий выбранный элемент в списке текущих общих ресурсов, и будет передавать его имя (Strings[xx]) в качестве второго параметра функции. (Не забудьте добавить объявления функций в интерфейсную часть программы, и как и в прошлый раз функция для NT будет иметь название NetShareDelNT(…) )

procedure TMainForm.btnCloseSharesClick(Sender: TObject);
var
 OS:Boolean;
 FLibHandle : THandle;
 Name9x:array [0..12] of Char;
 NameNT:PWChar;
 i:Integer;
 ShareName: String;
begin
 if not IsNT(OS) then Close; //Определяем тип системы

 if lbxShares.Items.Count = 0 then Exit;
 for i:= 0 to lbxShares.Items.Count -1 do
 if lbxShares.Selected[i] then Break; //Ищем выбранный элемент
 if not lbxShares.Selected[i] then Exit; //Если не найден уходим
 ShareName := lbxShares.Items.Strings[i];

 if OS then begin //Код для NT
 FLibHandle := LoadLibrary('NETAPI32.DLL');
 if FLibHandle = 0 then Exit;
 @NetShareDelNT := GetProcAddress(FLibHandle,'NetShareDel');
 if not Assigned(NetShareDelNT) then //Проверка
 begin
 FreeLibrary(FLibHandle);
 Exit; 
 end;
 i:= SizeOf(WideChar)*256; 
 GetMem(NameNT,i); //Выделяем память под переменную
 StringToWideChar(ShareName,NameNT,i); //Преобразуем в PWideChar
 NetShareDelNT(nil,NameNT,0); //Удаляем ресурс
 FreeMem(NameNT); //Освобождаем память
 end else begin //Код для 9х-Ме
 FLibHandle := LoadLibrary('SVRAPI.DLL');
 if FLibHandle = 0 then Exit;
 @NetShareDel := GetProcAddress(FLibHandle,'NetShareDel');
 if not Assigned(NetShareDel) then //Проверка
 begin
 FreeLibrary(FLibHandle);
 Exit; 
 end;
 FillChar(Name9x, SizeOf(Name9x), #0); //Очищаем массив
 move(ShareName[1],Name9x[0],Length(ShareName)); //Заполняем массив
 NetShareDel(nil,@Name9x,0); //Удаляем ресурс
 end;
 FreeLibrary(FLibHandle);
end;

Заметьте, что я опять не делаю никаких проверок на результат выполнения функции, как я объяснял выше, во первых, чтобы не загромождать демонстрационный код, а во вторых - в данной процедуре не используются результаты выполнения функций (они не критичны), но в реальной программе вы обязаны обработать результаты и в случае неуспешного выполнения (результат не равен нулю) уведомить об этом пользователя. Обратите внимание, что в версии кода для Windows 9x-Me я преобразую имя ресурса ShareName в массив Char и передаю указатель на него. Это обязательное действие, так как PСhar(ShareName) попросту не сработает. Подробнее о том почему выбран именно такой размер массива смотрите в MSDN


Открытие локального ресурса

Теперь нам следует научится открывать общий ресурс. Для этого воспользуемся функцией NetShareAdd

Объявление функции для 9х - Ме Windows:

var
 NetShareAdd: function ( pszServer :Pchar;
 SLevel :Cardinal;
 PbBuffer :PChar;
 CbBuffer :Word):DWORD; stdcall;

Параметры:
  pszServer - должен содержать имя удаленного компьютера на котором должна выполнится функция, если открываем локальный ресурс то данному параметру нужно присвоить NIL.
  sLevel - должен содержать идентификатор структуры.
  pbBuffer - должен содержать указатель на структуру.
  cbBuffer - должен содержать размер структуры.

Обьявление функции для Windows NT:

var
 NetShareAdd: function ( servername : PWideChar;
 level : DWORD;
 buf : Pointer;
 parm_err : LPDWORD): DWORD; stdcall;

Параметры:
  servername - должен содержать имя удаленного компьютера на котором должна выполнится функция, если открываем локальный ресурс то данному параметру нужно присвоить NIL.
  level - должен содержать идентификатор структуры.
  buf - должен содержать указатель на структуру.
  parm_err - содержит указатель члена структуры вызывающий ошибку

Заметьте что в функции для NT также используется указатель а не адрес указателя. Обе функции используют структуры описанные выше. Для демонстрации их возможностей воспользуемся уже разобранными нами структурами share_info_50 и SHARE_INFO_502. Параметр parm_err в рамках этой статьи я разбирать не буду, подробности в MSDN, можете присвоить ему nil. Итак, добавьте объявления функций в интерфейсную часть модуля (не забудьте про переименование процедуры для NT), добавьте еще одну кнопку на форму и измените ее имя на btnAddShares. В обработчик OnClick этой кнопки мы поместим код позволяющий нам выбрать папку, общий доступ к которой мы хотим открыть. Для этого нам нужно написать еще одну небольшую функцию, показывающую диалог выбора папки. Вот она:

function TMainForm.SelectDirectory: String;
var
 lpItemID : PItemIDList;
 BrowseInfo : TBrowseInfo;
 DisplayName : array[0..MAX_PATH] of Char;
 TempPath : array[0..MAX_PATH] of Char;
begin
 FillChar(BrowseInfo, sizeof(TBrowseInfo), #0);
 BrowseInfo.hwndOwner := Handle;
 BrowseInfo.pszDisplayName := @DisplayName;
 BrowseInfo.lpszTitle := 'Specify a directory';
 BrowseInfo.ulFlags := BIF_RETURNONLYFSDIRS;
 lpItemID := SHBrowseForFolder(BrowseInfo);
 if Assigned(lpItemId) then begin
 SHGetPathFromIDList(lpItemID, TempPath);
 GlobalFreePtr(lpItemID);
 end else Result := '';
 Result := String(TempPath);
end;

Для выполнения данной функции добавьте в раздел Uses модули ShellAPI и ShlObj. Вот сам код открытия ресурса:

procedure TMainForm.btnAddSharesClick(Sender: TObject);
const
 STYPE_DISKTREE = 0;
 ACCESS_ALL = 258;
 SHI50F_FULL = 258;
var
 FLibHandle : THandle;
 Share9x : TShareInfo50;
 ShareNT : TShareInfo2;
 TmpDir, TmpName: String;
 TmpDirNT, TmpNameNT: PWChar;
 OS: Boolean;
 TmpLength: Integer;
begin
 TmpDir := SelectDirectory; //Определяем путь к будущему ресурсу
 TmpName := InputBox('Share name','Enter name','Test'); //Определяем имя под которым он будет виден в сети
 if TmpDir = '' then Exit;

 if not IsNT(OS) then Close; //Выясняем тип системы

 if OS then begin //Код для NT
 FLibHandle := LoadLibrary('NETAPI32.DLL');
 if FLibHandle = 0 then Exit;
 @NetShareAddNT := GetProcAddress(FLibHandle,'NetShareAdd');
 if not Assigned(NetShareAddNT) then
 begin
 FreeLibrary(FLibHandle);
 Exit;
 end;
 TmpLength := SizeOF(WideChar)*256; //Определяем необходимый размер
 
 GetMem(TmpNameNT, TmpLength); //Конвертируем в PWChar
 StringToWideChar(TmpName, TmpNameNT, TmpLength);
 ShareNT.shi2_netname := TmpNameNT; //Имя

 ShareNT.shi2_type := STYPE_DISKTREE; //Тип ресурса
 ShareNT.shi2_remark := ''; //Комментарий
 ShareNT.shi2_permissions := ACCESS_READ; //Доступ
 ShareNT.shi2_max_uses := DWORD(-1); //Кол-во максим. подключ.
 ShareNT.shi2_current_uses := 0; //Кол-во тек подкл.

 GetMem(TmpDirNT, TmpLength);
 StringToWideChar(TmpDir, TmpDirNT, TmpLength);
 ShareNT.shi2_path := TmpDirNT; //Путь к ресурсу

 ShareNT.shi2_passwd := nil; //Пароль

 NetShareAddNT(nil,2,@ShareNT,nil); //Добавляем ресурс
 FreeMem (TmpNameNT); //освобождаем память
 FreeMem (TmpDirNT);
 end else begin //Код для 9x
 FLibHandle := LoadLibrary('SVRAPI.DLL');
 if FLibHandle = 0 then Exit;
 @NetShareAdd := GetProcAddress(FLibHandle,'NetShareAdd');
 if not Assigned(NetShareAdd) then
 begin
 FreeLibrary(FLibHandle);
 Close;
 end;
 FillChar(Share9x.shi50_netname, SizeOf(Share9x.shi50_netname), #0);
 move(TmpName[1],Share9x.shi50_netname[0],Length(TmpName)); //Имя
 Share9x.shi50_type := STYPE_DISKTREE; //Тип ресурса
 Share9x.shi50_flags := SHI50F_RDONLY; //Доступ
 FillChar(Share9x.shi50_remark,
 SizeOf(Share9x.shi50_remark), #0); //Комментарий
 FillChar(Share9x.shi50_path,
 SizeOf(Share9x.shi50_path), #0);
 Share9x.shi50_path := PAnsiChar(TmpDir); //Путь к ресурсу
 FillChar(Share9x.shi50_rw_password,
 SizeOf(Share9x.shi50_rw_password), #0); //Пароль полного доступа
 FillChar(Share9x.shi50_ro_password,
 SizeOf(Share9x.shi50_ro_password), #0); //Пароль для чтения
 NetShareAdd(nil,50,@Share9x,SizeOf(Share9x));
 end;
 FreeLibrary(FLibHandle);
end;

Обратите внимание на то, что переменные TmpNameNT и TmpDirNT освобождаются только после выполнения функции. Это критично, в противном случае структура переданная функции будет с двумя "незаполненными" полями. Также обратите внимание на то что в версии кода для Windows 9х все поля - представляющие собой массив Char элементов, вначале очищаются функцией FillChar, во избежание искажения данных (знак окончания строки равен #0). Данный код открывает новый ресурс на полный доступ. Рассматривать все виды открытия в данной статье я не имею возможности, за подробностями опять же отсылаю к MSDN.


Скрытие и показ ресурсов

Эта глава будет маленькая, никакого кода приводить не буду. Только объясню как можно добиться скрытия и показа ресурсов. Вы наверное уже обратили внимание на ресурсы в имени которых в конце стоит знак доллара. Это так называемые системные ресурсы. Манипулировать с ними я крайне не советую. Объясню почему. Во первых, ко всем этим ресурсам стоит полный доступ. Во вторых, при закрытии некоторых из системных ресурсов доступ к вашему компьютеру по сети может исчезнуть. В третьих, однажды я проэксперементировал с активацией и скрытием над системными ресурсами, после этого возникли неожиданные осложнения. Я попытался сделать активным ресурс "C$" в Windows XP, после этого я его, естественно, скрыл и перезагрузил систему. Каково же было мое удивление, когда я увидел что у меня появился ресурс "C" ( "C$" тоже присутствовал) дающий полный доступ к моему системному диску. Повторное его закрытие ничего не дало, ресурс снова появлялся после каждой перезагрузки системы. Проблема решилась тотальной правкой реестра (ключей уже к сожалению не помню). И это еще не самое страшное что может произойти. Как вы уже поняли скрыть ресурс можно простым добавлением к его имени знака доллара. Активировать, обратной операцией. Это естественно не правильно, но работает. Второй вариант скрыть ресурс, это удалить его и создать копию его но с правами SHI50F_SYSTEM или указанием shi502_security_descriptor (для этого нужно использовать структуру SHARE_INFO_502).
Не проводите манипуляции над следующими ресурсами:
IPC$, ADMIN$, PRINT$, WWWROOT$, BIOSINFO$, A$, B$, C$, D$, E$, F$, G$, H$, I$, J$, K$, L$, M$, N$, O$, P$, Q$, R$,S$, T$, U$, V$, W$, X$, Y$, Z$

У вас может возникнуть вопрос: "Для чего скрывать ресурсы?" Объясню, в моей домашней локальной сети ресурсы скрываются для того чтобы о них никто кроме нескольких избранных не знал. К примеру папки с исходниками, которые остальным "пользователям - не программистам" ни к чему. Некоторые таким образом прячут "экстремальные" фильмы ;) от детей своих "друзей - сетевиков".


Получение списка текущих сессий

С управлением ресурсами мы разобрались, теперь самое время перейти ко второй части, сетевым сессиям, т.е. с определением кто, когда подключился к нам (или удаленному компьютеру). Для определения пользователей подключенных к нашему компьютеру воспользуемся функцией NetSessionEnum

Объявление функции для Windows 9х - Ме:

var
 NetSessionEnum:function( pszServer : PChar;
 sLevel : DWORD;
 pbBuffer : Pointer;
 cbBuffer : DWORD;
 pcEntriesRead,
 pcTotalAvial : Pointer):integer; stdcall;

Параметры:
  pszServer - должен содержать имя удаленного компьютера на котором должна выполнится функция, если смотрим у себя то данному параметру нужно присвоить NIL.
  sLevel - должен содержать идентификатор структуры.
  pbBuffer - должен содержать указатель на массив структур.
  cbBuffer - должен содержать размер массива структур.
  pcEntriesRead - указатель на переменную содержащую общее кол-во структур
  pcTotalAvial - не используется

Объявление функции для Windows NT:

var
 NetSessionEnum:function( ServerName,
 UncClientName,
 Username : PWChar;
 Level : DWORD;
 bufptr : Pointer;
 prefmaxlen : DWORD;
 entriesread,
 totalentries,
 resume_handle : LPDWORD):DWORD; stdcall;

Параметры:
  ServerName - должен содержать имя удаленного компьютера на котором должна выполнится функция, если смотрим у себя то данному параметру нужно присвоить NIL.
  UncClientName - содержит указатель на строку содержащую имя сессии о которой мы хотим получить информацию, если нужно просмотреть все сессии параметру нужно присвоить NIL.
  UserName - содержит указатель на строку содержащую имя пользователя о котором мы хотим получить информацию, если нужно просмотреть всё, параметру нужно присвоить NIL.
  Level - должен содержать идентификатор структуры.
  Bufptr - должен содержать адрес указателя на массив структур.
  Prefmaxlen - должен содержать максимальную длину возвращенных данных в байтах, если не ставить ограничение то данному параметру нужно присвоить DWORD(-1)
  Entriesread - должен содержать указатель на переменную в которую запишется количество общих ресурсов доступных на данный момент.
  Totalentries - не используется
  Resume_handle - не используется, должен быть NIL

Существует также 6 типов структур передаваемых функции NetSessionEnum.
  SESSION_INFO_0 - только Windows NT
  SESSION_INFO_1 - только Windows NT
  SESSION_INFO_2 - только Windows NT
  SESSION_INFO_10 - только Windows NT
  SESSION_INFO_502 - только Windows NT
  session_info_50 - только Windows 9x-Me

Я опять рассмотрю только две из них как наиболее полные по своей сути.

Структура session_info_50:

Описание структуры:

type 
 TSessionInfo50 = packed record
 sesi50_cname : PChar;
 sesi50_username : PChar;
 sesi50_key : Cardinal;
 sesi50_num_conns : Word;
 sesi50_num_opens : Word;
 sesi50_time : Cardinal;
 sesi50_idle_time : Cardinal;
 sesi50_protocol : Byte;
 pad1 : Byte;
 end;

Поля:
  sesi50_cname - Содержит указатель на строку содержащую имя компьютера установившего сессию
  sesi50_username - Содержит указатель на строку содержащую имя пользователя установившего сессию
  sesi50_key - содержит значение при помощи которого мы будем завершать сессию
  sesi50_num_conns - содержит число подключений сделанных в течении сессии
  sesi50_num_opens - содержит кол-во файлов открытых в течении сессии
  sesi50_time - содержит время в секундах в течение которого сессия была активна
  sesi50_idle_time - содержит время в секундах в течение которого сессия была неактивна
  sesi50_protocol - содержит имя протокола, при помощи которого клиент связывается с сервером
  Pad1 - небольшой выравниватель структуры, не используется

Структура SESSION_INFO_502

Описание структуры:

type 
 TSessionInfo502 = packed record
 Sesi502_cname : PWideChar;
 Sesi502_username : PWideChar;
 Sesi502_num_opens : DWORD;
 Sesi502_time : DWORD;
 Sesi502_idle_time : DWORD;
 Sesi502_user_flags : DWORD;
 Sesi502_cltype_name : PWideChar;
 Sesi502_transport : PWideChar;
 End;
 PSessionInfo502 = ^TSessionInfo502;
 TSessionInfo502Array = array[0..512] of TSessionInfo502;
 PSessionInfo502Array = ^TSessionInfo502Array;

Поля:
  sesi502_cname - Содержит указатель на строку содержащую имя компьютера установившего сессию
  sesi502_username - Содержит указатель на строку содержащую имя пользователя установившего сессию
  sesi502_num_opens - содержит кол-во файлов открытых в течении сессии
  sesi502_time - содержит время в секундах в течение которого сессия была активна
  sesi502_idle_time - содержит время в секундах в течение которого сессия была неактивна
  sesi50_user_flags - значение описывающее как пользователь установил сессию (см. MSDN)
  sesi502_cltype_name - тип клиента установившего сессию, не используется
  sesi502_transport - содержит имя протокола, при помощи которого клиент связывается с сервером

Продолжение...

Получить ссылку на материал

Категория: Разные | Добавил: Барон (14.12.2011)
Просмотров: 1667 | Теги: сеть, Мониторинг, delphi | Рейтинг: 1.0/1
[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Поиск
Категории раздела
Web-приложения [6]
Почта [12]
Работа с HTTP [4]
Робота с XML [4]
Сервер [3]
Разные [50]
Королевство Delphi © 2010-2024
Яндекс цитирования