如何处理剪贴板阻塞和其他异常情况
在过去的几个小时中,我一直在追踪一个相当具体的错误,该错误是由于另一个应用程序打开了剪贴板而发生的。 本质上,因为剪贴板是共享资源(根据 "为什么我的共享剪贴板不起作用?"),并且您尝试执行
Clipboard.SetText(string)
或
Clipboard.Clear().
抛出以下异常:
System.Runtime.InteropServices.ExternalException: Requested Clipboard operation did not succeed. at System.Windows.Forms.Clipboard.ThrowIfFailed(Int32 hr) at System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32 retryTimes, Int32 retryDelay) at System.Windows.Forms.Clipboard.SetText(String text, TextDataFormat format) at System.Windows.Forms.Clipboard.SetText(String text)
我最初的解决方案是短暂暂停后重试,直到我意识到 Clipboard.SetDataObject 有用于次数和延迟长度的字段。 .NET 的默认行为是尝试 10 次,延迟 100 毫秒。
最终用户注意到了最后一件事。 也就是说,尽管抛出异常,复制到剪贴板操作仍然有效。 我无法找到有关原因的任何进一步信息。
我目前对问题的解决方案只是默默地忽略异常......这真的是最好的方法吗?
Over the course of the last couple of hours I have been tracking down a fairly specific bug with that occurs because another application has the clipboard open. Essentially as the clipboard is a shared resource (as per "Why does my shared clipboard not work?") and you attempt to execute
Clipboard.SetText(string)
or
Clipboard.Clear().
The following exception is thrown:
System.Runtime.InteropServices.ExternalException: Requested Clipboard operation did not succeed. at System.Windows.Forms.Clipboard.ThrowIfFailed(Int32 hr) at System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32 retryTimes, Int32 retryDelay) at System.Windows.Forms.Clipboard.SetText(String text, TextDataFormat format) at System.Windows.Forms.Clipboard.SetText(String text)
My initial solution was to retry after a short pause, until I realised that Clipboard.SetDataObject has fields for the number of times and the length of the delay. .NET's default behaviour is to try 10 times with a 100 msec delay.
There is one final thing that has been noted by the end user. That is, despite the exception being thrown, the copy to clipboard operation still works. I haven't been able to find any further information about why this may be.
My current solution to the issue is just to silently ignore the exception... is this really the best way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
在
Clipboard.SetDataObject(pasteString, true)
之前执行Clipboard.Clear()
似乎可以解决问题。之前设置
retryTimes
和retryDelay
的建议对我来说不起作用,无论如何,默认值是retryTimes = 10
和retryDelay = 100 毫秒
Doing a
Clipboard.Clear()
beforeClipboard.SetDataObject(pasteString, true)
seems to do the trick.The earlier suggestion of setting
retryTimes
andretryDelay
didn't work for me and in any case the defaults areretryTimes = 10
andretryDelay = 100ms
首先调用它:
我注意到,如果您正在进行粘贴操作(WM_PASTE 消息),包括在 TextChanged 事件期间,剪贴板将保持由接收该事件的窗口(TextBox)锁定。 因此,如果您只是在事件处理程序中调用“CloseClipboard”方法,那么您可以调用托管的 Clipboard.Clear 和 Clipboard.SetText 方法,而不会出现任何问题或延迟。
Just call this first:
I noticed that if you're in the middle of a paste operation (WM_PASTE message), including during the TextChanged event, the clipboard remains locked by the window (the TextBox) receiving the event. So if you just call that "CloseClipboard" method inside the event handler, then you can call the managed Clipboard.Clear and Clipboard.SetText methods without any issues or delays.
我今天遇到了这个错误。 我决定通过告诉用户潜在的行为不当的应用程序来处理它。 为此,您可以执行以下操作:
对我来说,问题窗口标题是“skype_plugin_core_proxy_window”。 我搜索了相关信息,令我惊讶的是它只产生了一个点击,而且是俄语的。 因此,我添加这个答案,既是为了再次打击该字符串,也是为了提供进一步的帮助,以揭露潜在的行为不当的应用程序。
I ran into this error today. I decided to handle it by telling the user about the potentially misbehaving application. To do so, you can do something like this:
For me, the problem window title was "skype_plugin_core_proxy_window". I searched for info on that, and was surprised that it yielded only one hit, and that was in Russian. So I'm adding this answer, both to give another hit for that string, and to provide further help to bring potentially-misbehaving apps to light.
由于剪贴板是由所有 UI 应用程序共享的,因此您有时会遇到这种情况。 显然,您不希望应用程序在无法写入剪贴板时崩溃,因此优雅地处理ExternalException是合理的。 我建议如果写入剪贴板的 SetObjectData 调用失败,则向用户显示错误。
建议使用(通过P/Invoke)
user32!GetOpenClipboardWindow
查看其他应用程序是否具有剪贴板打开。 它将返回打开剪贴板的窗口的 HWND,如果没有应用程序打开它,则返回 IntPtr.Zero。 您可以旋转该值,直到达到IntPtr.Zero
指定的时间。As the clipboard is shared by all UI applications, you will run into this from time to time. Obviously, you don't want your application to crash if it failed to write to the clipboard, so gracefully handling ExternalException is reasonable. I would suggest presenting an error to the user if the SetObjectData call to write to the clipboard fails.
A suggestion would be to use (via P/Invoke)
user32!GetOpenClipboardWindow
to see if another application has the clipboard open. It will return the HWND of the window which has the clipboard open, orIntPtr.Zero
if no application had it open. You could spin on the value until itsIntPtr.Zero
for a specified amount of time.另一种解决方法是使用
Clipboard.SetDataObject
而不是Clipboard.SetText
。根据 这篇 MSDN 文章,此方法有两个参数 - retryTimes 和 retryDelay - 您可以像这样使用:
Another workaround would be to use
Clipboard.SetDataObject
instead ofClipboard.SetText
.According to this MSDN article this method has two parameters - retryTimes and retryDelay - that you can use like this:
通过使用 Jeff Roe 的代码(Jeff 的代码),
您能够以非常方便的方式处理错误。
我通过使用 System.Windows.Forms.Clipboard 而不是 System.Windows.Clipboard 成功地降低了错误发生的频率。
我强调,这并不能解决问题,但它减少了我的应用程序的发生率。
By making use of Jeff Roe's code (Jeff's Code)
you are able to handle the error in a pretty handy way.
I have managed to reduce the frequency of the error by making use of
System.Windows.Forms.Clipboard
Instead ofSystem.Windows.Clipboard
.I stress that this doesn't fix the problem but it has reduced the occurrence for my application.
我实际上已经提出了自己的解决方案,它似乎对我有用。
这显然是 C#,但是这些方法向所有 Visual Studio 公开。 显然,我创建了一个循环函数,并尝试通过重试将其强制放入剪贴板。
基本上这就是流程。 假设您要将单词剪贴板放入剪贴板中的代码中的任何位置(假设已定义此函数)。
是的,如果您知道无论如何您的剪贴板都会出现异常(无限循环),那么这确实有一个缺陷。 但是,我还没有使用此方法遇到无限循环。 另一个缺陷是,它可能需要几秒钟的时间(基本上会减慢您的应用程序的速度)才能工作,在尝试时可能会冻结您的应用程序,一旦成功,应用程序无论如何都会继续。
I've actually come up with my own solution and it seems to be working for me.
This is obviously C#, however these methods are exposed to all Visual Studios. I have obviously created a looping function, as well as attempted to force it into the clipboard with retries.
Essentially here's the flow. Let's say you want to place the word clipboard into the clipboard, anywhere in your code (assuming this function is defined).
Yes, this does have a flaw if you know your clipboard will always have an exception no matter what (infinite loop). However I have not run into an infinite loop with this method yet. The other flaw is that it can take a couple of seconds (essentially slowing down your applications) before it will work, while it's attempting it may freeze your application, once it succeeds the application will continue anyway.
这有点糟糕......但它解决了我的问题。
延迟后重试clear()。
更多信息请参阅博客文章如何处理阻止的剪贴板 - Clipboard.Clear() 错误。
This is bit crappy... But it solved my problem.
Retry the clear() after a delay.
More information is in the blog post How to handle a blocked clipboard - Clipboard.Clear() error.