删除的 zip 文件会导致 e.Data.GetData("FileContents") 引发异常

2024-03-03

我正在尝试在 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 存档中包含的文件拖到窗口中时,对 e.Data.GetData("FileContents") 的调用会抛出 System.ArgumentException(“参数超出范围”),调用堆栈如下:

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/releases/Orcas/NetFXw7/wpf/src/Core/ CSharp/系统/Windows/dataobject@cs/1/dataobject@cs 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() 方法的实现如下

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 存档中获取文件的内容?


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

使用语句:

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

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

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

/// <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--;
        }
    }
}

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

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++;                            
                    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

删除的 zip 文件会导致 e.Data.GetData("FileContents") 引发异常 的相关文章

  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • .Net应用程序设置路径

    默认情况下 Windows 应用程序设置保存在该目录中 USERPROFILE Local Settings Application Data
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • 在.rdlc报告的底部设置一个文本框

    我在 rdlc 报告中使用 tablix 有一个文本框 其中包含文本 签名 我想将此文本框放置在报告最后一页的底部 就在页脚之前 我已经用谷歌搜索了这个解决方案 但没有找到满意的结果 我的环境是VS2010 framework 4 0 有什
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐