为什么下面的代码有时会发生与内容“CLIPBRD_E_CANT_OPEN”异常:
Clipboard.SetText(str);
这通常发生在第一时间剪贴板在应用程序,而不是之后使用。
为什么下面的代码有时会发生与内容“CLIPBRD_E_CANT_OPEN”异常:
Clipboard.SetText(str);
这通常发生在第一时间剪贴板在应用程序,而不是之后使用。
其实,我觉得这是Win32 API中的故障 。
要在剪贴板组数据,你必须打开它第一。 只有一个进程可以有剪贴板一次打开。 所以,当你检查,如果另一个进程具有打开剪贴板以任何理由 ,你试图打开它将会失败。
它只是恰巧,终端服务跟踪剪贴板,并在旧版本的Windows(Vista以前的),你必须打开剪贴板看看里面有什么......这最终阻止你。 唯一的解决办法是等待,直到终端服务关闭剪贴板,然后再试一次。
要认识到这是不是针对终端服务是很重要的,虽然:它可以与任何事情发生。 在Win32的剪贴板工作是一个巨大的竞争条件。 但是,由于设计你只应该用剪贴板渣土响应用户输入的身边,这通常不会出现问题。
这是通过终端服务的剪贴板(以及可能的其他东西)和剪贴板的.NET实现中的错误/功能引起的。 在打开剪贴板的延迟导致错误,这通常通过在几毫秒内。
解决的办法是在一个循环中尝试多次之间长裤睡觉
for (int i = 0; i < 10; i++)
{
try
{
Clipboard.SetText(str);
return;
}
catch { }
System.Threading.Thread.Sleep(10);
}
我知道这个问题是旧的,但问题依然存在。 如前所述,当系统剪贴板被另一进程阻塞,就会发生这种异常。 不幸的是,有很多剪断工具,截图和文件复制工具,它可以阻止Windows剪贴板程序。 所以,你会在每次您尝试使用时间得到异常Clipboard.SetText(str)
时,在电脑上安装这种工具。
解:
从不使用
Clipboard.SetText(str);
改用
Clipboard.SetDataObject(str);
其实有可能是手头的另一个问题。 该框架调用(无论是WPF和WinForm的口味),以这样的事情(代码是从反射镜):
private static void SetDataInternal(string format, object data)
{
bool flag;
if (IsDataFormatAutoConvert(format))
{
flag = true;
}
else
{
flag = false;
}
IDataObject obj2 = new DataObject();
obj2.SetData(format, data, flag);
SetDataObject(obj2, true);
}
需要注意的是SetDataObject总是与真所谓在这种情况下。
内部触发两次调用Win32 API的,一个设置数据,因此它的可用应用程序关闭后,一个从应用中冲洗掉。
我见过几个应用程序(一些镀铬插件和下载管理器)侦听到剪贴板事件。 一旦第一个电话打,应用程序将打开剪贴板中寻找到的数据,第二次调用刷新将失败。
有没有发现,除了编写使用直接的Win32 API我自己的剪贴板类或直接与假称setDataObject保持数据的应用程序关闭后一个很好的解决方案。
我解决了这个问题,对使用本机Win32函数自己的应用程序:OpenClipboard(),CloseClipboard()和SetClipboardData()。
下面的包装类我做了。 任何人都可以请审查,并判断它是否正确 。 特别是当托管代码运行的应用程序的x64(我使用任何CPU在项目选项)。 当我从64位应用程序链接到库的x86,会发生什么?
谢谢!
下面的代码:
public static class ClipboardNative
{
[DllImport("user32.dll")]
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
private static extern bool CloseClipboard();
[DllImport("user32.dll")]
private static extern bool SetClipboardData(uint uFormat, IntPtr data);
private const uint CF_UNICODETEXT = 13;
public static bool CopyTextToClipboard(string text)
{
if (!OpenClipboard(IntPtr.Zero)){
return false;
}
var global = Marshal.StringToHGlobalUni(text);
SetClipboardData(CF_UNICODETEXT, global);
CloseClipboard();
//-------------------------------------------
// Not sure, but it looks like we do not need
// to free HGLOBAL because Clipboard is now
// responsible for the copied data. (?)
//
// Otherwise the second call will crash
// the app with a Win32 exception
// inside OpenClipboard() function
//-------------------------------------------
// Marshal.FreeHGlobal(global);
return true;
}
}
这发生在我在我的WPF应用程序。 我OpenClipboard失败(异常来自HRESULT:0x800401D0(CLIPBRD_E_CANT_OPEN))。
我用
ApplicationCommands.Copy.Execute(null, myDataGrid);
解决方法是先清除剪贴板
Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);