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

sid*_*hes 6 c# com

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

\\FOO\dataC:\gather\Foo_data
\\BAR\manage\currentC:\gather\bar\manage

等等.问题在于FileOperation.CopyItem.它必须是因为目标目录还不存在 - IFileOperation将在复制期间创建它,对吗?我使用了另一个问题的技术并将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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

IFileOperation.CopyItem抛出一个ArgumentException,我无法弄清楚为什么.我没有IShellItem正确地做" 不存在的文件"吗?我怀疑我需要进入SFGAO_FOLDER那里,因为我正在尝试创建IShellItem一个不存在的目录,而不是文件,但是如何?

sid*_*hes 7

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

  1. 编写一个实现COM兼容的类IFileSystemBindData.
  2. 分配一个WIN32_FIND_DATA结构并设置它dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY.(其他成员在这里是无关紧要的,据我在一些测试后可以看出.)
  3. 创建一个IFileSystemBindData类的实例.
  4. 将您的WIN32_FIND_DATA对象传递给IFileSystemBindData::SetFindData.
  5. 创建一个实例IBindCtx.
  6. IBindCtx::RegisterObjectParamSTR_FILE_SYS_BIND_DATA(#defined as L"File System Bind Data")和你的IFileSystemBindData对象的参数调用它.
  7. 调用SHCreateItemFromParsingName与创建目录的路径名,和你的IBindCtx对象.

有用.绑定上下文对象告诉SHCreateItemFromParsingName不要查询文件系统,只使用它给出的内容.我必须IFileOperation将一个文件复制到一个新的和巧妙命名的目录中D:\Some\Path\That\Did\Not\Previously\Exist,并且它在此过程中创建了所有七个目录.据推测,可以使用相同的技术IShellItem为任何不存在的文件系统对象创建一个,具体取决于您放入的内容dwFileAttributes.

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