не правильно- сканировать нужно рекурсивно пока до компьютеров не доберемся (TNetResource.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER), а не 1 уровень (как здесь) или два (как в топике по ссылке).
Thread:
(*
ETNetCompEnum class represents a thread that scans "Microsoft Windows Network"
for all network computers. Computer names are stored in
"Computers" property. Wait for thread termination and get it.
EugeNet Artworks, 2005
*)unit ETNetCompEnum;
interface
uses
Windows, Classes, SysUtils;
type
TETNetCompEnum = class(TThread)
private{ Private declarations }
FComputers: TStrings;
procedure DoScan;
procedure ScanLevel( var _Res : TNetResource );
protected
procedure Execute; override;
published
constructor Create(CreateSuspended: Boolean);
property Computers : TStrings read FComputers write FComputers;
end;
implementation{ TETNetCompEnum }constructor TETNetCompEnum.Create(CreateSuspended: Boolean);
begin
inherited;
FComputers := TStringList.Create;
end;
procedure TETNetCompEnum.DoScan;
var
_lpNetResource : TNetResource;
begin
FillChar( _lpNetResource, SizeOf( _lpNetResource ), 0 );
with _lpNetResource do
begin
dwScope := RESOURCE_GLOBALNET;
dwType := RESOURCETYPE_DISK;
dwUsage := RESOURCEUSAGE_CONTAINER;
end;
ScanLevel( _lpNetResource );
end;
procedure TETNetCompEnum.Execute;
begin{ Place thread code here }
DoScan;
DoTerminate;
Terminate;
Free;
end;
procedure TETNetCompEnum.ScanLevel(var _Res: TNetResource);
var
_Enum : THandle;
_Buffer : array[1..10000] of TNetResource; //10000 entries max / 10000 элементов, понятно...
_BuffSize,
_ResCountMax : DWORD;
Cycle : Integer;
begin
_Enum := 0;
_ResCountMax := High( _Buffer );
try
if WNetOpenEnum( RESOURCE_GLOBALNET,
RESOURCETYPE_DISK, // no printers
0, // may add already connected flag to include connections that aren't visible
@_Res,
_Enum ) <> NO_ERROR then RaiseLastOSError;
_BuffSize := SizeOf( _Buffer );
if WNetEnumResource( _Enum,
_ResCountMax,
@_Buffer,
_BuffSize ) = NO_ERROR then
begin
for Cycle := 1 to _ResCountMax do
begin
case _Buffer[ Cycle ].dwDisplayType of
RESOURCEDISPLAYTYPE_NETWORK,
RESOURCEDISPLAYTYPE_GROUP, // RESOURCEDISPLAYTYPE_GROUP havn't been noticed, but I think it's needed
RESOURCEDISPLAYTYPE_DOMAIN : ScanLevel( _Buffer[ Cycle ] );
RESOURCEDISPLAYTYPE_SERVER : FComputers.Add(
_Buffer[ Cycle ].lpRemoteName );
end;
end;
end;
finally
if _Enum <> 0 then WNetCloseEnum( _Enum );
end;
end;
end.
Сорри за англ комментарии- привычка. Все нужное выделено жирным...
из программы вызываем так:
procedure TForm1.StartClick(Sender: TObject);
begin
TETNetCompEnum.Create( False ).OnTerminate := EndClick
end;
procedure TForm1.EndClick(Sender: TObject);
begin
ListBox1.Items.AddStrings( TETNetCompEnum( Sender ).Computers )
end;
Здравствуйте, EugeNet.Spb, Вы писали:
ES>Вроде сделал я компонент в виде Thread-а.
Лучше передавать в него TStrings при инициализации, и обложить соответствующий Add вызовом Synchronize. Тогда в твой тред можно будет передавать прямо TMemo.Lines, и еще много всяких свойств, без написания отдельного дожидающегося и копирующего кода. Помимо всего прочего, ты сразу сможешь видеть прогресс.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, EugeNet.Spb, Вы писали:
ES>Вроде сделал я компонент в виде Thread-а.
Еще косячок-с: в доке рекомендуется не только выделить буфер разумного размера, но и проверить после вызова состояние переменной, переданной в lpBufferSize для определения необходимости повторного вызова.
Особенно приятно то, что ты позаботился о забивании стека рекурсивной функции. За что не любят рекурсию? Правильно — она жрет стек. Поэтому в рекурсивных функциях стараются держать фрейм компактным. А ты так бодро выделяешь там по тридцать два килобайта... Да ты смельчак!
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.