2012-08-10 102 views
5

使用Stephen Toub的C#的IFileOperation包裝器(link),直到現在一直運行良好。現在我試圖做一個副本從網絡位置收集文件,每個網絡位置都放到它自己的子目錄中。使用IFileOperation在副本中創建目錄

\\FOO\dataC:\gather\Foo_data
\\BAR\manage\currentC:\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爲一個不存在的目錄,而不是文件,但如何?

回答

6

在本週末進行了大量的谷歌搜索和編碼實驗之後,我發現了一個解決方案。

  1. 寫一個COM兼容的類,實現IFileSystemBindData
  2. 分配一個WIN32_FIND_DATA結構並設置它的dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY。 (其他成員在這裏是無關緊要的,就我所知,經過一些測試後)。
  3. 創建IFileSystemBindData類的實例。
  4. 將您的WIN32_FIND_DATA對象傳遞給IFileSystemBindData::SetFindData
  5. 創建一個IBindCtx的實例。
  6. 將其參數IBindCtx::RegisterObjectParam的參數設爲STR_FILE_SYS_BIND_DATA#define d作爲L"File System Bind Data")和IFileSystemBindData對象。
  7. 請致電SHCreateItemFromParsingName與要創建的目錄的路徑名,以及您的IBindCtx對象。

它的工作原理。綁定上下文對象告訴SHCreateItemFromParsingName不要查詢文件系統,只使用它給出的內容。我得到了IFileOperation將一個文件複製到新的巧妙命名的目錄D:\Some\Path\That\Did\Not\Previously\Exist,並沿途創建了所有七個目錄。據推測,這種技術可用於爲任何不存在的文件系統對象創建IShellItem,具體取決於您在dwFileAttributes中放置的內容。

但它很醜。我希望有更好的方法。我的編碼實驗是用C++編寫的;現在編寫COM interop的東西,再次在C#中完成。或者,也許會更容易扔掉項目並從C++開始。