使用IFileOperation在副本期间创建目录
使用Stephen Toub的C#( link )的IFileOperation包装器,直到现在一直运行良好。 现在我正在尝试复制以从网络位置收集文件,将每个网络位置收集到其自己的子目录中。
\\FOO\data
into C:\gather\Foo_data
\\BAR\manage\current
进入C:\gather\bar\manage
等等。 问题出在FileOperation.CopyItem
。 必须是因为目标目录还不存在 – IFileOperation
将在复制期间创建它,对吗? 我使用了另一个问题的技术,并将Toub的FileOperation.CreateShellItem
更改为:
private static ComReleaser CreateShellItem( string path ) { try { return new ComReleaser( (IShellItem)SHCreateItemFromParsingName( path, null, ref _shellItemGuid ) ); } catch ( FileNotFoundException ) { IntPtr pidl = SHSimpleIDListFromPath( path ); IShellItem isi = (IShellItem)SHCreateItemFromIDList( pidl, ref _shellItemGuid ); Marshal.FreeCoTaskMem( pidl ); System.Diagnostics.Debug.WriteLine( "Shell item: " + isi.GetDisplayName( SIGDN.DesktopAbsoluteParsing ) ); return new ComReleaser( isi ); } }
我把Debug.WriteLine
放在那里检查它是否正常工作,它看起来工作正常; 它把路径写回来了。
但IFileOperation.CopyItem
抛出ArgumentException
,我无法弄清楚原因。 我没有正确地为“不存在的文件”执行“ IShellItem
”吗? 我怀疑我需要在那里获得SFGAO_FOLDER
,因为我正在尝试为不存在的目录而不是文件创建一个IShellItem
,但是如何?
在本周末进行了大量谷歌搜索和编码实验(这是一个疯狂的派对周末)后,我找到了解决方案。
- 编写一个实现
IFileSystemBindData
的COM兼容类。 - 分配
WIN32_FIND_DATA
结构并设置其dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY
。 (据我所知,其他成员在这里无关紧要。) - 创建
IFileSystemBindData
类的实例。 - 将
WIN32_FIND_DATA
对象传递给IFileSystemBindData::SetFindData
。 - 创建
IBindCtx
的实例。 - 使用
STR_FILE_SYS_BIND_DATA
(#define
d作为L"File System Bind Data"
)和IFileSystemBindData
对象的参数调用其IBindCtx::RegisterObjectParam
。 - 使用要创建的目录的路径名和您的
IBindCtx
对象调用SHCreateItemFromParsingName
。
有用。 绑定上下文对象告诉SHCreateItemFromParsingName
不要查询文件系统,只使用它给出的内容。 我让IFileOperation
将一个文件复制到一个新的,巧妙命名的目录D:\Some\Path\That\Did\Not\Previously\Exist
,并且它创建了所有七个目录。 据推测,可以使用相同的技术为任何不存在的文件系统对象创建IShellItem
,具体取决于您在dwFileAttributes
放置的dwFileAttributes
。
但它很难看。 我希望有更好的方法。 我的编码实验是用C ++编写的; 现在编写COM互操作的东西再用C#做。 或者也许更容易抛出项目并重新开始使用C ++。