Как создать резервную копию и восстановить системный буфер обмена в С#?
Я сделаю все возможное, чтобы подробно объяснить, чего я пытаюсь достичь.
Я использую С# с обработчиками окна 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? Кто-нибудь знает, как лучше создать резервную копию и восстановить системный буфер обмена?
Ответы
Ответ 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);