使用IFileOperation在副本期间创建目录

时间:2012-08-10 12:52:40

标签: c# com

使用Stephen Toub的C#(link)的IFileOperation包装器,直到现在一直运行良好。现在我正在尝试复制以从网络位置收集文件,将每个网络位置收集到其自己的子目录中。

\\FOO\data加入C:\gather\Foo_data
\\BAR\manage\current进入C:\gather\bar\manage

等等。问题出在FileOperation.CopyItem。必须是因为目标目录尚不存在 - IFileOperation将在复制期间创建它,对吗?我使用another question中的技术并将Toub的FileOperation.CreateShellItem改为:

private static ComReleaser<IShellItem> CreateShellItem( string path )
{
    try
    {
        return new ComReleaser<IShellItem>( (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<IShellItem>( isi );
    }
}

我把Debug.WriteLine放在那里检查它是否正常工作,它似乎工作正常;它把路径写回来。

IFileOperation.CopyItem会抛出ArgumentException,我无法弄清楚原因。我没有正确地为“不存在的文件”执行“IShellItem”吗?我怀疑我需要在那里获得SFGAO_FOLDER,因为我正在尝试为不存在的目录创建IShellItem,而不是文件,但是如何?

1 个答案:

答案 0 :(得分:6)

经过本周末的大量谷歌搜索和编码实验(这是一个疯狂的派对周末),我找到了解决方案。

  1. 编写一个实现IFileSystemBindData的COM兼容类。
  2. 分配WIN32_FIND_DATA结构并设置其dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY。 (其他成员在这里是无关紧要的,据我测试一样。)
  3. 创建IFileSystemBindData班级的实例。
  4. WIN32_FIND_DATA对象传递给IFileSystemBindData::SetFindData
  5. 创建IBindCtx
  6. 的实例
  7. 使用IBindCtx::RegisterObjectParamSTR_FILE_SYS_BIND_DATA d为#define)和L"File System Bind Data"对象的参数调用IFileSystemBindData
  8. 使用要创建的目录的路径名和SHCreateItemFromParsingName对象调用IBindCtx
  9. 有效。绑定上下文对象告诉SHCreateItemFromParsingName不要查询文件系统,只使用它给出的内容。我得到IFileOperation将文件复制到新的且名称巧妙的目录D:\Some\Path\That\Did\Not\Previously\Exist中,并且沿途创建了所有七个目录。据推测,可以使用相同的技术为任何不存在的文件系统对象创建IShellItem,具体取决于您在dwFileAttributes中放置的内容。

    但它很难看。我希望有更好的方法。我的编码实验是用C ++编写的;现在编写COM互操作的东西再用C#做。或者也许更容易抛出项目并重新开始用C ++。