+1  A: 

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);
Thomas Levesque
The problem I'm having is that any SetData or SetDataObject I perform gives me a COM exception because it failed to open the clipboard. I will try that method but underlying issue is the clipboard seems locked.
gtaborga
This is the exception I get on the first SetData call in that loop: "Cannot SetData on a frozen OLE data object"
gtaborga
Try Clipboard.SetData instead of IDataObject.SetData, then...
Thomas Levesque
Using Clipboard.SetData I received this exception which is the one I get whenever I try to do a Set: OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN))
gtaborga
Try this code, and then copy a large selection in Excel. Oh wait, make sure you save all open documents. Better make a restore point first, in case you trash your system.Use Process Explorer from System Internals to measure the amount of RAM and CPU used by Excel as you do this, and be sure to END PROCESS on both Excel and your app before your system crashes. It will be worth the trip.
Chris Thornton
+3  A: 

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.

Chris Thornton
“Programs should not transfer data into our out of the clipboard without an explicit instruction from the user.” — Charles Petzold, Programming Windows 3.1, Microsoft Press, 1992
Chris Thornton
That would be why the only time I've ever written Clipboard handling code was when implementing Cut, Copy, and Paste in a menu in a .NET application.
R. Bemrose
I never intended to render all of the data being backed up. The amount of data retrieved using the CTRL-C is about the length of a sentence in text. I was hoping for a way to put back the original contents of the clipboard after using the clipboard for my own needs. Is it even possible to restore the clipboard without getting a 'can't open clipboard' error in this scenario?
gtaborga
@gtaborga - you can avoid the "can't open clipboard" by handling the error, sleeping for a brief wait, and re-trying. 3 strikes and you're out, I'd say though. Anyway, I don't get your coment about "The amount of data retrieved using the CTRL-C is about the length of a sentence in text". If you're going to backup the ORIGINAL clipboard contents, then that's what you need to consider for the worst-case memory scenario.
Chris Thornton