如何重命名c#中当前由Windows资源管理器打开的文件夹

2024-04-17

在 C# 中重命名文件夹时,System.IO.Directory.Move throws System.IO.IOException(消息“访问被拒绝”)如果该文件夹或任何子文件夹当前由 (Windows 7) 资源管理器窗口打开。 使用命令行RENAME也失败了。 使用第二个资源管理器窗口成功。

即使折叠父文件夹(或其父文件夹)后,该错误仍然存​​在。事实上,需要关闭特定的资源管理器窗口。 因此,资源管理器似乎创建了一些锁只是为了显示文件夹结构,并且即使不再显示实际文件夹也不会释放它们(在我看来,这纯粹是胡说八道)。

有没有办法重命名当前由资源管理器窗口显示(或可见,见上文)的文件夹(在程序中,例如使用 C#)?

Update

找到了一种方法,如我自己对这个问题的回答所描述的(见下文)使用SHFileOperation()。然而,这个解决方案不太可行(另见下文)。


我用过Rohitab 的 API 监视器 v2 http://www.rohitab.com/apimonitor监视 Windows API 调用。

更改目录名称时D:\test to D:\abc,此调用已记录:

explorerframe.dll   ITransferSource::RenameItem ( 0x0000000015165738, "abc", TSF_COPY_CREATION_TIME | TSF_COPY_LOCALIZED_NAME | TSF_COPY_WRITE_TIME | TSF_DELETE_RECYCLE_IF_POSSIBLE, 0x00000000150f77d0 )

进一步挖掘监视器的输出显示了一些本机调用:

正如你所看到的,他们没有使用MoveFile,相反,他们使用NtOpenFile with FILE_OPEN_FOR_BACKUP_INTENT等打开原目录,然后调用NtSetInformationFile使用新的目录名称和标志FileRenameInformation这是有记录的here https://msdn.microsoft.com/en-us/library/windows/hardware/ff567096(v=vs.85).aspx.

不幸的是,这些都是内核调用。

您可以从用户模式获取 C/C++ 中目录的句柄,如下所示:

HANDLE h = ::CreateFileA("D:\\test",
    DELETE | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS,
    NULL);

但是,您仍然需要一个用户模式替代方案NtSetInformationFile-call.

一些要继续的选项(按复杂性排序):

  • 看看是否可以使用shell接口ITransferSource::RenameItem https://msdn.microsoft.com/en-us/library/windows/desktop/bb774535(v=vs.85).aspx或者找到一个现成的 shell 函数
  • 进一步深入研究用户模式解决方案并尝试找到替代方案NtSetInformationFile
  • 编写一个包含执行这些内核模式操作的 IOCTL 的驱动程序并调用DeviceIoControl来自 C#。

Update

似乎是SHFileOperation https://msdn.microsoft.com/en-us/library/windows/desktop/bb762164(v=vs.85).aspx函数执行 OP 发现的上述所有操作。

将把这个答案留在网上,因为它可能会向其他人展示如何调试类似的问题并获得有价值的指导。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何重命名c#中当前由Windows资源管理器打开的文件夹 的相关文章

随机推荐