使用Windows剪贴板

时间:2016-10-03 12:48:11

标签: c# wpf google-chrome clipboard

我正在维护一个WPF .NET应用程序,并且用户在尝试从DataGrid控件进行复制时遇到了崩溃。我用谷歌搜索,发现其原因是他使用的其他一些应用程序可能没有调用CloseClipboard()。 Excel也在相同的情况下给出了一条错误消息,消息“我们无法释放剪贴板上的空间”。另一个程序现在可能正在使用它。'

然后我写了另一个程序,它有一个打开/关闭剪贴板的按钮,然后我可以重现这种行为,并且我实现了相同的修复'只是一条错误信息。

然而,出于好奇,我想看看谷歌浏览器如何处理这个问题。我使用我的程序锁定了剪贴板,并确认Excel正在抱怨。但是,Chrome仍然可以优雅地处理复制/粘贴。我可以从Chrome复制到记事本,但不能从记事本和Excel复制。而且很有趣,我实际上可以从记事本复制到Chrome。

我一直在浏览Chromium的源代码,但我无法找到复制/粘贴逻辑的实现。有谁知道Chrome如何处理这个问题?

我怎样才能在记事本中复制/粘贴,但从记事本到Chrome工作正常?

在我可以在网上找到的所有实现中,解决方案似乎与我现在的解决方案相同:在放弃之前尝试几次,大约一秒钟。

作为参考,这是我的剪贴板储物柜背后的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ClipboardLocker
{
    public partial class MainWindow : Window
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern IntPtr GetOpenClipboardWindow();

        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        static extern bool OpenClipboard(IntPtr hWndNewOwner);

        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        static extern bool CloseClipboard();

        bool clipboardLocked = false;

        public MainWindow()
        {
            InitializeComponent();

            double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
            double screenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;
            double windowWidth = this.Width;
            double windowHeight = this.Height;
            this.Left = (screenWidth / 2) - (windowWidth / 2);
            this.Top = (screenHeight / 2) - (windowHeight / 2);
        }

        private void LockButton_Click(object sender, RoutedEventArgs e)
        {
            if (!clipboardLocked)
            {
                IntPtr handle = GetOpenClipboardWindow();
                OpenClipboard(handle);
                clipboardLocked = true;
                LockButton.Content = "Unlock";
            }
            else
            {
                CloseClipboard();
                clipboardLocked = false;
                LockButton.Content = "Lock";
            }
        }
    }
}

[UPDATE]

经过一些实验,似乎Chrome能够以某种方式解锁剪贴板。在Chrome中完成复制/粘贴后,它也适用于其他应用程序。 Chromw如何偷窃'来自我的储物柜程序的剪贴板? MSDN mentioins ChangeClipboardChain。我会试着尝试一下。

2 个答案:

答案 0 :(得分:1)

要接管剪贴板,我首先使用OpenClipboard参数调用NULL。这会从当前持有它的任何窗口“窃取”剪贴板。然后我通过拨打CloseClipboard来关闭它。这将是有效的,因为剪贴板将是“打开的剪贴板与当前任务相关联”,如MSDN所示。

现在剪贴板已正确关闭,调用WPF或Windows窗体'Clipboard.SetText()可以正常工作。

这当然不是一个很好的解决方案,但我相信这是Windows在这种情况下给我们的最佳选择。

如果其他人遇到此问题,请点击此处ClipboardHelper

static class ClipboardHelper
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr GetOpenClipboardWindow();

    [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
    static extern bool OpenClipboard(IntPtr hWndNewOwner);

    [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
    static extern bool CloseClipboard();

    [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
    static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    public static bool SetText(string text)
    {
        IntPtr hWnd = GetOpenClipboardWindow(); // Gets the HWND of the window that currently owns the clipboard

        if (hWnd == null)   // If no window currently owns the clipboard, just go ahead and set the text.
        {
            System.Windows.Forms.Clipboard.SetText(text);
        }
        else
        {
            OpenClipboard(IntPtr.Zero);
            CloseClipboard();
            System.Windows.Forms.Clipboard.SetText(text);
        }
        return true;
    }
}

答案 1 :(得分:0)

将数据写入JSON文件而不是剪贴板。因此,即使程序将被关闭,您也可以访问值。