删除的zip文件导致e.Data.GetData(“FileContents”)抛出异常 [英] Dropped zip file causes e.Data.GetData("FileContents") to throw an exception

查看:305
本文介绍了删除的zip文件导致e.Data.GetData(“FileContents”)抛出异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在WPF应用程序中实现一个处理程序,用于从压缩文件夹拖动的文件。处理程序应该获取文件内容进行进一步处理。

I'm trying to implement a handler in my WPF application for files dragged from a zip archive. The handler should get the file content for further processing.

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

My environment: Windows7, 7-zip installed, Visual Studio 2012 Express, .Net 4.5

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

Here is the code of a simple MainWindow app to demonstrate the problem:

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存档中的文件拖动到我的窗口时,对e.Data.GetData(FileContents)的调用会使用以下callstack引发一个System.ArgumentException(Argument out of Range):

When I drag a file contained in a zip archive to my Window the call to e.Data.GetData("FileContents") throws a System.ArgumentException ("Argument out of Range") with the following callstack:

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的源代码(<啊REF =http://reflector.webtropy.com/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src / Core / CSharp / System / Windows / dataobject @ cs / 1 / dataobject @ csrel =nofollow> http://reflector.webtropy.com/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1 / 3 @ 5 @ 1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / dataobject @ cs / 1 / dataobject @ cs ),但GetDataInner方法实现像

I've looked up the source code of this OleConverter (http://reflector.webtropy.com/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Core/CSharp/System/Windows/dataobject@cs/1/dataobject@cs) but the GetDataInner() method is implemented like

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();
     } 
 }

所以这还没有提供进一步的错误信息

So this does also not provide further info of what's wrong here.

我还尝试使用卸载的7-zip和不同的zip存档,但没有变化。

I also tried with uninstalled 7-zip and with different zip archives, but no change.

我的问题:有没有人知道这里有什么问题?我需要做什么才能将压缩文件中的文件的内容放到我的窗口上?

My question: Does any one have a clue what's going wrong here? What do I need to do in order to get the content of a file from a zip-archive dropped onto my window?

推荐答案

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

Old question but I needed to do this today so....

首先你需要得到FileDescriptor的内容,这里是一个读它们的类。

First you need to get the "FileDescriptor" contents, here's a class which reads them.

/// <summary>
/// Specifies which fields are valid in a FileDescriptor Structure
/// </summary>    
[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<FileDescriptor> 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<string> 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--;
        }
    }
}

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

Now using that you can get the matching file content for each file:

static class ClipboardHelper
{
    internal static MemoryStream GetFileContents(Windows.IDataObject dataObject, int index)
    {
        //cast the default IDataObject to a com IDataObject
        IDataObject comDataObject;
        comDataObject = (IDataObject)dataObject;

        Windows.DataFormat Format = 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);
    }
}

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

Now you can enumerate the streams in the file contents:

                var fileDescriptor = (MemoryStream)Clipboard.GetDataObject().GetData("FileGroupDescriptorW");
                var files = FileDescriptorReader.Read(fileDescriptor)
                    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(), i);
                            fileData.Position = 0;
                            //Do something with the fileContent Stream
                        }
                        i++;                            
                    }

这篇关于删除的zip文件导致e.Data.GetData(“FileContents”)抛出异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆