【问题标题】:How I can list the contents of a folder of a remote machine如何列出远程计算机文件夹的内容
【发布时间】:2011-10-09 14:51:51
【问题描述】:

我正在寻找 Windows api 函数或其他方法来获取位于我的 LAN 上的计算机中的文件夹的内容(文件夹和文件)。当然,对于我想要访问的每台机器,我都有一个有效的 Windows 用户和密码。

【问题讨论】:

  • 看看这里:stackoverflow.com/questions/5433570/…。虽然它在 C# 中。
  • 感谢@Mrchief,但我需要列出any folder 的内容,而不仅仅是共享。
  • 您可以指定:ResourceDisplayType.Any。再想一想,ResourceDisplayType.Share 并不意味着共享文件夹(它包括共享文件夹,是的,但它只是说不要给我的打印文件夹等)
  • 如果文件夹真正未被共享,您将无法看到它们。但是,除非有人采取措施删除它们,否则每个驱动器(至少是硬盘驱动器)的根目录通常都会有一个管理共享。这些通常命名为“C$”、“D$”等。我会强烈建议不要依赖他们的存在。

标签: windows delphi winapi networking delphi-xe


【解决方案1】:

您可以使用 WMI ,检查 CIM_DataFileCIM_Directory 类。

一些注意事项

1.首先您必须在客户端机器上启用 wmi 远程访问。阅读这些文章,了解如何做到这一点以及 Windows 版本 Connecting to WMI on a Remote ComputerSecuring a Remote WMI Connection 之间的区别。

2.始终必须使用过滤器(Where 条件)来限制这些 WMI 类的结果。

3.始终必须使用Drive 字段作为条件,因为这些类返回所有驱动器的文件。

4.Wmi 将\(反斜杠)字符解释为保留符号,因此您必须对该字符进行转义以避免WQL 语句出现问题。

德尔福代码

{$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.

【讨论】:

  • +1 Kewl WMI 使用!然而,远程启用它的需要确实让人们对 WMI 解决方案的喜爱有所降温。在大型企业环境中的更好解决方案,您可以通过组策略将 WMI 启用。
【解决方案2】:

没有授权部分,就很简单了。进行授权的正确方法是调用 Windows.pas 方法WNetAddConnection2 并走这条路。

但是,因为我处于简单的破解模式,所以我尝试了这个,它基本上可以工作:

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;

对于 ShellExecute “网络使用”的丑陋黑客攻击深表歉意。 (咧嘴笑)请注意,我选择“挂载”这个共享文件夹而不给它一个驱动器号,避免了如果该驱动器已经映射了该怎么办的问题。

这是一个good link,我将链接到 WNetAddConnection2 代码示例而不是偷猎。它展示了一个非邪恶方法的示例。 :-) 然后你可以使用我上面显示的目录枚举代码。

【讨论】:

    【解决方案3】:

    我想这包含在 Warren 的回答中,但切入正题,IOUtils.TDirectory 支持 UNC:

    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;
    

    等等等等……

    【讨论】:

      猜你喜欢
      • 2012-07-09
      • 2016-07-03
      • 1970-01-01
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-11-17
      • 1970-01-01
      相关资源
      最近更新 更多