2012-02-26 36 views
25

Gần đây, chúng tôi đã nâng cấp một dự án rất lớn từ .NET framework 3.5 đến 4 và ban đầu mọi thứ dường như hoạt động tương tự. Nhưng bây giờ lỗi đã bắt đầu xuất hiện trên các hoạt động sao chép dán. Tôi đã quản lý để tạo ra một ứng dụng nhỏ có thể tái sản xuất, cho thấy hành vi khác nhau trong .NET 3.5 và 4. Tôi cũng đã tìm thấy cách giải quyết (tuần tự hóa dữ liệu vào khay nhớ tạm), nhưng tôi cần phải biết "tại sao" có một sự khác biệt trong hành vi.Clipboard hoạt động khác nhau trong .NET 3.5 và 4, nhưng tại sao?

Đây là ứng dụng thử nghiệm nhỏ tôi đã thực hiện:

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 đầu ra:
Serializer: tất cả tốt
Clipboard: tất cả tốt

NET 4 đầu ra:
Serializer : tất cả tốt
Clipboard: Danh sách là null

Tôi đã xem xét các nguồn NET cho Clipboard & lớp DataObject, nhưng tôi không thể nhìn thấy những gì serializer được sử dụng. Các tài liệu MSDN nói rằng loại phải được serializable, mà trong trường hợp này cả hai danh sách <> và các lớp Element. Việc sao chép đối tượng Element chỉ hoạt động tốt, nhưng ngay sau khi tôi sao chép danh sách các phần tử, nó sẽ phá vỡ.

Để kiểm tra, tôi đã tạo 2 dự án "Ứng dụng bảng điều khiển" C# trong Visual Studio 2010 SP1. Dự án đầu tiên tôi đã để lại với thiết lập "Target framework" mặc định của ".NET Framework 4 Client Profile". Dự án thứ hai tôi đã sửa đổi để sử dụng ".NET Framework 3.5 Client Profile".

Thông tin thêm về hình thức phiên bản của tôi DLL:
gốc filename: System.Windows.Forms.dll
phiên bản File/prouct phiên bản: 4.0.30319.235
Ngôn ngữ: English (United States)
Ngày sửa đổi: 16 -02-2012 22:50

+0

Đối với tôi nó hoạt động tốt với .NET 4 ... nó in "tất cả tốt" cho cả hai trường hợp –

+0

Hm, trên máy của tôi, nó hoạt động tốt với 3.5 và không thành công trên 4.0 được đặt làm khung đích, giống như OP các trạng thái (nó ném một cấu trúc "FORMATETC cấu trúc không hợp lệ" COM trong Clipboard.GetDataObject(). GetData()). Ngoài ra, tôi đã tìm thấy một vấn đề tương tự ở đây: https://connect.microsoft.com/VisualStudio/feedback/details/488627/comexception-invalid-formatetc-structure-while-pasting-marshalbyref-data-from-datagridview – Alan

+0

(sử dụng VS2010 SP1 trên XP SP3) – Alan

Trả lời

26

Tôi repro. Bạn có thể hiểu rõ hơn về lỗi với Debug + Exceptions, đánh dấu vào hộp kiểm Thrown cho các ngoại lệ CLR. Điều đó sẽ dừng chương trình khi một ngoại lệ bên trong được ném bởi mã clipboard trong khung công tác. Phương thức triển khai IDataObject.GetDataHere() không thành công với ngoại lệ COM, "Cấu trúc FORMATETC không hợp lệ (Ngoại lệ từ HRESULT: 0x80040064 (DV_E_FORMATETC))".

Có gì đó sai với định dạng. Điều đó trở nên rõ ràng khi bạn thiết lập một điểm ngắt sau câu lệnh Clipboard.SetDataObject (obj). Và đặt Clipboard.GetDataObject() GetFormats() trong một biểu thức xem trình gỡ lỗi. Tôi thấy:

"System.Collections.Generic.List`1 [[ClipboardTest.Program + Element, ConsoleApplication1, Version = 1.0.0.0, Culture = trung lập, công khai"

Lưu ý như thế nào chuỗi bị cắt ngắn, phần PublicKeyToken bị xáo trộn. Bạn có thể tùy ý thay đổi chuỗi bị cắt ngắn này bằng cách thay đổi tên không gian tên và tên dự án. Làm cho chúng đủ ngắn và chương trình sẽ không thành công.

Rõ ràng đây là nguyên nhân của sự cố. Độ dài chuỗi được cắt bớt thành 127 ký tự, bất kỳ loại nào có tên đầy đủ dài hơn sẽ gây ra lỗi này. Với khả năng cao, đây sẽ là loại chung vì chúng có tên rất dài.

Vui lòng báo cáo lỗi này tại connect.microsoft.com. Mã của bạn thể hiện lỗi rất tốt, chỉ cần đăng một liên kết đến nó trong báo cáo lỗi của bạn là đủ. Tôi không có cách giải quyết tốt, đảm bảo tên đủ ngắn không thực tế lắm. Nhưng bạn có thể với mã như thế này:

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

UPDATE: lỗi này được báo cáo cố định trong VS2013.

+0

Ahh .. bây giờ nó có ý nghĩa hơn nhiều. Và nó cũng giải thích tại sao workaround serialization thủ công của tôi hoạt động. Cảm ơn rất nhiều. – bitmonk8

+0

Nộp tại kết nối: https://connect.microsoft.com/VisualStudio/feedback/details/726652/clipboard-truncates-type-name-to-127-characters –

+0

Rất tiếc .. Có vẻ như chúng tôi đã gửi gấp đôi. https://connect.microsoft.com/VisualStudio/feedback/details/726654/clipboard-has-different-undocumented-behavior-in-net-3-5-and-4 – bitmonk8

Các vấn đề liên quan