如何处理被阻止的剪贴板和其他奇怪的事情

Ric*_*ter 50 .net c# clipboard

在过去的几个小时里,我一直在跟踪一个相当具体的错误,因为另一个应用程序打开了剪贴板.基本上,因为剪贴板是一个共享资源(根据"为什么我的共享剪贴板不起作用?")并且您尝试执行

Clipboard.SetText(string)
Run Code Online (Sandbox Code Playgroud)

要么

Clipboard.Clear().
Run Code Online (Sandbox Code Playgroud)

抛出以下异常:

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毫秒.

最终用户已经注意到最后一件事,即尽管异常被抛出,副本到剪贴板操作仍然有效,但我还没有找到任何关于为什么会这样做的进一步信息.

我目前解决这个问题的方法就是默默地忽略异常...这真的是最好的方法吗?

Ale*_*lex 41

我很抱歉复活了一个旧问题,但另一种解决方法是使用Clipboard.SetDataObject而不是Clipboard.SetText.

根据这篇msdn文章,这个方法有两个参数 - retryTimesretryDelay--你可以像这样使用:

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
Run Code Online (Sandbox Code Playgroud)

  • 请不要在.NET框架中有两个`Clipboard`类.一个在`System.Windows.Forms`命名空间,另一个在`System.Windows`命名空间(用于WPF).只有第一个具有重载次数和延迟的重载. (4认同)

Phi*_*ice 28

由于剪贴板由所有UI应用程序共享,你会遇到这种不时显然,你不想让你的应用程序崩溃,如果它无法写入剪贴板,所以适当地处理ExternalException是合理的,我会建议提呈如果setobjectdata调用写入剪贴板失败,则会给用户带来错误.

一个建议是使用(通过P/Invoke的)user32!GetOpenClipboardWindow,看是否另一个应用程序具有打开剪贴板,它会返回HWND具有剪贴板打开的窗口,或者IntPtr.Zero如果没有应用程序有它打开,你可以旋转的价值直到它IntPtr.Zero达到指定的时间.


Jef*_*Roe 12

我今天遇到了这个错误.我决定通过告诉用户可能行为不端的应用程序来处理它.为此,您可以执行以下操作:

[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
}
Run Code Online (Sandbox Code Playgroud)

对我来说,问题窗口标题是"skype_plugin_core_proxy_window".我搜索了这方面的信息,并且惊讶地发现它只产生了一次打击,那是俄语.所以我添加了这个答案,既为该字符串提供了另一个答案,又提供了进一步的帮助,以便将可能行为不端的应用程序点亮.


Tri*_*nko 7

首先调用这个:

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr CloseClipboard();
Run Code Online (Sandbox Code Playgroud)

我注意到,如果您正在进行粘贴操作(WM_PASTE 消息),包括在 TextChanged 事件期间,剪贴板将保持由接收该事件的窗口(TextBox)锁定。因此,如果您只是在事件处理程序中调用“CloseClipboard”方法,那么您可以调用托管的 Clipboard.Clear 和 Clipboard.SetText 方法,而不会出现任何问题或延迟。


小智 5

Clipboard.Clear()之前Clipboard.SetDataObject(pasteString, true)似乎可以解决问题。

之前的设置建议对我来说retryTimes不起作用retryDelay,无论如何默认值retryTimes = 10retryDelay = 100ms