使用Windows剪贴板

问题描述:

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

然后我写了,有一个按钮,打开/关闭剪贴板另一个程序,然后我可以重现此问题,我实现了相同的“修复”,只需一个错误消息。

但是,出于好奇,我想看看Google Chrome如何处理这个问题。我使用我的程序锁定了剪贴板,并确认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"; 
      } 
     } 
    } 
} 

[更新]

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

+0

你有没有使用的WinForms剪贴板类测试(https://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard(v=vs.110).aspx)并看看他们的行为是否有所不同?不知道是否会,只是一个想法。 – Yushatak

+0

@Yushatak是的,WinForms剪贴板方法使用'尝试几次'循环,而WPF剪贴板方法不使用,只是立即抛出异常。据我所知,没有其他区别。 – Istarnion

+0

看起来像CloseClipboard不需要任何参数,因此可能在处理该异常的地方尝试调用CloseClipboard并重试? – Yushatak

接管剪贴板,我先请OpenClipboardNULL说法。这会从当前拥有它的任何窗口中“窃取”剪贴板。然后我打电话给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; 
    } 
} 

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

+0

我认为他没有将它用作数据存储,而是需要特别的剪贴板支持? – Yushatak

+0

是的,用例是在我的应用程序和excel之间复制/粘贴。 – Istarnion