Это один из тех вопросов, который иногда пробегает по иерархии RU.DELPHI.*. В этой статье мы рассмотрим, как можно получить список компьютеров в сети. Для начала вспомним, что сетевые ресурсы организованы в виде дерева: на самом верхнем уровне идут домены и рабочие группы, затем сервера (компьютеры), затем ресурсы, предоставляемые серверами. Таким образом, вопрос немного видоизменяется: как получить дерево сетевых ресурсов. Для этого используется тройка функций WNetOpenEnum, WNetEnumResource и WNetCloseEnum, в ч╠м-то напоминающая FindFirst, FindNext и FindClose. Единицей хранения информации об узле дерева сетевых ресурсов является структура типа TNetResource. TNetResource = packed record dwScope: DWORD; dwType: DWORD; dwDisplayType: DWORD; dwUsage: DWORD; lpLocalName: PAnsiChar; lpRemoteName: PAnsiChar; lpComment: PAnsiChar; lpProvider: PAnsiChar; end; Для того, чтобы прочитать список подузлов любого узла дерева, используется функция WNetOpenEnum: function WNetOpenEnum(dwScope, dwType, dwUsage: DWORD; lpNetResource: PNetResource; var lphEnum: THandle): DWORD; stdcall; Для корневого узла дерева в качестве lpNetResource надо указать nil. Функция предоставляет нам доступ к дескриптору lphEnum, с помощью которого и выполняется вся основная работа. Итак, функция, непосредственно читающая данные о сетевых ресурсах, называется WNetEnumResource. function WNetEnumResource(hEnum: THandle; var lpcCount: DWORD; lpBuffer: Pointer; var lpBufferSize: DWORD): DWORD; stdcall; Эта функция работает в одном из двух режимов: либо мы читаем список в цикле, каждый раз заполняя и обрабатывая небольшой буфер; либо сразу выделяем буфер необходимого размера. В первом случае мы должны выделить буфер под массив структур TNetResource и вызывать функцию WNetEnumResource до тех пор, пока она не верн╠т значение ERROR_NO_MORE_ITEMS. Переменная lpBufferSize должна содеражть правильный размер массива. Во втором случае lpBufferSize должна содержать значение, меньшее, чем размер одной структуры TNetResource тогда WNetEnumResource запишет в эту переменную требуемый размер массива в байтах. Давайте рассмотрим первый способ на примере: type TNetEnumResourcesCallback = procedure(NetResource: TNetResource); procedure NetEnumResources(Root: PNetResource; Proc: TNetEnumResourcesCallback); const MAX_RES = 16; type PResources = ^TResources; TResources = array[0..MAX_RES-1] of TNetResource; var hEnum: THandle; Count: Integer; Res: Integer; Resources: PResources; BufferSize: Integer; I: Integer; sbegin // Открываем доступ к перечню сетевых ресурсов Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, lpNetResource, hEnum); if NO_ERROR <> Res then Exit; // Массив, в который читаются сетевые ресурсы BufferSize := SizeOf(TResources); GetMem(Resources, BufferSize); while True do begin // Загружаем перечень ресурсов в массив // Если возникла ошибка, значит, ресурсов больше нет --- покидаем цикл Count := MAX_RES; Res := WNetEnumResource(hEnum, Count, Resources, BufferSize); if (Res <> NO_ERROR) and (Res <> ERROR_MORE_DATA) then Break; // В противном случае копируем сетевые ресурсы... for I := 0 to Count - 1 do begin Proc(Resources^[I]); if (Resources^[I].dwUsage and RESOURCEUSAGE_CONTAINER) <> 0 then NetEnumResources(@(Resources^[I]), Proc); end; end; FreeMem(Resources); // Закрываем доступ WNetCloseEnum(hEnum); end; Функция NetEnumResources может быть использована для построения дерева сетевых ресурсов. Для каждого сетевого ресурса (TNetResource) она вызывает пользовательскую процедуру Proc. Я написал программу, которая строит дерево сетевых ресурсов. Вот пример дерева в нашей локальной сети: |