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

发布于 2024-08-28 05:58:13 字数 1430 浏览 9 评论 0原文

我将尽力详细解释我想要实现的目标。

我使用 C# 和 IntPtr 窗口句柄从我自己的 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
    }
}

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

我研究了一些低级别的 user32 调用,如 OpenClipboard、EmptyClipboard 和 CloseClipboard,希望它们能帮助我做到这一点,但到目前为止,我在尝试恢复时不断收到 COM 异常。

我认为这可能与 OpenClipboard 参数有关,该参数需要一个想要控制剪贴板的应用程序的 IntPtr 窗口句柄。因为我提到我的应用程序没有 GUI,所以这是一个挑战。我不知道要在这里传递什么。也许有人可以阐明这一点?

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

I will do my best to explain in detail what I'm trying to achieve.

I'm using C# with IntPtr window handles to perform a CTRL-C copy operation on an external application from my own C# application. I had to do this because there was no way of accessing the text directly using GET_TEXT. I'm then using the text content of that copy within my application. The problem here is that I have now overwritten the clipboard.

What I would like to be able to do is:

  1. Backup the original contents of the clipboard which could have been set by any application other than my own.
  2. Then perform the copy and store the value into my application.
  3. Then restore the original contents of the clipboard so that the user still has access to his/her original clipboard data.

This is the code I have tried so far:

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
    }
}

I am using the System.Windows.Clipboard and not the System.Windows.Forms.Clipboard. The reason for this was that when I performed the CTRL-C, the Clipboard class from System.Windows.Forms did not return any data, but the system clipboard did.

I looked into some of the low level user32 calls like OpenClipboard, EmptyClipboard, and CloseClipboard hoping that they would help my do this but so far I keep getting COM exceptions when trying to restore.

I thought perhaps this had to do with the OpenClipboard parameter which is expecting an IntPtr window handle of the application which wants to take control of the clipboard. Since I mentioned that my application does not have a GUI this is a challenge. I wasn't sure what to pass here. Maybe someone can shed some light on that?

Am I using the Clipboard class incorrectly? Is there a clear way to obtain the IntPtr window handle of an application with no GUI? Does anyone know of a better way to backup and restore the system clipboard?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

葬心 2024-09-04 05:58:13

尝试这样做是愚蠢的。您无法将剪贴板忠实地恢复到之前的状态。使用“延迟渲染”可能会出现数十种未渲染的数据格式,如果您尝试渲染所有这些,则会导致源应用程序耗尽资源。这就像走进一家餐馆并说“什么都给我一份”。

假设用户在 Excel 中选择了 500 行 x 100 列,并将其复制到剪贴板。 Excel“宣传”它可以生成大约 25 种不同格式的数据,包括位图。将其粘贴为位图后,您将强制 Excel 将其呈现为位图。那是 50000 个单元,并且将是一个大约 10,000 x 15,000 像素的位图。您是否希望用户在 Excel 吐出这个问题以及其他 24 种格式时等待?不可行。

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

放弃。

It's folly to try to do this. You cannot faithfully restore the clipboard to its prior state. There could be dozens of unrendered data formats present using "delayed rendering", and if you attempt to render them all, you'll cause the source app to run out of resources. It's like walking into a resturaunt and saying "give me one of everything".

Suppose that the user has selected 500 rows x 100 columns in Excel, and has copied that to the clipboard. Excel "advertises" that it can produce this data in about 25 different formats, including Bitmap. Once you paste it as a Bitmap, you force Excel to render it as a bitmap. That's 50000 cells, and would be a bitmap approx 10,000 x 15,000 pixels. And you expect the user to wait around while Excel coughs that up, along with 24 other formats? Not feasible.

Furthermore, you're going to be triggering WM_DrawClipboard events, which will impact other clipboard viewers.

Give up.

千仐 2024-09-04 05:58:13

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

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);

You could save the content of the clipboard in a dictionary, and restore it afterwards :

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文