tags:

views:

365

answers:

2

I'm trying to write a small application that needs to use the clipboard for some functionality. Since I don't want to overwrite the user's data currently in the clipboard I decided to save it to memory, do my job and then write it back. The code below is a console application that is a barebones example of what I'm trying to do.

The problem I'm having is restoring the state. If I copy something to the clipboard from Visual Studio before running the application there are a total of six objects in the clipboard (various string formats and a locale) which all get put in the cache. Once I restore them though only the locale is in the clipboard and it appears each call to SetData() overwrites the last. (by the way SetDataObject doesn't seem to be the inverse of GetDataObject so I can't just use that)

Any ideas how I can store clipboard state and restore it later?

    [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();
    }
+1  A: 

Martin I've tried your code. I have ClipX installed on my system. With it running when I run your code I get as many items as there in ClipX's cache. But the call Clipboard.GetDataObject() returns only the latest object. So what happens is that when you call this loop:

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

it returns the format for all the object in the ClipX and convert the data returned by

IDataObject clipboardData = Clipboard.GetDataObject();

So actually when you are executing this loop

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

you have only one object which is being set to clipboard.

Secondly when using Clipboard.SetData(format,object) overwriting older object with new one is normal behaviour not the normal one. If you are building multiple entry clipboard sort of thing then you need to intercept copy and paste system calls and keep the object in your program's memory or disk. You cannot rely on default clipboard.

TheVillageIdiot
Thanks for the response. I'm not using any clipboard extensions at all and I'm only looking to save one item, but if you copy text from Visual Studio (for example) there will be multiple items stored in the clipboard - a string representation of the text, an RTF version, the locale - in total my clipboardData has six formats in it, and I want to put all six objects back into the clipboard. Can you try copying text from Visual Studio? How many results do you get from clipboardData.GetFormats() then?
Martin Harris
Just to add - I also thought that you could only store one item in the clipboard, but it from messing around with it today that you can have one item *per* format. I'd also be interested to know if I'm not right about this...
Martin Harris
+1  A: 

The windows clipboard only has one object in it at a time. But there are multiple formats available (e.g. RTF, Text, HTML) from that one object. I think you are making it too complicated and your code should be something like this:

//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();
Rosco
As I said in my question I didn't think that SetDatObject was working because it didn't seem to accept an IDataObject and left the clipboard empty, but I was wrong. By default it only keeps the data in the clipboard until the application exits. After reading round a little I found that your code works in you replace SetDataObject(clipboardData) with SetDataObject(clipboardData, true). Thanks - I thought is should be simple.
Martin Harris