删除的zip文件会导致e.Data.GetData(“FileContents”)抛出exception

我正在尝试在我的WPF应用程序中为从zip存档拖动的文件实现一个处理程序。 处理程序应获取文件内容以供进一步处理。

我的环境:安装了Windows7,7-zip,Visual Studio 2012 Express,.Net 4.5

以下是一个简单的MainWindow应用程序的代码,用于演示此问题:

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); AllowDrop= true; Drop += onDrop; } private void onDrop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent("FileContents")) { var fileContents = e.Data.GetData("FileContents"); //get file contents... } } } 

当我将zip存档中包含的文件拖到我的Window时,对e.Data.GetData(“FileContents”)的调用将使用以下callstack抛出System.ArgumentException(“Argument out of Range”):

 System.Windows.DataObject.OleConverter.GetDataInner(formatetc, medium) System.Windows.DataObject.OleConverter.GetDataFromOleHGLOBAL(format, aspect, index) System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(format, aspect, index) System.Windows.DataObject.OleConverter.GetData(format, autoConvert, aspect, index) System.Windows.DataObject.OleConverter.GetData(format, autoConvert) System.Windows.DataObject.GetData(format, autoConvert) System.Windows.DataObject.GetData(format) TestZip.MainWindow.onDrop(sender, e) Zeile 34 C# 

我查了一下这个OleConverter的源代码( http://reflector.webtropy.com/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/发布/ Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / dataobject @cs / 1 / dataobject @cs )但GetDataInner()方法实现如下

 private void GetDataInner(ref FORMATETC formatetc, out STGMEDIUM medium) { new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); // BlessedAssert try { _innerData.GetData(ref formatetc, out medium); } finally { SecurityPermission.RevertAssert(); } } 

所以这也没有提供更多关于这里错误的信息。

我也试过卸载7-zip和不同的zip档案,但没有变化。

我的问题:有没有人知道这里出了什么问题? 为了将zip-archive中的文件内容放到我的窗口,我需要做什么?

老问题,但今天我需要这样做….

使用陈述:

 using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text; 

参考PresentationCore https://msdn.microsoft.com/en-us/library/system.windows.idataobject(v=vs.110).aspx

首先,您需要获取“FileDescriptor”内容,这是一个读取它们的类。

 ///  /// Specifies which fields are valid in a FileDescriptor Structure ///  [Flags] enum FileDescriptorFlags : uint { ClsId = 0x00000001, SizePoint = 0x00000002, Attributes = 0x00000004, CreateTime = 0x00000008, AccessTime = 0x00000010, WritesTime = 0x00000020, FileSize = 0x00000040, ProgressUI = 0x00004000, LinkUI = 0x00008000, Unicode = 0x80000000, } internal static class FileDescriptorReader { internal sealed class FileDescriptor { public FileDescriptorFlags Flags{get;set;} public Guid ClassId{get;set;} public Size Size{get;set;} public Point Point{get;set;} public FileAttributes FileAttributes{get;set;} public DateTime CreationTime{get;set;} public DateTime LastAccessTime{get;set;} public DateTime LastWriteTime{get;set;} public Int64 FileSize{get;set;} public string FileName{get;set;} public FileDescriptor(BinaryReader reader) { //Flags Flags = (FileDescriptorFlags)reader.ReadUInt32(); //ClassID ClassId = new Guid(reader.ReadBytes(16)); //Size Size = new Size(reader.ReadInt32(), reader.ReadInt32()); //Point Point = new Point(reader.ReadInt32(), reader.ReadInt32()); //FileAttributes FileAttributes = (FileAttributes)reader.ReadUInt32(); //CreationTime CreationTime = new DateTime(1601,1,1).AddTicks(reader.ReadInt64()); //LastAccessTime LastAccessTime = new DateTime(1601,1,1).AddTicks(reader.ReadInt64()); //LastWriteTime LastWriteTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); //FileSize FileSize = reader.ReadInt64(); //FileName byte[] nameBytes = reader.ReadBytes(520); int i = 0; while(i < nameBytes.Length) { if (nameBytes[i] == 0 && nameBytes[i + 1] == 0) break; i++; i++; } FileName = UnicodeEncoding.Unicode.GetString(nameBytes, 0, i); } } public static IEnumerable Read(Stream fileDescriptorStream) { BinaryReader reader = new BinaryReader(fileDescriptorStream); var count = reader.ReadUInt32(); while (count > 0) { FileDescriptor descriptor = new FileDescriptor(reader); yield return descriptor; count--; } } public static IEnumerable ReadFileNames(Stream fileDescriptorStream) { BinaryReader reader = new BinaryReader(fileDescriptorStream); var count = reader.ReadUInt32(); while(count > 0) { FileDescriptor descriptor = new FileDescriptor(reader); yield return descriptor.FileName; count--; } } } 

现在使用它可以获得每个文件的匹配文件内容:

 static class ClipboardHelper { internal static MemoryStream GetFileContents(System.Windows.IDataObject dataObject, int index) { //cast the default IDataObject to a com IDataObject IDataObject comDataObject; comDataObject = (IDataObject)dataObject; System.Windows.DataFormat Format = System.Windows.DataFormats.GetDataFormat("FileContents"); if (Format == null) return null; FORMATETC formatetc = new FORMATETC(); formatetc.cfFormat = (short)Format.Id; formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT; formatetc.lindex = index; formatetc.tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_HGLOBAL; //create STGMEDIUM to output request results into STGMEDIUM medium = new STGMEDIUM(); //using the com IDataObject interface get the data using the defined FORMATETC comDataObject.GetData(ref formatetc, out medium); switch (medium.tymed) { case TYMED.TYMED_ISTREAM: return GetIStream(medium); default: throw new NotSupportedException(); } } private static MemoryStream GetIStream(STGMEDIUM medium) { //marshal the returned pointer to a IStream object IStream iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember); Marshal.Release(medium.unionmember); //get the STATSTG of the IStream to determine how many bytes are in it var iStreamStat = new System.Runtime.InteropServices.ComTypes.STATSTG(); iStream.Stat(out iStreamStat, 0); int iStreamSize = (int)iStreamStat.cbSize; //read the data from the IStream into a managed byte array byte[] iStreamContent = new byte[iStreamSize]; iStream.Read(iStreamContent, iStreamContent.Length, IntPtr.Zero); //wrapped the managed byte array into a memory stream return new MemoryStream(iStreamContent); } } 

现在您可以枚举文件内容中的流:

  var fileDescriptor = (MemoryStream)Clipboard.GetDataObject().GetData("FileGroupDescriptorW"); var files = FileDescriptorReader.Read(fileDescriptor); var fileIndex = 0; foreach (var fileContentFile in files) { if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0) { //Do something with directories? //Note that directories do not have FileContents //And will throw if we try to read them } else { var fileData = ClipboardHelper.GetFileContents(Clipboard.GetDataObject(), FileIndex); fileData.Position = 0; //Do something with the fileContent Stream } fileIndex++; }