How do I backup and restore the system clipboard in C#?
I will do my best to explain in detail what I'm trying to achieve.
I'm using C# with IntPtr window handles to perform a CTRL-C copy operation on an external application from my own C# application. I had to do this because there was no way of accessing the text directly using GET_TEXT. I'm then using the text content of that copy within my application. The problem here is that I have now overwritten the clipboard.
What I would like to be able to do is:
- Backup the original contents of the clipboard which could have been set by any application other than my own.
- Then perform the copy and store the value into my application.
- Then restore the original contents of the clipboard so that the user still has access to his/her original clipboard data.
This is the code I have tried so far:
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 clipbo开发者_StackOverflow中文版ard
text = clipboard.GetData(DataFormats.Text) as string;
}
if (backupClipboad != null)
{
Clipboard.SetDataObject(backupClipboad, true); // throws exception
}
}
I am using the System.Windows.Clipboard and not the System.Windows.Forms.Clipboard. The reason for this was that when I performed the CTRL-C, the Clipboard class from System.Windows.Forms did not return any data, but the system clipboard did.
I looked into some of the low level user32 calls like OpenClipboard, EmptyClipboard, and CloseClipboard hoping that they would help my do this but so far I keep getting COM exceptions when trying to restore.
I thought perhaps this had to do with the OpenClipboard parameter which is expecting an IntPtr window handle of the application which wants to take control of the clipboard. Since I mentioned that my application does not have a GUI this is a challenge. I wasn't sure what to pass here. Maybe someone can shed some light on that?
Am I using the Clipboard class incorrectly? Is there a clear way to obtain the IntPtr window handle of an application with no GUI? Does anyone know of a better way to backup and restore the system clipboard?
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.
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);
精彩评论