Re: Работа с сетевыми ресурсами [Окончание !!]
От: EugeNet.Spb  
Дата: 27.01.05 10:32
Оценка:
Окончательный вариант:


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.


Еще раз сорри за инглиш.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.