C# 如何处理被阻止的剪贴板和其他奇怪的东西
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/930219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to handle a blocked clipboard and other oddities
提问by Richard Slater
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.
我最初的解决方案是在短暂的暂停后重试,直到我意识到 Clipboard.SetDataObject 具有用于次数和延迟长度的字段。.NET 的默认行为是尝试 10 次,延迟 100 毫秒。
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?
我目前对这个问题的解决方案只是默默地忽略异常......这真的是最好的方法吗?
采纳答案by Phil Price
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.
由于剪贴板由所有 UI 应用程序共享,因此您不时会遇到此问题。显然,您不希望应用程序在无法写入剪贴板时崩溃,因此优雅地处理 ExternalException 是合理的。如果 SetObjectData 调用写入剪贴板失败,我建议向用户显示错误。
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, or IntPtr.Zero
if no application had it open. You could spin on the value until its IntPtr.Zero
for a specified amount of time.
一个建议是使用(通过P/Invoke)user32!GetOpenClipboardWindow
来查看另一个应用程序是否打开了剪贴板。它将返回打开剪贴板的窗口的 HWND,或者IntPtr.Zero
如果没有应用程序打开它。您可以旋转该值直到其IntPtr.Zero
持续指定的时间。
回答by Alex
Another workaround would be to use Clipboard.SetDataObject
instead of Clipboard.SetText
.
另一种解决方法是使用Clipboard.SetDataObject
而不是Clipboard.SetText
.
According to this MSDN articlethis method has two parameters - retryTimesand retryDelay- that you can use like this:
根据这篇 MSDN 文章,该方法有两个参数 - retryTimes和retryDelay- 您可以像这样使用:
System.Windows.Forms.Clipboard.SetDataObject(
"some text", // Text to store in clipboard
false, // Do not keep after our application exits
5, // Retry 5 times
200); // 200 ms delay between retries
回答by Patrick Sameera
This is bit crappy... But it solved my problem.
这有点糟糕......但它解决了我的问题。
Retry the clear() after a delay.
延迟后重试 clear() 。
More information is in the blog post How to handle a blocked clipboard - Clipboard.Clear() error.
更多信息在博客文章如何处理被阻止的剪贴板 - Clipboard.Clear() 错误中。
回答by Jeff Roe
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:
我今天遇到了这个错误。我决定通过告诉用户潜在的行为不端的应用程序来处理它。为此,您可以执行以下操作:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetOpenClipboardWindow();
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int GetWindowText(int hwnd, StringBuilder text, int count);
private void btnCopy_Click(object sender, EventArgs e)
{
try
{
Clipboard.Clear();
Clipboard.SetText(textBox1.Text);
}
catch (Exception ex)
{
string msg = ex.Message;
msg += Environment.NewLine;
msg += Environment.NewLine;
msg += "The problem:";
msg += Environment.NewLine;
msg += getOpenClipboardWindowText();
MessageBox.Show(msg);
}
}
private string getOpenClipboardWindowText()
{
IntPtr hwnd = GetOpenClipboardWindow();
StringBuilder sb = new StringBuilder(501);
GetWindowText(hwnd.ToInt32(), sb, 500);
return sb.ToString();
// example:
// skype_plugin_core_proxy_window: 02490E80
}
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.
对我来说,问题窗口标题是“skype_plugin_core_proxy_window”。我搜索了这方面的信息,很惊讶它只产生了一次命中,而且是俄语。所以我添加了这个答案,既是为了再次打击该字符串,也是为了提供进一步的帮助,让潜在的行为不端的应用程序曝光。
回答by FlyingMongoose
I've actually come up with my own solution and it seems to be working for me.
我实际上提出了自己的解决方案,它似乎对我有用。
// This allows the clipboard to have something copied to it.
public static void ClipboardPaste(String pasteString)
{
// This clears the clipboard
Clipboard.Clear();
// This is a "Try" of the statement inside {}, if it fails it goes to "Catch"
// If it "Catches" an exception. Then the function will retry itself.
try
{
// This, per some suggestions I found is a half second second wait before another
// clipboard clear and before setting the clipboard
System.Threading.Thread.Sleep(500);
Clipboard.Clear();
// This is, instead of using SetText another method to put something into
// the clipboard, it includes a retry/fail set up with a delay
// It retries 5 times with 250 milliseconds (0.25 second) between each retry.
Clipboard.SetDataObject(pasteString, false, 5, 250);
}
catch (Exception)
{
ClipboardPaste(pasteString);
}
}
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.
这显然是 C#,但是这些方法向所有 Visual Studio 公开。我显然已经创建了一个循环函数,并试图通过重试将其强制放入剪贴板。
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).
基本上这里是流程。假设您想将剪贴板一词放入剪贴板中的代码中的任何位置(假设此函数已定义)。
- Call function ClipboardPaste("Clipboard");
- It will then clear the clipboard
- Then it will "try" to put your string into the clipboard.
- First it waits half a second (500 milliseconds)
- Clears the clipboard again
- Then it tries to put the string into the clipboard using SetDataObject
- SetDataObject if it fails will retry up to five times, with a 250 millisecond delay in between each retry.
- If the initial attempt fails, it catches the exception, the crash, then it tries it all over again.
- 调用函数 ClipboardPaste("剪贴板");
- 然后它会清除剪贴板
- 然后它会“尝试”将您的字符串放入剪贴板。
- 首先它等待半秒(500 毫秒)
- 再次清除剪贴板
- 然后它尝试使用 SetDataObject 将字符串放入剪贴板
- 如果失败,SetDataObject 将重试最多五次,每次重试之间有 250 毫秒的延迟。
- 如果初始尝试失败,它会捕获异常、崩溃,然后重新尝试。
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.
是的,如果您知道剪贴板无论如何都会有异常(无限循环),那么这确实存在缺陷。但是我还没有遇到这种方法的无限循环。另一个缺陷是它可能需要几秒钟(基本上会减慢您的应用程序的速度)才能工作,而它正在尝试它可能会冻结您的应用程序,一旦成功,该应用程序将继续运行。
回答by Tony Bennett
Doing a Clipboard.Clear()
before Clipboard.SetDataObject(pasteString, true)
seems to do the trick.
做一个Clipboard.Clear()
beforeClipboard.SetDataObject(pasteString, true)
似乎可以解决问题。
The earlier suggestion of setting retryTimes
and retryDelay
didn't work for me and in any case the defaults are retryTimes = 10
and retryDelay = 100ms
设置的早先提出的建议retryTimes
,并retryDelay
没有为我在任何情况下,默认的方式工作retryTimes = 10
和retryDelay = 100ms
回答by Triynko
Just call this first:
先调用这个:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr CloseClipboard();
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.
我注意到,如果您正在进行粘贴操作(WM_PASTE 消息),包括在 TextChanged 事件期间,剪贴板将保持被接收该事件的窗口(TextBox)锁定。因此,如果您只是在事件处理程序中调用“CloseClipboard”方法,那么您可以调用托管的 Clipboard.Clear 和 Clipboard.SetText 方法而不会出现任何问题或延迟。
回答by Strider2009
By making use of Jeff Roe's code (Jeff's Code)
通过使用 Jeff Roe 的代码 ( Jeff's Code)
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetOpenClipboardWindow();
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int GetWindowText(int hwnd, StringBuilder text, int count);
private void btnCopy_Click(object sender, EventArgs e)
{
try
{
Clipboard.Clear();
Clipboard.SetText(textBox1.Text);
}
catch (Exception ex)
{
string msg = ex.Message;
msg += Environment.NewLine;
msg += Environment.NewLine;
msg += "The problem:";
msg += Environment.NewLine;
msg += getOpenClipboardWindowText();
MessageBox.Show(msg);
}
}
private string getOpenClipboardWindowText()
{
IntPtr hwnd = GetOpenClipboardWindow();
StringBuilder sb = new StringBuilder(501);
GetWindowText(hwnd.ToInt32(), sb, 500);
return sb.ToString();
// example:
// skype_plugin_core_proxy_window: 02490E80
}
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 of System.Windows.Clipboard
.
我已经设法通过使用而System.Windows.Forms.Clipboard
不是减少错误的频率 System.Windows.Clipboard
。
I stress that this doesn't fix the problem but it has reduced the occurrence for my application.
我强调这并不能解决问题,但它减少了我的应用程序的发生率。