Как получить список компьютеров в локальной сети - by Mark Shevchenko
 ( выдержки из документа )

Это один из тех вопросов, который иногда пробегает по иерархии RU.DELPHI.*. В этой статье мы рассмотрим, как можно получить список компьютеров в сети. Для начала вспомним, что сетевые ресурсы организованы в виде дерева: на самом верхнем уровне идут домены и рабочие группы, затем сервера (компьютеры), затем ресурсы, предоставляемые серверами. Таким образом, вопрос немного видоизменяется: как получить дерево сетевых ресурсов.

Для этого используется тройка функций WNetOpenEnum, WNetEnumResource и WNetCloseEnum, в чeм-то напоминающая 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.