2012-02-26 11 views
25

Recientemente actualizamos un proyecto muy grande de .NET framework 3.5 a 4, e inicialmente todo parecía funcionar de la misma manera. Pero ahora los errores han comenzado a aparecer en las operaciones de copiar y pegar. He logrado hacer una pequeña aplicación reproducible, que muestra el comportamiento diferente en .NET 3.5 y 4. También encontré una solución alternativa (serializar manualmente los datos en el portapapeles), pero me queda una necesidad de saber "por qué" hay una diferencia en el comportamiento.El portapapeles se comporta de manera diferente en .NET 3.5 y 4, pero ¿por qué?

Ésta es la aplicación de prueba pequeña que hice:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Windows.Forms; 

namespace ClipboardTest 
{ 
    public class Program 
    { 
     [Serializable] 
     public class Element 
     { 
      public Element(string name) 
      { 
       this.name = name; 
      } 

      public string name; 
     } 

     public static List<Element> TestSerializer(List<Element> obj) 
     { 
      var memoryStream = new MemoryStream(); 
      var formatter = new BinaryFormatter(); 
      formatter.Serialize(memoryStream, obj); 
      return (List<Element>)formatter.Deserialize(new MemoryStream(memoryStream.GetBuffer())); 
     } 

     public static List<Element> TestClipboard(List<Element> obj) 
     { 
      Clipboard.SetDataObject(obj); 
      return (List<Element>)Clipboard.GetDataObject().GetData(typeof(List<Element>)); 
     } 

     public static void DumpObject(string testName, List<Element> obj) 
     { 
      if (obj == null) 
      { 
       Console.WriteLine("{0} : List is null", testName); 
       return; 
      } 
      foreach (var prop in obj) 
      { 
       Console.WriteLine("{0} : {1}", testName, prop.name); 
      } 
     } 

     [STAThread] 
     static void Main() 
     { 
      var copyData = new List<Element> { new Element("all good") }; 
      DumpObject("Serializer", TestSerializer(copyData)); 
      DumpObject("Clipboard", TestClipboard(copyData)); 
     } 
    } 
} 

.NET 3.5 de salida:
Serializador: todo bien
portapapeles: todo bien

.NET 4 de salida:
Serializador : todo bien
Portapapeles: La lista es nula

He consultado la fuente de .NET para la clase DataObject Clipboard &, pero no pude ver qué serializador se utilizó. La documentación de MSDN dice que el tipo debe ser serializable, que en este caso son las clases List <> y Element. Copiar un objeto Element funciona bien, pero tan pronto como copie una lista de elementos, se rompe.

Para probar, he creado 2 proyectos C# "Aplicación de consola" en Visual Studio 2010 SP1. El primer proyecto que me queda con la configuración predeterminada "Marco de destino" de ".NET Framework 4 Client Profile". El segundo proyecto que modifiqué para usar ".NET Framework 3.5 Client Profile".

información adicional sobre las Formas mi versión de DLL:
Nombre original del archivo: System.Windows.Forms.dll
versión Archivo/versión prouct: 4.0.30319.235
Idioma: Inglés (Estados Unidos)
Fecha de modificación: 16 -02-2012 22:50

+0

Para mí funciona bien con .NET 4 ... imprime "todo bien" para ambos casos –

+0

Hm, en mi máquina, funciona bien con 3.5 y falla en 4.0 como marco de destino, al igual que el OP estados (arroja una excepción COM "Estructura de FORMATETC inválida" en Clipboard.GetDataObject(). GetData()). Además, encontré un problema similar aquí: https://connect.microsoft.com/VisualStudio/feedback/details/488627/comexception-invalid-formatetc-structure-while-pasting-marshalbyref-data-from-datagridview – Alan

+0

(utilizando VS2010 SP1 en XP SP3) – Alan

Respuesta

26

I repro. Puede obtener más información sobre el error con Debug + Exceptions, marque la casilla de verificación Thrown para excepciones de CLR. Eso detendrá el programa cuando el código del portapapeles en el marco genere una excepción interna. El método de implementación IDataObject.GetDataHere() falla con una excepción COM, "estructura INVALID FORMATETC (Excepción de HRESULT: 0x80040064 (DV_E_FORMATETC))".

Hay algo mal con el formato. Eso se vuelve claro cuando establece un punto de interrupción después de la instrucción Clipboard.SetDataObject (obj). Y coloque Clipboard.GetDataObject(). GetFormats() en una expresión de reloj del depurador. Veo:

"System.Collections.Generic.List`1 [[ClipboardTest.Program + Elemento, ConsoleApplication1, Version = 1.0.0.0, Culture = neutral, Públicos"

Nota cómo el cadena se trunca, la parte PublicKeyToken se destrozó. Puede modificar arbitrariamente esta cadena truncada cambiando el nombre del espacio de nombres y el nombre del proyecto. Hazlos lo suficientemente cortos y el programa no fallará.

Claramente esta es la causa del problema. La longitud de la cadena está recortada a 127 caracteres, cualquier tipo cuyo nombre completo sea más largo que el que va a causar esta falla. Con una alta probabilidad de que este sea un tipo genérico ya que tienen nombres muy largos.

Informe este error en connect.microsoft.com. Su código demuestra muy bien el error, bastará con publicar un enlace en el informe de errores. No tengo una solución muy buena, asegurarme de que el nombre sea lo suficientemente breve no es muy práctico. Pero se puede con código como el siguiente:

 // Put it on the clipboard, use a wrapper type with a short name 
     var envelope = new List<object>(); 
     envelope.AddRange(obj); 
     Clipboard.SetDataObject(envelope); 

     // Retrieve from clipboard, unwrap back to original type 
     envelope = (List<object>)Clipboard.GetDataObject().GetData(typeof(List<object>)); 
     var retval = new List<Element>(); 
     retval.AddRange(envelope.Cast<Element>()); 
     return retval; 

ACTUALIZACIÓN: Se ha informado de este error corregido en VS2013.

+0

Ahh ... ahora tiene mucho más sentido. Y también explica por qué funciona mi solución de serialización manual. Muchas gracias. – bitmonk8

+0

Archivado en connect: https://connect.microsoft.com/VisualStudio/feedback/details/726652/clipboard-truncates-type-name-to-127-characters –

+0

Whoops ... Parece que hemos archivado dos veces. https://connect.microsoft.com/VisualStudio/feedback/details/726654/clipboard-has-different-undocumented-behavior-in-net-3-5-and-4 – bitmonk8

Cuestiones relacionadas