使用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
。我会试着去尝试一下。
接管剪贴板,我先请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;
}
}
你有没有使用的WinForms剪贴板类测试(https://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard(v=vs.110).aspx)并看看他们的行为是否有所不同?不知道是否会,只是一个想法。 – Yushatak
@Yushatak是的,WinForms剪贴板方法使用'尝试几次'循环,而WPF剪贴板方法不使用,只是立即抛出异常。据我所知,没有其他区别。 – Istarnion
看起来像CloseClipboard不需要任何参数,因此可能在处理该异常的地方尝试调用CloseClipboard并重试? – Yushatak