设置从.NET剪贴板时CLIPBRD_E_CANT_OPEN错误设置从.NET剪贴板时CLIPBRD

2019-05-11 20:51发布

为什么下面的代码有时会发生与内容“CLIPBRD_E_CANT_OPEN”异常:

Clipboard.SetText(str);

这通常发生在第一时间剪贴板在应用程序,而不是之后使用。

Answer 1:

其实,我觉得这是Win32 API中的故障 。

要在剪贴板组数据,你必须打开它第一。 只有一个进程可以有剪贴板一次打开。 所以,当你检查,如果另一个进程具有打开剪贴板以任何理由 ,你试图打开它将会失败。

它只是恰巧,终端服务跟踪剪贴板,并在旧版本的Windows(Vista以前的),你必须打开剪贴板看看里面有什么......这最终阻止你。 唯一的解决办法是等待,直到终端服务关闭剪贴板,然后再试一次。

要认识到这是不是针对终端服务是很重要的,虽然:它可以与任何事情发生。 在Win32的剪贴板工作是一个巨大的竞争条件。 但是,由于设计你只应该用剪贴板渣土响应用户输入的身边,这通常不会出现问题。



Answer 2:

这是通过终端服务的剪贴板(以及可能的其他东西)和剪贴板的.NET实现中的错误/功能引起的。 在打开剪贴板的延迟导致错误,这通常通过在几毫秒内。

解决的办法是在一个循环中尝试多次之间长裤睡觉

for (int i = 0; i < 10; i++)
{
    try
    {
        Clipboard.SetText(str);
        return;
    }
    catch { }
    System.Threading.Thread.Sleep(10);
} 


Answer 3:

我知道这个问题是旧的,但问题依然存在。 如前所述,当系统剪贴板被另一进程阻塞,就会发生这种异常。 不幸的是,有很多剪断工具,截图和文件复制工具,它可以阻止Windows剪贴板程序。 所以,你会在每次您尝试使用时间得到异常Clipboard.SetText(str)时,在电脑上安装这种工具。

解:

从不使用

Clipboard.SetText(str);

改用

Clipboard.SetDataObject(str);


Answer 4:

其实有可能是手头的另一个问题。 该框架调用(无论是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保持数据的应用程序关闭后一个很好的解决方案。



Answer 5:

我解决了这个问题,对使用本机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;
    }
}


Answer 6:

这发生在我在我的WPF应用程序。 我OpenClipboard失败(异常来自HRESULT:0x800401D0(CLIPBRD_E_CANT_OPEN))。

我用

ApplicationCommands.Copy.Execute(null, myDataGrid);

解决方法是先清除剪贴板

Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);


文章来源: CLIPBRD_E_CANT_OPEN error when setting the Clipboard from .NET