如何在C#中备份和恢复系统剪贴板?

gta*_*rga 14 c# backup clipboard restore

我将尽我所能详细解释我正在努力实现的目标.

我正在使用带有IntPtr窗口句柄的C#来从我自己的C#应用​​程序对外部应用程序执行CTRL-C复制操作.我不得不这样做,因为无法使用GET_TEXT直接访问文本.然后我在我的应用程序中使用该副本的文本内容.这里的问题是我现在已经覆盖了剪贴板.

我希望能做的是:

  1. 备份剪贴板的原始内容,该内容可能由我自己以外的任何应用程序设置.
  2. 然后执行复制并将值存储到我的应用程序中.
  3. 然后恢复剪贴板的原始内容,以便用户仍然可以访问他/她的原始剪贴板数据.

这是我到目前为止尝试的代码:

private void GetClipboardText()
{

    text = "";

    IDataObject backupClipboad = Clipboard.GetDataObject();

    KeyboardInput input = new KeyboardInput(this);
    input.Copy(dialogHandle); // Performs a CTRL-C (copy) operation

    IDataObject clipboard = Clipboard.GetDataObject(); 
    if (clipboard.GetDataPresent(DataFormats.Text))
    {
        // Retrieves the text from the clipboard
        text = clipboard.GetData(DataFormats.Text) as string;
    }

    if (backupClipboad != null) 
    {
        Clipboard.SetDataObject(backupClipboad, true); // throws exception
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用System.Windows.Clipboard而不是System.Windows.Forms.Clipboard.原因是当我执行CTRL-C时,System.Windows.Forms中的Clipboard类没有返回任何数据,但系统剪贴板却没有.

我查看了一些低级user32调用,如OpenClipboard,EmptyClipboard和CloseClipboard,希望它们可以帮助我这样做,但到目前为止,我一直在尝试恢复时遇到COM异常.

我想也许这与OpenClipboard参数有关,该参数期望一个想要控制剪贴板的应用程序的IntPtr窗口句柄.由于我提到我的应用程序没有GUI,这是一个挑战.我不知道该在这里传递什么.也许有人可以对此有所了解?

我是否错误地使用了Clipboard类?有没有明确的方法来获取没有GUI的应用程序的IntPtr窗口句柄?有谁知道备份和恢复系统剪贴板的更好方法?

Chr*_*ton 18

尝试这样做是愚蠢的.您无法忠实地将剪贴板恢复到先前的状态.使用"延迟呈现"可能存在数十种未呈现的数据格式,如果您尝试全部呈现它们,则会导致源应用程序耗尽资源.这就像走进餐厅并说"给我一切".

假设用户在Excel中选择了500行x 100列,并将其复制到剪贴板.Excel"宣传"它可以以大约25种不同的格式生成这些数据,包括Bitmap.将其粘贴为位图后,可以强制Excel将其渲染为位图.这是50000个单元格,大约是10,000 x 15,000像素的位图.而且你希望用户在Excel咳嗽时等待,以及其他24种格式?不可行.

此外,您将触发WM_DrawClipboard事件,这将影响其他剪贴板查看器.

放弃.

  • "程序不应该在没有用户明确指示的情况下将数据传输到我们的剪贴板中." - Charles Petzold,编程Windows 3.1,Microsoft Press,1992 (5认同)
  • @ricovox,当剪贴板被 OP 的应用程序覆盖时,“广告”将无效。将句柄恢复为延迟渲染格式将不起作用。真的不会 (2认同)

Tho*_*que 6

您可以将剪贴板的内容保存在字典中,然后将其恢复:

public IDictionary<string, object> GetClipboardData()
{
    var dict = new Dictionary<string, object>();
    var dataObject = Clipboard.GetDataObject();
    foreach(var format in dataObject.GetFormats())
    {
        dict.Add(format, dataObject.GetData(format));
    }
    return dict;
}

public void SetClipboardData(IDictionary<string, object> dict)
{
    var dataObject = Clipboard.GetDataObject();
    foreach(var kvp in dict)
    {
        dataObject.SetData(kvp.Key, kvp.Value);
    }
}

...

var backup = GetClipboardData();
// Do something with the clipboard...
...
SetClipboardData(backup);
Run Code Online (Sandbox Code Playgroud)

  • 尝试此代码,然后在Excel中复制大量选择.哦等等,请确保保存所有打开的文档.如果您丢弃系统,最好先制作一个还原点.使用System Internals中的Process Explorer来测量Excel使用的RAM和CPU的数量,并确保在系统崩溃之前在Excel和您的应用程序上进行END PROCESS.这次旅行值得. (2认同)