delphi - 如何在Delphi中正确使用IFileOperation删除文件夹中的文件

标签 delphi winapi

我正在尝试创建一个使用 IFileOperation 删除文件中的简单示例 给定目录,包含在另一个 q 的答案中,以便与其他方法进行比较。

下面是我的MRE的代码。它 成功在 C:\Temp 的子目录中创建 1000 个文件,然后尝试删除 它们位于 DeleteFiles 方法中。这个看似“简单”的任务失败了,但我不确定 正是它脱轨的地方。代码中的注释显示了我的期望 和实际结果。有一次,我没有看到异常,而是弹出了一个窗口 要求确认删除名称奇怪的项目,该项目显然是一个数组 引用 shell 项目的数字,但我尝试使用 Ctrl-C 捕获它失败了;

我相当确定我错过了一两个步骤,滥用了所涉及的接口(interface) 或两者。我的问题是,任何人都可以显示对代码的必要更正,以使 IFileOperation.DeleteItems() 删除有问题的文件,因为我完全不了解这些东西?我对使用 shell 接口(interface)或其他方式删除这些文件的替代方法不感兴趣。

procedure TForm2.DeleteFiles;
var
  iFileOp: IFileOperation;
  iIDList : ItemIDList;
  iItemArray : IShellItemArray;
  iArray : Array[0..1] of ItemIDList;
  Count : DWord;
begin
  iFileOp := CreateComObject(CLSID_FileOperation) as IFileOperation;

  iIDList := ILCreateFromPath(sPath)^;

  //  IFileOperation.DeleteItems seems to require am IShellItemArray, so the following attempts
  //  to create one
  //  The definition of SHCreateShellItemArrayFromIDLists
  //  seems to require a a zero-terminated array of ItemIDLists so the next steps
  //  attempt to create one

  ZeroMemory(@iArray, SizeOf(iArray));
  iArray[0] := iIDList;
  OleCheck(SHCreateShellItemArrayFromIDLists(1, @iArray, iItemArray));

  //  Next test the number of items in iItemArray, which I'm expecting to be 1000
  //  seeing as the CreateFiles routine creats that many

  OleCheck(iItemArray.GetCount(Count));
  Caption := IntToStr(Count);  //  Duh, this shows Count to be 1, not the expected 1000

  OleCheck(iFileOp.DeleteItems(iItemArray));
  OleCheck( iFileOp.PerformOperations );
  // Returns Exception 'No object for moniker'

end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  DeleteFiles;
end;

procedure CreateFiles;
var
  i : Integer;
  SL : TStringList;
  FileName,
  FileContent : String;
begin

  SL := TStringList.Create;
  try
    if not (DirectoryExists(sPath)) then
      MkDir(sPath);

    SL.BeginUpdate;
    for i := 0 to 999 do begin
      FileName := Format('File%d.Txt', [i]);
      FileContent := Format('content of file %s', [FileName]);
      SL.Text := FileContent;
      SL.SaveToFile(sPath + '\' + FileName);
    end;
    SL.EndUpdate;
  finally
    SL.Free;
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  CreateFiles;
end;

最佳答案

您正在泄漏 ILCreateFromPath() 返回的内存,当您使用完返回的 PItemIDList 后,您需要调用 ILFree() .

此外,您不应该取消引用 PItemIDListSHCreateShellItemArrayFromIDLists() 需要一个 PItemIDList 指针数组,但您给它一个 ItemIDList 实例数组。

试试这个:

procedure TForm2.DeleteFiles;
var
  iFileOp: IFileOperation;
  iIDList : PItemIDList;
  iItemArray : IShellItemArray;
  Count : DWord;
begin
  iFileOp := CreateComObject(CLSID_FileOperation) as IFileOperation;

  iIDList := ILCreateFromPath(sPath);
  try
    OleCheck(SHCreateShellItemArrayFromIDLists(1, @iIDList, iItemArray));
  finally
    ILFree(iIDList);
  end;

  //  Next test the number of items in iItemArray, which I'm expecting to be 1000
  //  seeing as the CreateFiles routine creates that many

  OleCheck(iItemArray.GetCount(Count));
  Caption := IntToStr(Count);  //  Duh, this shows Count to be 1, not the expected 1000

  OleCheck(iFileOp.DeleteItems(iItemArray));
  OleCheck( iFileOp.PerformOperations );
  // Returns Exception 'No object for moniker'
end;

话虽如此,即使工作正常,您也不会为各个文件创建包含 1000 个 IShellItemIShellItemArray。您正在为 C:\Temp 子目录本身创建一个 IShellItemArray,其中包含 1 个 IShellItem

如果您的目标是删除整个文件夹,那么这很好。但在这种情况下,我建议改用 SHCreateItemFromIDList()SHCreateItemFromParsingName(),然后将该 IShellItem 传递给 IFileOperation。删除项目()

但是,如果您的目标是删除单个文件而不删除子目录,那么您必须:

  • 获取子目录的 IShellFolder 接口(interface),然后使用 IShellFolder.EnumObjects() 枚举其文件的相对 PIDL,然后将 PIDL 传递到数组到 SHCreateShellItemArray()

  • 获取子目录的 IShellFolder 接口(interface),然后使用 IShellFolder.GetUIObjectOf() 查询其 IDataObject 接口(interface),以及然后使用 SHCreateShellItemArrayFromDataObject(),或者直接将 IDataObject 提供给 IFileOperation.DeleteItems()

  • 获取子目录的 IShellItem 接口(interface),然后使用 IShellItem.BindToHandler() 查询其 IEnumShellItems 接口(interface),然后通过直接到 IFileOperation.DeleteItems()

关于delphi - 如何在Delphi中正确使用IFileOperation删除文件夹中的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58597454/

相关文章:

Excel 从 VCL 表单中窃取键盘焦点(在 AddIn 中)

delphi - 从远程 FTP 下载文件列表

Windows Kit 8.0 和 Visual Studio 2012 - 它们是一起发货的吗?

c++ - NetUserAdd() 成功,但用户为 "invisible"

delphi - 为自定义组件中存储在 DFM 上的属性检索到错误值

Delphi 报表组件,为最终用户提供可视化控件

c++ - 折叠 TreeView 中的所有节点,最后展开的节点除外

.net - 创建一个尊重 "Append Data"NTFS 权限的 FileStream

python - 如何使用 WMI 和 Python 弹出 CD?

delphi - 调整主菜单大小以获得高 DPI/字体大小