开发者

How I can list the contents of a folder of a remote machine

I'm looking for a windows api function or another way to get the开发者_JAVA百科 content (folder and files) of a folder located in a machine on my LAN. off course which I have a valid windows user and password for every machine which I want to access.


You can use the WMI , check the CIM_DataFile and CIM_Directory classes.

Some Notes

1.First you must enable the wmi remote access in the client machines. Read these articles to see how do this and the differences between windows versions Connecting to WMI on a Remote Computer, Securing a Remote WMI Connection.

2.Always you must use filters (Where conditions) to restrict the result of these WMI classes.

3.Always you must use the Drive field as condition, because these classes return the files of all drives.

4.The Wmi interprets the \ (Backslash) character as a reserverd symbol so you must need to escape that character to avoid problems with the WQL sentence.

Delphi Code

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

procedure  GetRemoteFolderContent(Const WbemComputer,WbemUser,WbemPassword,Path:string);
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;    
  WmiPath       : string;
  Drive         : string;
begin;
  //The path  
  //Get the drive 
  Drive   :=ExtractFileDrive(Path);
  //get the path and add a backslash to the end
  WmiPath :=IncludeTrailingPathDelimiter(Copy(Path,3,Length(Path)));
  //escape the backslash character
  WmiPath :=StringReplace(WmiPath,'\','\\',[rfReplaceAll]);

  Writeln('Connecting');
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //Establish the connection
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);

  Writeln('Files');
  Writeln('-----');
  //Get the files from the specified folder
  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_DataFile Where Drive="%s" AND Path="%s"',[Drive,WmiPath]),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('%s',[FWbemObject.Name]));
    FWbemObject:=Unassigned;
  end;

  Writeln('Folders');
  Writeln('-------');
  //Get the folders from the specified folder
  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_Directory Where Drive="%s" AND Path="%s"',[Drive,WmiPath]),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('%s',[FWbemObject.Name]));
    FWbemObject:=Unassigned;
  end;
end;


begin
 try
    CoInitialize(nil);
    try
      GetRemoteFolderContent('remote_machine','user','password','C:\');
      GetRemoteFolderContent('remote_machine','user','password','C:\Program Files');
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.


Without the authorization part, it's simple enough. The right way to do the authorization is to call Windows.pas method WNetAddConnection2 and go that way.

However, because I'm in a simple hack mode, I tried this, and it basically works:

uses Types, IOUtils, ShellApi; // Works in Delphi XE.

procedure TForm5.Button1Click(Sender: TObject);
var
 dirs:TStringDynArray;
 files:TStringDynArray;
 apath, dir,filename:String;
begin
 ListBox1.Items.Clear;
 apath := '\\hostname\sharename';

// This should be calling WNetAddConnection2:
// instead It's an evil (portable) hack.
 ShellExecute(HWND(0), 'open', PChar('net use /delete '+  apath), 
    nil,nil,SW_SHOW );
 ShellExecute(HWND(0), 'open', PChar('net use '+ apath+' /user:uid pswd'),
    nil,nil,SW_SHOW );

  dirs := TDirectory.GetDirectories(apath);
  if Length(dirs)=0 then
      ListBox1.Items.Add('None found.')
  else
  for dir in dirs do
      ListBox1.Items.Add('Directory: '+dir);
  files := TDirectory.GetFiles(apath);
  for filename in files do
      ListBox1.Items.Add('File: '+filename );

end;

Abject Apologies for the ugly hack of ShellExecute "net use". (Grin) Note that I have elected to "mount" this shared folder without giving it a drive letter, avoiding the problem of what to do if that drive is already mapped.

Here's a good link with a WNetAddConnection2 code sample that I will link to instead of poaching. It shows a sample of the non-evil way to do it. :-) Then you can use the Directory enumeration code as I have shown above.


I suppose this is included in Warren's answer, but to cut to the chase, IOUtils.TDirectory supports UNCs:

implementation
uses IOUtils,types;

procedure GetFiles;
var
  i: integer;
  files: TStringDynArray;
begin
  files := TDirectory.GetFiles('\\aServer\aPath\aShare\', '*.aFileFilter');
  for i := Low(files)to High(files) do
       memo1.Lines.Add(files[i]);
end;

etc, etc...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜