2014-11-27 1 views
3

У меня проблема, с которой я столкнулся, и надеюсь, что кто-то здесь может помочь.AccessViolationException после копирования файла из ZIP-архива в буфер обмена и обработки его данных

Мы используем несколько модифицированный код из этого проекта OutlookDataObject для обработки файлов, удаленных из разных почтовых клиентов, таких как Outlook, а также общее копирование файлов в буфер обмена для их обработки и сохранения их в файловой системе.

Он работает нормально в большинстве случаев, однако, если пользователь открывает файл ZIP с помощью проводника Windows, копирует файл и пытается добавить его, мы получаем исключение AccessViolationException в следующей части метода GetData файла FileContentDataObject:

//marshal the unmanaged memory to to FILEGROUPDESCRIPTORW struct 
object fileGroupDescriptorObject = Marshal.PtrToStructure(fileGroupDescriptorWPointer, typeof(NativeMethods.FILEGROUPDESCRIPTORW)); 

Вот сокращенный вариант всего кода в вопросе, с которым вы должны быть в состоянии воспроизвести этот вопрос:

// Starting Method 
public void InsertFromClipboard() 
{ 
    FileContentDataObjectBase dataObject = GetDataObject(); 
    if(dataObject!= null) 
    { 
     dataObject.SaveToFileSystem("C:/temp"); 
    } 
} 

private FileContentDataObjectBase GetDataObject() 
{ 
    var dataObject = System.Windows.Forms.Clipboard.GetDataObject(); 

    return new FileContentDataObject(System.Windows.Forms.Clipboard.GetDataObject()); 
} 

public class FileContentDataObject : FileContentDataObjectBase 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="OutlookDataObject"/> class. 
    /// </summary> 
    /// <param name="underlyingDataObject">The underlying data object to wrap.</param> 
    public FileContentDataObject(System.Windows.Forms.IDataObject underlyingDataObject) 
     : base(underlyingDataObject) { } 

    public override void SaveToFileSystem(string path) 
    { 
     string[] filenames; 

     //get the names and data streams of the files dropped 
     if (this.GetFormats().Contains("FileGroupDescriptor")) 
      filenames = (string[])this.GetData("FileGroupDescriptor", true); 
     else if (this.GetFormats().Contains("FileGroupDescriptorW")) 
      filenames = (string[])this.GetData("FileGroupDescriptorW", true); 
     else 
      return; 

     MemoryStream[] filestreams = (MemoryStream[])this.GetData("FileContents"); 

     SaveToFileSystem(filenames, filestreams, path); 
    } 

    public new object GetData(string format, bool autoConvert) 
    { 
     switch (format) 
     { 
      case "FileGroupDescriptorW": 
       //override the default handling of FileGroupDescriptorW which returns a 
       //MemoryStream and instead return a string array of file names 
       IntPtr fileGroupDescriptorWPointer = IntPtr.Zero; 
       try 
       { 
        //use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream 
        MemoryStream fileGroupDescriptorStream = (MemoryStream)this.underlyingDataObject.GetData("FileGroupDescriptorW"); 
        byte[] fileGroupDescriptorBytes = new byte[fileGroupDescriptorStream.Length]; 
        fileGroupDescriptorStream.Read(fileGroupDescriptorBytes, 0, fileGroupDescriptorBytes.Length); 
        fileGroupDescriptorStream.Close(); 

        //copy the file group descriptor into unmanaged memory 
        fileGroupDescriptorWPointer = Marshal.AllocHGlobal(fileGroupDescriptorBytes.Length); 
        Marshal.Copy(fileGroupDescriptorBytes, 0, fileGroupDescriptorWPointer, fileGroupDescriptorBytes.Length); 

        //marshal the unmanaged memory to to FILEGROUPDESCRIPTORW struct 
        object fileGroupDescriptorObject = Marshal.PtrToStructure(fileGroupDescriptorWPointer, typeof(NativeMethods.FILEGROUPDESCRIPTORW)); 
        NativeMethods.FILEGROUPDESCRIPTORW fileGroupDescriptor = (NativeMethods.FILEGROUPDESCRIPTORW)fileGroupDescriptorObject; 

        //create a new array to store file names in of the number of items in the file group descriptor 
        string[] fileNames = new string[fileGroupDescriptor.cItems]; 

        //get the pointer to the first file descriptor 
        IntPtr fileDescriptorPointer = (IntPtr)((int)fileGroupDescriptorWPointer + Marshal.SizeOf(fileGroupDescriptor.cItems)); 

        //loop for the number of files acording to the file group descriptor 
        for (int fileDescriptorIndex = 0; fileDescriptorIndex < fileGroupDescriptor.cItems; fileDescriptorIndex++) 
        { 
         //marshal the pointer top the file descriptor as a FILEDESCRIPTORW struct and get the file name 
         NativeMethods.FILEDESCRIPTORW fileDescriptor = (NativeMethods.FILEDESCRIPTORW)Marshal.PtrToStructure(fileDescriptorPointer, typeof(NativeMethods.FILEDESCRIPTORW)); 
         fileNames[fileDescriptorIndex] = fileDescriptor.cFileName; 

         //move the file descriptor pointer to the next file descriptor 
         fileDescriptorPointer = (IntPtr)((int)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor)); 
        } 

        //return the array of filenames 
        return fileNames; 
       } 
       finally 
       { 
        //free unmanaged memory pointer 
        Marshal.FreeHGlobal(fileGroupDescriptorWPointer); 
       } 
     } 

      //use underlying IDataObject to handle getting of data 
      return this.underlyingDataObject.GetData(format, autoConvert); 
     } 
    } 

    public abstract class FileContentDataObjectBase : System.Windows.Forms.IDataObject 
    { 
     #region NativeMethods 

     protected class NativeMethods 
     { 
      [DllImport("kernel32.dll")] 
      static extern IntPtr GlobalLock(IntPtr hMem); 

      [DllImport("ole32.dll", PreserveSig = false)] 
      internal static extern ILockBytes CreateILockBytesOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease); 

      [DllImport("OLE32.DLL", CharSet = CharSet.Auto, PreserveSig = false)] 
      internal static extern IntPtr GetHGlobalFromILockBytes(ILockBytes pLockBytes); 

      [DllImport("OLE32.DLL", CharSet = CharSet.Unicode, PreserveSig = false)] 
      internal static extern IStorage StgCreateDocfileOnILockBytes(ILockBytes plkbyt, uint grfMode, uint reserved); 

      [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000B-0000-0000-C000-000000000046")] 
      internal interface IStorage 
      { 
       [return: MarshalAs(UnmanagedType.Interface)] 
       IStream CreateStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2); 
       [return: MarshalAs(UnmanagedType.Interface)] 
       IStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2); 
       [return: MarshalAs(UnmanagedType.Interface)] 
       IStorage CreateStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2); 
       [return: MarshalAs(UnmanagedType.Interface)] 
       IStorage OpenStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr pstgPriority, [In, MarshalAs(UnmanagedType.U4)] int grfMode, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.U4)] int reserved); 
       void CopyTo(int ciidExclude, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] pIIDExclude, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest); 
       void MoveElementTo([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName, [In, MarshalAs(UnmanagedType.U4)] int grfFlags); 
       void Commit(int grfCommitFlags); 
       void Revert(); 
       void EnumElements([In, MarshalAs(UnmanagedType.U4)] int reserved1, IntPtr reserved2, [In, MarshalAs(UnmanagedType.U4)] int reserved3, [MarshalAs(UnmanagedType.Interface)] out object ppVal); 
       void DestroyElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsName); 
       void RenameElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsOldName, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName); 
       void SetElementTimes([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In] System.Runtime.InteropServices.ComTypes.FILETIME pctime, [In] System.Runtime.InteropServices.ComTypes.FILETIME patime, [In] System.Runtime.InteropServices.ComTypes.FILETIME pmtime); 
       void SetClass([In] ref Guid clsid); 
       void SetStateBits(int grfStateBits, int grfMask); 
       void Stat([Out]out System.Runtime.InteropServices.ComTypes.STATSTG pStatStg, int grfStatFlag); 
      } 

      [ComImport, Guid("0000000A-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
      internal interface ILockBytes 
      { 
       void ReadAt([In, MarshalAs(UnmanagedType.U8)] long ulOffset, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, [In, MarshalAs(UnmanagedType.U4)] int cb, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pcbRead); 
       void WriteAt([In, MarshalAs(UnmanagedType.U8)] long ulOffset, IntPtr pv, [In, MarshalAs(UnmanagedType.U4)] int cb, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pcbWritten); 
       void Flush(); 
       void SetSize([In, MarshalAs(UnmanagedType.U8)] long cb); 
       void LockRegion([In, MarshalAs(UnmanagedType.U8)] long libOffset, [In, MarshalAs(UnmanagedType.U8)] long cb, [In, MarshalAs(UnmanagedType.U4)] int dwLockType); 
       void UnlockRegion([In, MarshalAs(UnmanagedType.U8)] long libOffset, [In, MarshalAs(UnmanagedType.U8)] long cb, [In, MarshalAs(UnmanagedType.U4)] int dwLockType); 
       void Stat([Out]out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, [In, MarshalAs(UnmanagedType.U4)] int grfStatFlag); 
      } 

      [StructLayout(LayoutKind.Sequential)] 
      internal sealed class POINTL 
      { 
       public int x; 
       public int y; 
      } 

      [StructLayout(LayoutKind.Sequential)] 
      internal sealed class SIZEL 
      { 
       public int cx; 
       public int cy; 
      } 

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
      internal sealed class FILEGROUPDESCRIPTORA 
      { 
       public uint cItems; 
       public FILEDESCRIPTORA[] fgd; 
      } 

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
      internal sealed class FILEDESCRIPTORA 
      { 
       public uint dwFlags; 
       public Guid clsid; 
       public SIZEL sizel; 
       public POINTL pointl; 
       public uint dwFileAttributes; 
       public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; 
       public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; 
       public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; 
       public uint nFileSizeHigh; 
       public uint nFileSizeLow; 
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
       public string cFileName; 
      } 

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
      internal sealed class FILEGROUPDESCRIPTORW 
      { 
       public uint cItems; 
       public FILEDESCRIPTORW[] fgd; 
      } 

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
      internal sealed class FILEDESCRIPTORW 
      { 
       public uint dwFlags; 
       public Guid clsid; 
       public SIZEL sizel; 
       public POINTL pointl; 
       public uint dwFileAttributes; 
       public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; 
       public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; 
       public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; 
       public uint nFileSizeHigh; 
       public uint nFileSizeLow; 
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
       public string cFileName; 
      } 
     } 

     #endregion 

     #region Property(s) 

     /// <summary> 
     /// Holds the <see cref="System.Windows.Forms.IDataObject"/> that this class is wrapping 
     /// </summary> 
     protected System.Windows.Forms.IDataObject underlyingDataObject; 

     /// <summary> 
     /// Holds the <see cref="System.Runtime.InteropServices.ComTypes.IDataObject"/> interface to the <see cref="System.Windows.Forms.IDataObject"/> that this class is wrapping. 
     /// </summary> 
     protected System.Runtime.InteropServices.ComTypes.IDataObject comUnderlyingDataObject; 

     /// <summary> 
     /// Holds the internal ole <see cref="System.Windows.Forms.IDataObject"/> to the <see cref="System.Windows.Forms.IDataObject"/> that this class is wrapping. 
     /// </summary> 
     protected System.Windows.Forms.IDataObject oleUnderlyingDataObject; 

     /// <summary> 
     /// Holds the <see cref="MethodInfo"/> of the "GetDataFromHGLOBLAL" method of the internal ole <see cref="System.Windows.Forms.IDataObject"/>. 
     /// </summary> 
     protected MethodInfo getDataFromHGLOBLALMethod; 

     #endregion 

     #region Constructor(s) 

     /// <summary> 
     /// Initializes a new instance of the <see cref="OutlookDataObject"/> class. 
     /// </summary> 
     /// <param name="underlyingDataObject">The underlying data object to wrap.</param> 
     public FileContentDataObjectBase(System.Windows.Forms.IDataObject underlyingDataObject) 
     { 
      //get the underlying dataobject and its ComType IDataObject interface to it 
      this.underlyingDataObject = underlyingDataObject; 
      this.comUnderlyingDataObject = (System.Runtime.InteropServices.ComTypes.IDataObject)this.underlyingDataObject; 

      //get the internal ole dataobject and its GetDataFromHGLOBLAL so it can be called later 
      FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance); 
      this.oleUnderlyingDataObject = (System.Windows.Forms.IDataObject)innerDataField.GetValue(this.underlyingDataObject); 
      this.getDataFromHGLOBLALMethod = this.oleUnderlyingDataObject.GetType().GetMethod("GetDataFromHGLOBLAL", BindingFlags.NonPublic | BindingFlags.Instance); 
     } 

     #endregion 

     #region IDataObject Members 

     /// <summary> 
     /// Retrieves the data associated with the specified class type format. 
     /// </summary> 
     /// <param name="format">A <see cref="T:System.Type"></see> representing the format of the data to retrieve. See <see cref="T:System.Windows.Forms.DataFormats"></see> for predefined formats.</param> 
     /// <returns> 
     /// The data associated with the specified format, or null. 
     /// </returns> 
     public object GetData(Type format) 
     { 
      return this.GetData(format.FullName); 
     } 

     /// <summary> 
     /// Retrieves the data associated with the specified data format. 
     /// </summary> 
     /// <param name="format">The format of the data to retrieve. See <see cref="T:System.Windows.Forms.DataFormats"></see> for predefined formats.</param> 
     /// <returns> 
     /// The data associated with the specified format, or null. 
     /// </returns> 
     public object GetData(string format) 
     { 
      return this.GetData(format, true); 
     } 

     /// <summary> 
     /// Retrieves the data associated with the specified data format, using a Boolean to determine whether to convert the data to the format. 
     /// </summary> 
     /// <param name="format">The format of the data to retrieve. See <see cref="T:System.Windows.Forms.DataFormats"></see> for predefined formats.</param> 
     /// <param name="autoConvert">true to convert the data to the specified format; otherwise, false.</param> 
     /// <returns> 
     /// The data associated with the specified format, or null. 
     /// </returns> 
     public object GetData(string format, bool autoConvert) 
     { 
      return this.underlyingDataObject.GetData(format, autoConvert); 
     } 

     /// <summary> 
     /// Retrieves the data associated with the specified data format at the specified index. 
     /// </summary> 
     /// <param name="format">The format of the data to retrieve. See <see cref="T:System.Windows.Forms.DataFormats"></see> for predefined formats.</param> 
     /// <param name="index">The index of the data to retrieve.</param> 
     /// <returns> 
     /// A <see cref="MemoryStream"/> containing the raw data for the specified data format at the specified index. 
     /// </returns> 
     public MemoryStream GetData(string format, int index) 
     { 
      //create a FORMATETC struct to request the data with 
      FORMATETC formatetc = new FORMATETC(); 
      formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id; 
      formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT; 
      formatetc.lindex = index; 
      formatetc.ptd = new IntPtr(0); 
      formatetc.tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_ISTORAGE | 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 
      this.comUnderlyingDataObject.GetData(ref formatetc, out medium); 

      //retrieve the data depending on the returned store type 
      switch (medium.tymed) 
      { 
       case TYMED.TYMED_ISTORAGE: 
        //to handle a IStorage it needs to be written into a second unmanaged 
        //memory mapped storage and then the data can be read from memory into 
        //a managed byte and returned as a MemoryStream 

        NativeMethods.IStorage iStorage = null; 
        NativeMethods.IStorage iStorage2 = null; 
        NativeMethods.ILockBytes iLockBytes = null; 
        System.Runtime.InteropServices.ComTypes.STATSTG iLockBytesStat; 
        try 
        { 
         //marshal the returned pointer to a IStorage object 
         iStorage = (NativeMethods.IStorage)Marshal.GetObjectForIUnknown(medium.unionmember); 
         Marshal.Release(medium.unionmember); 

         //create a ILockBytes (unmanaged byte array) and then create a IStorage using the byte array as a backing store 
         iLockBytes = NativeMethods.CreateILockBytesOnHGlobal(IntPtr.Zero, true); 
         iStorage2 = NativeMethods.StgCreateDocfileOnILockBytes(iLockBytes, 0x00001012, 0); 

         //copy the returned IStorage into the new IStorage 
         iStorage.CopyTo(0, null, IntPtr.Zero, iStorage2); 
         iLockBytes.Flush(); 
         iStorage2.Commit(0); 

         //get the STATSTG of the ILockBytes to determine how many bytes were written to it 
         iLockBytesStat = new System.Runtime.InteropServices.ComTypes.STATSTG(); 
         iLockBytes.Stat(out iLockBytesStat, 1); 
         int iLockBytesSize = (int)iLockBytesStat.cbSize; 

         //read the data from the ILockBytes (unmanaged byte array) into a managed byte array 
         byte[] iLockBytesContent = new byte[iLockBytesSize]; 
         iLockBytes.ReadAt(0, iLockBytesContent, iLockBytesContent.Length, null); 

         //wrapped the managed byte array into a memory stream and return it 
         return new MemoryStream(iLockBytesContent); 
        } 
        finally 
        { 
         //release all unmanaged objects 
         Marshal.ReleaseComObject(iStorage2); 
         Marshal.ReleaseComObject(iLockBytes); 
         Marshal.ReleaseComObject(iStorage); 
        } 

       case TYMED.TYMED_ISTREAM: 
        //to handle a IStream it needs to be read into a managed byte and 
        //returned as a MemoryStream 

        IStream iStream = null; 
        System.Runtime.InteropServices.ComTypes.STATSTG iStreamStat; 
        try 
        { 
         //marshal the returned pointer to a IStream object 
         iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember); 
         Marshal.Release(medium.unionmember); 

         //get the STATSTG of the IStream to determine how many bytes are in it 
         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 and return it 
         return new MemoryStream(iStreamContent); 
        } 
        finally 
        { 
         //release all unmanaged objects 
         Marshal.ReleaseComObject(iStream); 
        } 

       case TYMED.TYMED_HGLOBAL: 
        //to handle a HGlobal the exisitng "GetDataFromHGLOBLAL" method is invoked via 
        //reflection 

        return (MemoryStream)this.getDataFromHGLOBLALMethod.Invoke(this.oleUnderlyingDataObject, new object[] { DataFormats.GetFormat((short)formatetc.cfFormat).Name, medium.unionmember }); 
      } 

      return null; 
     } 

     /// <summary> 
     /// Returns a list of all formats that data stored in this instance is associated with or can be converted to. 
     /// </summary> 
     /// <returns> 
     /// An array of the names that represents a list of all formats that are supported by the data stored in this object. 
     /// </returns> 
     public string[] GetFormats() 
     { 
      return this.underlyingDataObject.GetFormats(); 
     } 

     /// <summary> 
     /// Gets a list of all formats that data stored in this instance is associated with or can be converted to, using a Boolean value to determine whether to retrieve all formats that the data can be converted to or only native data formats. 
     /// </summary> 
     /// <param name="autoConvert">true to retrieve all formats that data stored in this instance is associated with or can be converted to; false to retrieve only native data formats.</param> 
     /// <returns> 
     /// An array of the names that represents a list of all formats that are supported by the data stored in this object. 
     /// </returns> 
     public string[] GetFormats(bool autoConvert) 
     { 
      return this.underlyingDataObject.GetFormats(autoConvert); 
     } 

     #endregion 

     #region methods 

     public static void SaveToFileSystem(string[] filenames, MemoryStream[] filestreams, string path) 
     { 

      for (int fileIndex = 0; fileIndex < filenames.Length; fileIndex++) 
      { 
       try 
       { 
        //use the fileindex to get the name and data stream 
        string filename = filenames[fileIndex]; 
        MemoryStream filestream = filestreams[fileIndex]; 

        //save the file stream using its name to the application path 
        FileStream outputStream = File.Create(Path.Combine(path, GetStrippedFileName(filename))); 
        filestream.WriteTo(outputStream); 
        outputStream.Close(); 
       } 
       catch (IOException ex) 
       { 
        throw new Exception(ex.Message, ex); 
       } 
       catch (SecurityException ex) 
       { 
        throw new Exception(ex.Message, ex); 
       } 
      } 

     } 

     public static void SaveToFileSystem(FileContentDataObjectBase dataObject, string path) 
     { 
      dataObject.SaveToFileSystem(path); 
     } 

     public abstract void SaveToFileSystem(string path); 

     private static string GetStrippedFileName(string input) 
     { 
      foreach (var chr in Path.GetInvalidFileNameChars()) 
       input = input.Replace(chr.ToString(), String.Empty); 
      return input; 
     } 

     #endregion 

} 

Я хотел бы понять, почему это происходит и как я могу исправить проблема.

Любая помощь или идеи будут приветствоваться.

Заранее спасибо.

ответ

5

После поиска довольно долго я, наконец, нашел проблему благодаря this полезный комментарий.

Как оказалось, объявления FILEGROUPDESCRIPTORA и FILEGROUPDESCRIPTORW в исходном коде, который мы использовали, являются неправильными, что может привести к исключению AccessViolation в некоторых случаях.

Так что я сделал изменения заявления как commentor, описанным из ...

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public sealed class FILEGROUPDESCRIPTORA 
{ 
    public uint cItems; 
    public FILEDESCRIPTORA[] fgd; 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public sealed class FILEGROUPDESCRIPTORW 
{ 
    public uint cItems; 
    public FILEDESCRIPTORW[] fgd; 
} 

К ...

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public sealed class FILEGROUPDESCRIPTORA 
{ 
    public uint cItems; 
    public FILEDESCRIPTORA fgd; 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public sealed class FILEGROUPDESCRIPTORW 
{ 
    public uint cItems; 
    public FILEDESCRIPTORW fgd; 
} 

Впоследствии AccessViolation Исключение ушло, и я только должен был изменить оригинал код Я связал в своем вопросе немного больше, чтобы заставить его работать.

Я должен был добавить дополнительные проверки во время обработки формата файлов FileContents для файлов Clipboard, чтобы каждый раз использовать правильные два FILEGROUPDESCRIPTOR, но теперь он отлично работает.

1

В вашем коде может быть ошибка. Эта первая строка ниже в обработчике для 'FILEGROUPDESCRIPTORW' может/не удастся на машине Win8.

заменить

object fileGroupDescriptorObject = Marshal.PtrToStructure(fileGroupDescriptorWPointer, typeof(NativeMethods.FILEGROUPDESCRIPTORW)); 
NativeMethods.FILEGROUPDESCRIPTORW fgd = (NativeMethods.FILEGROUPDESCRIPTORW)fileGroupDescriptorObject; 
files = new NativeMethods.FILEDESCRIPTOR[fgd.cItems]; 
pdata = (IntPtr)((int)pdata + Marshal.SizeOf(pdata)); 
for (int index = 0; index < fgd.cItems; index++) 

с

int ITEMCOUNT = Marshal.ReadInt32(pdata);     
files = new NativeMethods.FILEDESCRIPTOR[ITEMCOUNT]; 
// Set our pointer offset to the beginning of the FILEDESCRIPTOR* array 
pdata = (IntPtr)((long)pdata + Marshal.SizeOf(pdata)); 
// Walk the array, converting each FILEDESCRIPTOR* to a FILEDESCRIPTOR 
for (int index = 0; index < ITEMCOUNT; index++) 

Для получения более подробной информации см:

Drag-and-Drop multiple Attached File From Outlook to C# Window Form