Подтвердить что ты не робот

Как создать резервную копию и восстановить системный буфер обмена в С#?

Я сделаю все возможное, чтобы подробно объяснить, чего я пытаюсь достичь.

Я использую С# с обработчиками окна IntPtr для выполнения операции копирования CTRL-C во внешнем приложении из моего собственного приложения С#. Я должен был сделать это, потому что не было никакого способа получить доступ к тексту напрямую, используя GET_TEXT. Затем я использую текстовое содержимое этой копии в своем приложении. Проблема здесь в том, что теперь я перезаписал буфер обмена.

Я хотел бы иметь возможность:

  • Резервное копирование исходного содержимого буфера обмена, которое могло быть установлено любым другим приложением, отличным от моего.
  • Затем выполните копию и сохраните это значение в моем приложении.
  • Затем восстановите исходное содержимое буфера обмена, чтобы пользователь по-прежнему имел доступ к своим исходным данным буфера обмена.

Это код, который я пробовал до сих пор:

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, класс Clipboard из System.Windows.Forms не возвращал никаких данных, но сделал системный буфер обмена.

Я просмотрел некоторые низкоуровневые вызовы user32, такие как OpenClipboard, EmptyClipboard и CloseClipboard, надеясь, что они помогут мне это сделать, но до сих пор я продолжаю получать исключения COM при попытке восстановить.

Я подумал, что, возможно, это связано с параметром OpenClipboard, который ожидает дескриптор окна IntPtr приложения, который хочет взять управление буфером обмена. Поскольку я упоминал, что мое приложение не имеет графического интерфейса, это вызов. Я не был уверен, что мне нужно здесь пройти. Может быть, кто-то может пролить свет на это?

Я неправильно использую класс Clipboard? Есть ли четкий способ получить дескриптор окна IntPtr приложения без GUI? Кто-нибудь знает, как лучше создать резервную копию и восстановить системный буфер обмена?

4b9b3361

Ответ 1

Безумно пытаться это сделать. Вы не можете точно восстановить буфер обмена до его предыдущего состояния. Там могут быть десятки нераспределенных форматов данных, которые присутствуют с использованием "отложенного рендеринга", и если вы попытаетесь отобразить их все, это приведет к тому, что исходное приложение закончится из ресурсов. Это, как ходьба в resturaunt и говорящий "дайте мне одно из всего".

Предположим, что пользователь выбрал 500 строк по 100 столбцов в Excel и скопировал их в буфер обмена. Excel "рекламирует", что он может создавать эти данные примерно в 25 разных форматах, включая Bitmap. После того, как вы вставляете его в виде растрового изображения, вы вынуждаете Excel отображать его как растровое изображение. Это 50000 ячеек и будет растровым примерно 10 000 x 15 000 пикселей. И вы ожидаете, что пользователь будет ждать, пока Excel кашляет, вместе с 24 другими форматами? Невозможно.

Кроме того, вы будете запускать события WM_DrawClipboard, которые будут влиять на других зрителей буфера обмена.

Откажитесь.

Ответ 2

Вы можете сохранить содержимое буфера обмена в словаре и восстановить его впоследствии:

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