Странности с доступом к буферу обмена

Я пытаюсь написать небольшое приложение, которое должно использовать буфер обмена для некоторых функций. Поскольку я не хочу перезаписывать данные пользователя, которые в настоящее время находятся в буфере обмена, я решил сохранить их в памяти, выполнить свою работу, а затем записать их обратно. Приведенный ниже код представляет собой консольное приложение, которое является простейшим примером того, что я пытаюсь сделать.

У меня проблема с восстановлением состояния. Если я скопирую что-то в буфер обмена из Visual Studio перед запуском приложения, в буфере обмена будет всего шесть объектов (различные форматы строк и локаль), которые все будут помещены в кеш. Как только я восстанавливаю их, хотя в буфере обмена находится только локаль, и кажется, что каждый вызов SetData() перезаписывает последний. (кстати, SetDataObject не кажется обратным GetDataObject, поэтому я не могу просто использовать это)

Любые идеи, как я могу сохранить состояние буфера обмена и восстановить его позже?

    [STAThread]
    static void Main(string[] args)
    {
        //Store the old clipboard data
        Dictionary<string, object> clipboardCache = new Dictionary<string, object>();

        IDataObject clipboardData = Clipboard.GetDataObject();

        foreach (string format in clipboardData.GetFormats())
        {
            clipboardCache.Add(format, clipboardData.GetData(format));
        }

        Clipboard.SetText("Hello world!");

        string value = Clipboard.GetText();

        Console.WriteLine(value);

        //Clear the clipboard again and restore old data
        Clipboard.Clear();

        foreach (KeyValuePair<string, object> valuePair in clipboardCache)
        {
            Clipboard.SetData(valuePair.Key, valuePair.Value);
            Thread.Sleep(100);
        }

        Console.ReadLine();
    }

person Martin Harris    schedule 03.09.2009    source источник
comment
Используете ли вы какой-либо плагин буфера обмена с несколькими объектами, такой как ClipX?   -  person TheVillageIdiot    schedule 03.09.2009
comment
Фрагмент кода на самом деле решил мою проблему — полностью отличную от вашей — но Google привел меня сюда, поэтому я опубликую подробности здесь: Для тех, у кого возникли проблемы с доступом к буферу обмена Windows из консольного приложения, обязательно украсьте свой метод Main с помощью атрибут [STAThread]! :D   -  person BrainSlugs83    schedule 13.06.2013


Ответы (2)


В буфере обмена Windows одновременно находится только один объект. Но есть несколько доступных форматов (например, RTF, текст, HTML) из одного объекта. Я думаю, вы делаете это слишком сложным, и ваш код должен быть примерно таким:

//Store the old clipboard data
IDataObject clipboardData = Clipboard.GetDataObject();

Clipboard.SetText("Hello world!");

string value = Clipboard.GetText();
Console.WriteLine(value);

//Clear the clipboard again and restore old data
Clipboard.Clear();
Clipboard.SetDataObject(clipboardData);

Console.ReadLine();
person Rosco    schedule 04.09.2009
comment
Как я сказал в своем вопросе, я не думал, что SetDatObject работает, потому что он, похоже, не принимает IDataObject и оставляет буфер обмена пустым, но я ошибался. По умолчанию он сохраняет данные в буфере обмена только до выхода из приложения. Немного почитав, я обнаружил, что ваш код работает, если вы замените SetDataObject(clipboardData) на SetDataObject(clipboardData, true). Спасибо - я думал, это должно быть просто. - person Martin Harris; 04.09.2009

Мартин, я пробовал твой код. В моей системе установлен ClipX. Когда он работает, когда я запускаю ваш код, я получаю столько элементов, сколько есть в кеше ClipX. Но вызов Clipboard.GetDataObject() возвращает только последний объект. Итак, что происходит, когда вы вызываете этот цикл:

foreach (string format in clipboardData.GetFormats())
{
    clipboardCache.Add(format, clipboardData.GetData(format));
}

он возвращает формат для всего объекта в ClipX и преобразует данные, возвращенные

IDataObject clipboardData = Clipboard.GetDataObject();

Так что на самом деле, когда вы выполняете этот цикл

foreach (KeyValuePair<string, object> valuePair in clipboardCache)
{
    Clipboard.SetData(valuePair.Key, valuePair.Value);
    Thread.Sleep(100);
}

у вас есть только один объект, который помещается в буфер обмена.

Во-вторых, при использовании Clipboard.SetData(format,object) перезапись старого объекта новым является нормальным поведением, а не нормальным. Если вы создаете что-то вроде буфера обмена с несколькими записями, вам необходимо перехватывать системные вызовы копирования и вставки и сохранять объект в памяти или на диске вашей программы. Вы не можете полагаться на буфер обмена по умолчанию.

person TheVillageIdiot    schedule 03.09.2009
comment
Спасибо за ответ. Я вообще не использую никаких расширений буфера обмена и хочу сохранить только один элемент, но если вы скопируете текст из Visual Studio (например), в буфере обмена будет храниться несколько элементов - строковое представление текста, версия RTF, локаль - всего в моем clipboardData шесть форматов, и я хочу поместить все шесть объектов обратно в буфер обмена. Можете ли вы попробовать скопировать текст из Visual Studio? Сколько результатов вы получите от clipboardData.GetFormats()? - person Martin Harris; 03.09.2009
comment
Просто добавлю: я также думал, что вы можете хранить только один элемент в буфере обмена, но из-за того, что сегодня вы возитесь с ним, вы можете иметь один элемент на формат. Мне тоже было бы интересно узнать, не прав ли я в этом... - person Martin Harris; 03.09.2009