2010-04-05 123 views
13

我會盡我所能詳細解釋我想要達到的目標。如何在C#中備份和恢復系統剪貼板?

我正在使用C#與IntPtr窗口句柄來執行從我自己的C#應用​​程序的外部應用程序的CTRL-C複製操作。我必須這樣做,因爲沒有辦法直接使用GET_TEXT訪問文本。然後我在應用程序中使用該副本的文本內容。這裏的問題是我現在覆蓋了剪貼板。

我想做些什麼可以做的是:

  1. 備份本來可以通過設置比我自己以外的任何應用程序剪貼板的原始內容。
  2. 然後執行復制並將值存儲到我的應用程序中。
  3. 然後恢復剪貼板的原始內容,以便用戶仍可訪問其原始剪貼板數據。

這是迄今爲止我已經試過代碼:

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時,System.Windows.Forms中的Clipboard類沒有返回任何數據,但系統剪貼板沒有。

我看了一些像OpenClipboard,EmptyClipboard和CloseClipboard的低級別的user32調用,希望他們會幫助我做到這一點,但到目前爲止,我仍然在嘗試恢復時收到COM異常。

我想也許這與OpenClipboard參數有關,該參數需要應用程序的IntPtr窗口句柄來控制剪貼板。由於我提到我的應用程序沒有GUI,這是一個挑戰。我不知道該通過什麼。也許有人可以對此有所瞭解?

我是否正確使用剪貼板類?有沒有一種清晰的方式來獲得沒有GUI的應用程序的IntPtr窗口句柄?有誰知道備份和恢復系統剪貼板的更好方法嗎?

+0

我遇到了同樣的錯誤,發現這個職位。但是,只有在調用Clipboard.GetDataObject()。SetData(myData)時纔會出現此錯誤。如果我調用Clipboard.SetDataObject(myData),它工作正常。任何解釋爲什麼?如果它很重要,我的應用程序是基於WPF的。 – newman 2013-06-19 20:25:35

回答

6

你可以保存到剪貼板的字典的內容,並隨後將其還原:

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); 
+0

我遇到的問題是我執行的任何SetData或SetDataObject都會給我一個COM異常,因爲它無法打開剪貼板。我會嘗試這種方法,但潛在的問題是剪貼板似乎被鎖定。 – gtaborga 2010-04-05 14:55:54

+1

這是我在該循環中的第一個SetData調用得到的異常:「不能在凍結的OLE數據對象上設置數據」 – gtaborga 2010-04-05 15:10:23

+0

嘗試使用Clipboard.SetData而不是IDataObject.SetData,然後... – 2010-04-05 15:27:25

17

它的愚蠢,試圖做到這一點。您無法忠實地將剪貼板恢復到之前的狀態。使用「延遲呈現」可能會出現數十種未呈現的數據格式,如果您嘗試全部呈現它們,則會導致源應用程序耗盡資源。這就像走進一家餐廳,並說「給我一切」。

假設用戶在Excel中選擇了500行x 100列,並將其複製到剪貼板。 Excel「宣傳」它可以以大約25種不同的格式生成這些數據,包括位圖。將其作爲位圖粘貼後,即可強制Excel將其呈現爲位圖。這是50000個單元格,並且是一個大約10,000 x 15,000像素的位圖。你希望用戶等待,而Excel會與其他24種格式一起咳嗽嗎?不可行。

此外,您將觸發WM_DrawClipboard事件,這會影響其他剪貼板查看器。

放棄。

+5

」程序不應該在沒有來自用戶的明確指令的情況下將數據傳輸到我們的剪貼板中。「 - Charles Petzold,Programming Windows 3.1,Microsoft Press,1992 – 2010-04-05 17:28:06

+0

這就是爲什麼我唯一一次寫剪貼板處理代碼是在.NET應用程序的菜單中實現剪切,複製和粘貼時。 – Powerlord 2010-04-05 17:33:40

+0

我從來沒有打算渲染所有正在備份的數據。使用CTRL-C檢索的數據量大約是文本中句子的長度。我希望能夠根據自己的需要使用剪貼板後,將剪貼板的原始內容放回原處。甚至有可能在這種情況下恢復剪貼板而不會發生'無法打開剪貼板'錯誤? – gtaborga 2010-04-06 05:10:24