在C#中重命名文件夹时,如果(Windows 7)资源管理器窗口当前打开了该文件夹或任何子文件夹,则System.IO.IOException
会抛出RENAME
(消息"访问被拒绝") 。
使用命令行SHFileOperation()
也会失败。
使用第二个浏览器窗口成功。
即使在折叠父文件夹(或其父文件夹)后,错误仍然存在。实际上,需要关闭特定的资源管理器窗口。 因此,探索器似乎只是为了显示文件夹结构而创建一些锁,即使实际文件夹不再显示也不会释放它们(这是纯粹的非文本IMO)。
有没有办法重命名文件夹(在程序中,例如使用C#),目前在资源管理器窗口中显示(或可见,见上文)?
更新
使用from python_utilities import tools
找到我自己对此问题的回答(见下文)所描述的方法。但是,这种解决方案不太可行(另见下文)。
答案 0 :(得分:5)
我使用API Monitor v2 by Rohitab来监控Windows API调用。
将目录名从D:\test
更改为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
与FILE_OPEN_FOR_BACKUP_INTENT
和其他人一起打开原始目录,然后使用NtSetInformationFile
调用FileRenameInformation
新目录名称和标记为here的标记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);
。
不幸的是,这些都是内核调用。
您可以从用户模式获取C / C ++目录的句柄,如下所示:
NtSetInformationFile
但是,您仍需要NtSetInformationFile
- 呼叫的用户模式替代方案。
要继续的一些选项(按复杂程度排序):
ITransferSource::RenameItem
或查找即用型shell函数DeviceIoControl
(SetAssemblyFileVersion target) ->
C:\WORKSPACE\Backend\Back-End\msbuild-by-convention\Scripts\targets.msbuild(207,3): error MSB4018: The "Attrib" task failed unexpectedly. [C:\WORKSPACE\Backend\Back-End\Build\Scripts\main.msbuild]
C:\WORKSPACE\Backend\Back-End\msbuild-by-convention\Scripts\targets.msbuild(207,3): error MSB4018: System.ArgumentException: Illegal characters in path. [C:\WORKSPACE\Backend\Back-End\Build\Scripts\main.msbuild]
。<强>更新强>
似乎SHFileOperation
函数执行上述所有操作。
将在线留下这个答案,因为它可能会向其他人展示如何调试类似问题并获得有价值的指示。
答案 1 :(得分:3)
所以我在进一步研究之后回答了我自己的问题。
可以使用SHFileOperation()
重命名该文件夹,如下所示:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb776887%28v=vs.85%29.aspx
(这是否使用了Wouter提到的'魔术'。 - - )
但是如果有{/ 1}}等Windows / .Net API,WTF我是否需要使用Shell?不是谈论表现......
无论如何,使用System.IO.Directory.Move
是一个痛苦的...使用C#,因为你需要声明所有这些p调用的东西。在这种特殊情况下,您需要为32位和64位窗口使用不同的结构,因为打包是不同的(请参阅http://www.pinvoke.net/default.aspx/shell32.shfileoperation)。这非常麻烦,因为通常我会将 AnyCPU 指定为目标。此时您需要在运行时进行分支(确实非常糟糕),这取决于您是64位还是32位进程,还是针对两个不同的目标进行不同的构建,这对于解决这个愚蠢的资源管理器来说是一个非常大的影响。
此致
答案 2 :(得分:0)
我遇到了同样的问题。只要我打开一个资源管理器窗口并导航到要重命名的文件夹,Directory.Move
就会失败并且拒绝访问&#34;访问被拒绝&#34; (Windows 7 Professional 64位,应用程序编译为x86)。
有趣的是,命令Microsoft.VisualBasic.FileIO.FileSystem.MoveDirectory(...)
成功将内容移动到新目录,如果您要停留在要移动的目录的子文件夹中,它只能删除旧目录。这可以通过捕获第一个错误引发的异常并再次尝试再次尝试来解决。现在也删除了源文件夹。