// Returns true if the item copied successfully, false if it didn't (error or skipped) private CopyResult CreateLocalCopy( NativeInterfaces.IShellItem item, IFileTransferProgressEvents progressEvents, out string pathNameResult) { CopyResult returnResult; WorkItemResult itemResult; string displayName = null; item.GetDisplayName(NativeConstants.SIGDN.SIGDN_NORMALDISPLAY, out displayName); progressEvents.SetItemInfo(displayName); progressEvents.BeginItem(); while (true) { // Determine whether to copy from HTTP or from IStream. The heuristic we use here is simple: // if the attributes has SFGAO_CANCOPY, we IStream it. Else, we HTTP it. NativeConstants.SFGAO attribs; item.GetAttributes((NativeConstants.SFGAO) 0xfffffff, out attribs); try { if ((attribs & NativeConstants.SFGAO.SFGAO_CANCOPY) == NativeConstants.SFGAO.SFGAO_CANCOPY) { CreateLocalCopyFromIStreamSource(item, progressEvents, out pathNameResult); } else { CreateLocalCopyFromHttpSource(item, progressEvents, out pathNameResult); } returnResult = CopyResult.Success; itemResult = WorkItemResult.Finished; break; } catch (OperationCanceledException) { returnResult = CopyResult.CancelOperation; itemResult = WorkItemResult.Skipped; pathNameResult = null; break; } catch (Exception ex) { WorkItemFailureAction choice = progressEvents.ReportItemFailure(ex); if (choice == WorkItemFailureAction.SkipItem) { pathNameResult = null; returnResult = CopyResult.Skipped; itemResult = WorkItemResult.Skipped; break; } else if (choice == WorkItemFailureAction.RetryItem) { continue; } else if (choice == WorkItemFailureAction.CancelOperation) { pathNameResult = null; returnResult = CopyResult.CancelOperation; itemResult = WorkItemResult.Skipped; break; } } } progressEvents.EndItem(itemResult); return(returnResult); }
int NativeInterfaces.IFileDialogEvents.OnFileOk(NativeInterfaces.IFileDialog pfd) { int hr = NativeConstants.S_OK; NativeInterfaces.IShellItemArray results = null; FileOpenDialog.GetResults(out results); uint count = 0; results.GetCount(out count); List <NativeInterfaces.IShellItem> items = new List <NativeInterfaces.IShellItem>(); List <NativeInterfaces.IShellItem> needLocalCopy = new List <NativeInterfaces.IShellItem>(); List <NativeInterfaces.IShellItem> cannotCopy = new List <NativeInterfaces.IShellItem>(); List <string> localPathNames = new List <string>(); for (uint i = 0; i < count; ++i) { NativeInterfaces.IShellItem item = null; results.GetItemAt(i, out item); items.Add(item); } foreach (NativeInterfaces.IShellItem item in items) { // If it's a file system object, nothing special needs to be done. NativeConstants.SFGAO sfgaoAttribs; item.GetAttributes((NativeConstants.SFGAO) 0xffffffff, out sfgaoAttribs); if ((sfgaoAttribs & NativeConstants.SFGAO.SFGAO_FILESYSTEM) == NativeConstants.SFGAO.SFGAO_FILESYSTEM) { string pathName = null; item.GetDisplayName(NativeConstants.SIGDN.SIGDN_FILESYSPATH, out pathName); localPathNames.Add(pathName); } else if ((sfgaoAttribs & NativeConstants.SFGAO.SFGAO_STREAM) == NativeConstants.SFGAO.SFGAO_STREAM) { needLocalCopy.Add(item); } else { cannotCopy.Add(item); } } Marshal.ReleaseComObject(results); results = null; if (needLocalCopy.Count > 0) { IntPtr hwnd = IntPtr.Zero; NativeInterfaces.IOleWindow oleWindow = (NativeInterfaces.IOleWindow)pfd; oleWindow.GetWindow(out hwnd); Win32Window win32Window = new Win32Window(hwnd, oleWindow); IFileTransferProgressEvents progressEvents = this.FileDialogUICallbacks.CreateFileTransferProgressEvents(); ThreadStart copyThreadProc = delegate() { try { progressEvents.SetItemCount(needLocalCopy.Count); for (int i = 0; i < needLocalCopy.Count; ++i) { NativeInterfaces.IShellItem item = needLocalCopy[i]; string pathName = null; progressEvents.SetItemOrdinal(i); CopyResult result = CreateLocalCopy(item, progressEvents, out pathName); if (result == CopyResult.Success) { localPathNames.Add(pathName); } else if (result == CopyResult.Skipped) { // do nothing } else if (result == CopyResult.CancelOperation) { hr = NativeConstants.S_FALSE; break; } else { throw new InvalidEnumArgumentException(); } } } finally { OperationResult result; if (hr == NativeConstants.S_OK) { result = OperationResult.Finished; } else { result = OperationResult.Canceled; } progressEvents.EndOperation(result); } }; Thread copyThread = new Thread(copyThreadProc); copyThread.SetApartmentState(ApartmentState.STA); EventHandler onUIShown = delegate(object sender, EventArgs e) { copyThread.Start(); }; this.cancelSink = new CancelableTearOff(); progressEvents.BeginOperation(win32Window, onUIShown, cancelSink); this.cancelSink = null; copyThread.Join(); Marshal.ReleaseComObject(oleWindow); oleWindow = null; } this.FileNames = localPathNames.ToArray(); // If they selected a bunch of files, and then they all errored or something, then don't proceed. if (this.FileNames.Length == 0) { hr = NativeConstants.S_FALSE; } foreach (NativeInterfaces.IShellItem item in items) { Marshal.ReleaseComObject(item); } items.Clear(); items = null; GC.KeepAlive(pfd); return(hr); }