Окончательный вариант:
ETNetCompEnum.pas
(*
TETNetCompEnum 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
////////////////////////////////////////////////////////////////////////////////
Short help:
property Computers : TStrings - List of computers ('\\Server').
Get on OnTerminate.
property Shares : TStrings - Additionally scan SHARES
(to use with FindFirst / FindNext files enum)
Get on OnTerminate.
property ScanShares : Boolean - By default, thread creates and
anumerates computers ONLY.
property ScanAdminShares : Boolean - Also scan administrative shares
("\\Server\c$", "\\Server\admin$" ...)
function GetNetShares( _Comp : String ) : TStrings - Returns all shares as
list (incl. admin. shares)
_Comp is '\\CompName'
!!! Works ONLY on NT !!!
////////////////////////////////////////////////////////////////////////////////
HowTo Use:
--------------------------------------------------------------------------------
1. Scan computers:
procedure TForm1.FormCreate(Sender: TObject);
begin
TETNetCompEnum.Create( False ).OnTerminate := EndScanNet;
end;
procedure TForm1.EndScanNet(Sender: TObject);
begin
ListBox1.Items.AddStrings( TETNetCompEnum( Sender ).Computers );
end;
--------------------------------------------------------------------------------
2. Scan shares:
procedure TForm1.FormCreate(Sender: TObject);
begin
with TETNetCompEnum.Create( TRUE ) do
begin
OnTerminate := EndScanNet;
ScanShares := TRUE;
Resume;
end;
end;
procedure TForm1.EndScanNet(Sender: TObject);
begin
ListBox1.Items.AddStrings( TETNetCompEnum( Sender ).Computers );
end;
--------------------------------------------------------------------------------
*)
unit ETNetCompEnum;
interface
uses
Windows, Classes, SysUtils;
type
TETNetCompEnum = class(TThread)
private
{ Private declarations }
FComputers: TStrings;
FShares: TStrings;
FScanShares: Boolean;
FScanAdminShares: Boolean;
procedure DoScan;
procedure ScanLevel( var _Res : TNetResource );
protected
procedure Execute; override;
published
constructor Create(CreateSuspended: Boolean);
property Computers : TStrings read FComputers write FComputers;
property Shares : TStrings read FShares write FShares;
property ScanShares : Boolean read FScanShares write FScanShares default False;
property ScanAdminShares : Boolean read FScanAdminShares write FScanAdminShares default False;
end;
// Types of NetApi32.dll
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;
TShareInfo2Array = array [0..512] of TShareInfo2;
PShareInfo2Array = ^TShareInfo2Array;
function NetShareEnum( servername : PWChar; level : DWORD; bufptr : Pointer;
prefmaxlen : DWORD; entriesread, totalentries,
resume_handle : LPDWORD ) : DWORD;
stdcall; external 'Netapi32.dll';
function GetNetShares( _Comp : String ) : TStrings;
const
// Netapi32.dll
NERR_Success = 0;
MAX_PREFERRED_LENGTH = DWORD( -1 );
(*
STYPE_DISKTREE = 0;
STYPE_PRINTQ = 1;
STYPE_DEVICE = 2;
STYPE_IPC = 3;
STYPE_SPECIAL = $80000000;
*)
implementation
{ TETNetCompEnum }
constructor TETNetCompEnum.Create(CreateSuspended: Boolean);
begin
inherited;
FScanShares := False;
FScanAdminShares := False;
FComputers := TStringList.Create;
Shares := 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;
_BuffSize,
_ResCountMax : DWORD;
Cycle : Integer;
procedure LocalAddComps;
begin
FComputers.Add( _Buffer[ Cycle ].lpRemoteName );
end;
procedure LocalAddSHARES;
begin
FShares.Add( _Buffer[ Cycle ].lpRemoteName );
end;
begin
_Enum := 0;
_ResCountMax := High( _Buffer );
try
if WNetOpenEnum( RESOURCE_GLOBALNET,
RESOURCETYPE_DISK,
0,
@_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_DOMAIN : ScanLevel( _Buffer[ Cycle ] );
RESOURCEDISPLAYTYPE_SERVER : begin
LocalAddComps;
if FScanShares then
if FScanAdminShares then
FShares.AddStrings( GetNetShares(
_Buffer[ Cycle ].lpRemoteName ) )
else
ScanLevel( _Buffer[ Cycle ] );
end;
RESOURCEDISPLAYTYPE_SHARE : if NOT FScanAdminShares then
LocalAddSHARES;
end;
end;
end;
finally
if _Enum <> 0 then WNetCloseEnum( _Enum );
end;
end;
function GetNetShares( _Comp : String ) : TStrings;
var
_ShareNum,
_ShareTotal,
_ShareHandle : DWORD;
Cycle : Integer;
_SHARE_INFO : PShareInfo2Array;
_CompName : Array [ 0..511 ] of WideChar;
begin
Result := TStringList.Create;
_ShareHandle := 0;
StringToWideChar( _Comp, _CompName, SizeOf( _CompName ) );
// You may add WNetAddConnection2 here to be able to ask user for login/pass
if NetShareEnum( _CompName,
2,
@_SHARE_INFO,
MAX_PREFERRED_LENGTH,
@_ShareNum,
@_ShareTotal,
@_ShareHandle ) = NERR_Success then
for Cycle := 0 to _ShareNum - 1 do
Result.Add( _Comp + '\' + _SHARE_INFO^[ Cycle ].shi2_netname );
end;
end.
Еще раз сорри за инглиш.