2012-02-26 2 views
25

最近、非常に大きなプロジェクトを.NET Framework 3.5から4にアップグレードしましたが、当初はすべてが同じように動作していました。しかし、現在、コピー貼り付け操作でバグが表示され始めています。 私は小さな再現可能なアプリケーションを作成しました。これは.NET 3.5と4で異なる動作を示しています。 回避策を見つけました(手動でデータをクリップボードにシリアル化します)。しかし、 「なぜ」、行動に違いがあります。.NET 3.5と4ではクリップボードの動作が異なりますが、なぜですか?

これは私が作った小さなテストアプリです:

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出力:
シリアライザ:すべての良い
クリップボード:すべての良い

.NET 4出力:
シリアライザ:すべてgood
クリップボード:リストはnullです

クリップボード& DataObjectクラスの.NETソースを調べましたが、どのシリアライザが使用されているのかわかりませんでした。 MSDNのドキュメントでは、型がシリアライズ可能でなければならないとしています。この場合、List <>とElementクラスの両方があります。 Elementオブジェクトのコピーはうまくいきますが、要素のリストをコピーするとすぐに破棄されます。

私はVisual Studio 2010 SP1で2つのC# "コンソールアプリケーション"プロジェクトを作成しました。最初のプロジェクトでは、既定の "ターゲットフレームワーク"の設定である ".NET Framework 4 Client Profile"の設定が残っています。 2番目のプロジェクト「.NET Framework 3.5 Client Profile」を使用するように変更しました。

私のフォームDLLのバージョンに関する追加情報:
オリジナルファイル名:のSystem.Windows.Forms.dll
ファイルのバージョン/ Prouctバージョン:4.0.30319.235
言語:英語(米国)
変更日:16に-02-2012 22:50

+0

.NET 4ではうまく動作します...どちらの場合も "all good"と表示されます –

+0

私のマシンでは3.5でうまく動作し、4.0と同じようにターゲットフレームワークとして失敗します状態(Clipboard.GetDataObject()。GetData()に "無効なFORMATETC構造体" COM例外がスローされます)。また、私は似たような問題を発見しました:https://connect.microsoft.com/VisualStudio/feedback/details/488627/comexception-invalid-formatetc-structure-while-pasting-marshalbyref-data-from-datagridview – Alan

+0

(VS2010 SP1 on XP SP3) – Alan

答えて

26

I repro。 Debug + Exceptionsを使用してバグの詳細を確認し、CLR例外のThrownチェックボックスにチェックマークを付けることができます。フレームワーク内のクリップボードコードによって内部例外がスローされると、プログラムが停止します。 IDataObject.GetDataHere()実装メソッドは、COM例外、 "無効なFORMATETC構造体(例外:HRESULT:0x80040064(DV_E_FORMATETC))"で失敗します。

フォーマットに問題があります。これは、Clipboard.SetDataObject(obj)ステートメントの後にブレークポイントを設定すると明らかになります。また、Clipboard.GetDataObject()。GetFormats()をデバッガのウォッチ式に配置します。私は、以下を参照してください。

"System.Collections.Generic.List`1 [[ClipboardTest.Program +要素、ConsoleApplication1、バージョン= 1.0.0.0、文化=中立、公開は"

注方法文字列が切り詰められると、PublicKeyTokenの部分がマングルされます。名前空間名とプロジェクト名を変更することによって、この切り詰められた文字列を任意に変更できます。それらを十分に短くすると、プログラムは失敗しません。

明らかにこれが問題の原因です。文字列の長さは127文字にクリップされます。フルネームが長すぎると、このエラーが発生します。彼らは非常に長い名前を持っているので、これはジェネリック型である可能性が高いです。

このバグはconnect.microsoft.comに報告してください。あなたのコードはバグを非常にうまく示しています。バグレポートにリンクを投稿するだけで十分です。私は非常に良い回避策を持っていない、名前が十分に短いことを保証することはあまり実用的ではありません。

 // 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:このバグはVS2013で固定報告されていますが、このようなコードでできます。

+0

ああ..今それははるかに理にかなっている。また、私の手動シリアル化回避策がなぜ機能するのかも説明します。どうもありがとう。 – bitmonk8

+0

接続時に提出:https://connect.microsoft.com/VisualStudio/feedback/details/726652/clipboard-truncates-type-name-to-127-characters –

+0

おっと..私たちは二重提出されたようです。 https://connect.microsoft.com/VisualStudio/feedback/details/726654/clipboard-has-different-undocumented-behavior-in-net-3-5-and-4 – bitmonk8

関連する問題