剪贴板在.NET 3.5和4中的表现不同,但原因是什么
本文关键字:是什么 NET 剪贴板 | 更新日期: 2023-09-27 18:25:45
我们最近将一个非常大的项目从.NET framework 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输出:
序列化程序:一切正常
剪贴板:列表为空
我已经看了剪贴板的.NET源代码&DataObject类,但我看不出使用了什么序列化程序。MSDN文档规定该类型必须是可序列化的,在这种情况下,List<>元素类为。复制一个Element对象效果很好,但一旦我复制了一个元素列表,它就会中断。
为了进行测试,我在VisualStudio2010SP1中创建了2个C#"控制台应用程序"项目。我留下的第一个项目是默认的"目标框架"设置".NET framework 4客户端配置文件"。我修改的第二个项目是使用".NET Framework 3.5客户端配置文件"。
有关我的窗体DLL版本的其他信息:
原始文件名:System.Windows.Forms.dll
文件版本/产品版本:4.0.30319.235
语言:英语(美国)
修改日期:2012年2月16日22:50
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+Element,ConsoleApplication1,Version=1.0.0.0,Culture=neutral,Public"
注意字符串是如何被截断的,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;
更新:据报道,此错误已在VS2013中修复。