private void CreateLocalCopyFromHttpSource( NativeInterfaces.IShellItem item, IFileTransferProgressEvents progressEvents, out string pathNameResult) { string url = null; item.GetDisplayName(NativeConstants.SIGDN.SIGDN_URL, out url); Uri uri = new Uri(url); string pathName = FileSystem.GetTempPathName(url); WebRequest webRequest = WebRequest.Create(uri); webRequest.Timeout = 5000; using (WebResponse webResponse = webRequest.GetResponse()) { VerifyNotCanceled(); using (Stream uriStream = webResponse.GetResponseStream()) { VerifyNotCanceled(); using (FileStream outStream = new FileStream(pathName, FileMode.Create, FileAccess.Write, FileShare.Read)) { VerifyNotCanceled(); const int bufSize = 512; long length = webResponse.ContentLength; long bytesLeft = length; byte[] buffer = new byte[bufSize]; progressEvents.SetItemWorkTotal(length); while (bytesLeft > 0) { int amtRead = uriStream.Read(buffer, 0, buffer.Length); VerifyNotCanceled(); outStream.Write(buffer, 0, amtRead); VerifyNotCanceled(); bytesLeft -= amtRead; progressEvents.SetItemWorkProgress(length - bytesLeft); VerifyNotCanceled(); } } } } pathNameResult = pathName; }
private unsafe void CreateLocalCopyFromIStreamSource( NativeInterfaces.IShellItem item, IFileTransferProgressEvents progressEvents, out string pathNameResult) { string fileName = null; item.GetDisplayName(NativeConstants.SIGDN.SIGDN_NORMALDISPLAY, out fileName); string pathName = FileSystem.GetTempPathName(fileName); Guid bhidStream = NativeConstants.BHID_Stream; Guid iid_IStream = new Guid(NativeConstants.IID_IStream); NativeInterfaces.IStream iStream = null; item.BindToHandler(IntPtr.Zero, ref bhidStream, ref iid_IStream, out iStream); try { VerifyNotCanceled(); NativeStructs.STATSTG statstg = new NativeStructs.STATSTG(); iStream.Stat(out statstg, NativeConstants.STATFLAG.STATFLAG_NONAME); progressEvents.SetItemWorkTotal((long)statstg.cbSize); const int bufSize = 4096; byte[] buffer = new byte[bufSize]; fixed(void *pbBuffer = buffer) { IntPtr pbBuffer2 = new IntPtr(pbBuffer); ulong qwBytesLeft = statstg.cbSize; using (FileStream localFile = new FileStream(pathName, FileMode.Create, FileAccess.Write, FileShare.Read)) { VerifyNotCanceled(); // NOTE: We do not call VerifyNotCanceled() during any individual item. This is because, while testing // this, it was determined that oftentimes the transfer gets very confused if we just stop // calling Read() and jump straight to Marshal.ReleaseComObject(). By "confused" I mean that // the "Canceling..." text would remain on the progress dialog for up to a minute, and then // the blinking light on the camera would continue indefinitely and you wouldn't be able to // use the camera again until you unplugged it and plugged it back in. while (qwBytesLeft > 0) { uint wantToRead = (uint)Math.Min(qwBytesLeft, bufSize); uint amtRead = 0; iStream.Read(pbBuffer2, wantToRead, out amtRead); if (amtRead > qwBytesLeft) { throw new InvalidOperationException("IStream::Read() reported that more bytes were read than were in the file"); } qwBytesLeft -= amtRead; localFile.Write(buffer, 0, (int)amtRead); progressEvents.SetItemWorkProgress((long)(statstg.cbSize - qwBytesLeft)); } } VerifyNotCanceled(); } } finally { if (iStream != null) { try { Marshal.ReleaseComObject(iStream); } catch (Exception) { } iStream = null; } } pathNameResult = pathName; }
private unsafe void CreateLocalCopyFromIStreamSource( NativeInterfaces.IShellItem item, IFileTransferProgressEvents progressEvents, out string pathNameResult) { string fileName = null; item.GetDisplayName(NativeConstants.SIGDN.SIGDN_NORMALDISPLAY, out fileName); string pathName = FileSystem.GetTempPathName(fileName); Guid bhidStream = NativeConstants.BHID_Stream; Guid iid_IStream = new Guid(NativeConstants.IID_IStream); NativeInterfaces.IStream iStream = null; item.BindToHandler(IntPtr.Zero, ref bhidStream, ref iid_IStream, out iStream); try { VerifyNotCanceled(); NativeStructs.STATSTG statstg = new NativeStructs.STATSTG(); iStream.Stat(out statstg, NativeConstants.STATFLAG.STATFLAG_NONAME); progressEvents.SetItemWorkTotal((long)statstg.cbSize); const int bufSize = 4096; byte[] buffer = new byte[bufSize]; fixed (void* pbBuffer = buffer) { IntPtr pbBuffer2 = new IntPtr(pbBuffer); ulong qwBytesLeft = statstg.cbSize; using (FileStream localFile = new FileStream(pathName, FileMode.Create, FileAccess.Write, FileShare.Read)) { VerifyNotCanceled(); // NOTE: We do not call VerifyNotCanceled() during any individual item. This is because, while testing // this, it was determined that oftentimes the transfer gets very confused if we just stop // calling Read() and jump straight to Marshal.ReleaseComObject(). By "confused" I mean that // the "Canceling..." text would remain on the progress dialog for up to a minute, and then // the blinking light on the camera would continue indefinitely and you wouldn't be able to // use the camera again until you unplugged it and plugged it back in. while (qwBytesLeft > 0) { uint wantToRead = (uint)Math.Min(qwBytesLeft, bufSize); uint amtRead = 0; iStream.Read(pbBuffer2, wantToRead, out amtRead); if (amtRead > qwBytesLeft) { throw new InvalidOperationException("IStream::Read() reported that more bytes were read than were in the file"); } qwBytesLeft -= amtRead; localFile.Write(buffer, 0, (int)amtRead); progressEvents.SetItemWorkProgress((long)(statstg.cbSize - qwBytesLeft)); } } VerifyNotCanceled(); } } finally { if (iStream != null) { try { Marshal.ReleaseComObject(iStream); } catch (Exception) { } iStream = null; } } pathNameResult = pathName; }