2009-12-07 33 views
13

我使用下面的代碼將文本複製到剪貼板:我該如何解決「無法打開剪貼板:拒絕訪問」錯誤?

Clipboard.Open; 
    try 
    Clipboard.AsText := GenerateClipboardText; 
    finally 
    Clipboard.Close; 
    end; 

看似隨意,我得到「無法打開剪貼板:拒絕訪問」錯誤。我猜這些錯誤是由其他應用程序鎖定剪貼板引起的,但我似乎沒有對其他應用程序造成任何鎖定。

奇怪的是我的用戶似乎更彙報與Vista和Windows 7比XP中的錯誤。

有沒有一種方法來檢查,如果剪貼板正試圖訪問它之前鎖定?

+0

請注意,從德爾福的文檔這個片段:「Clipboard.Open - >打開剪貼板,防止其他應用程序,直到剪貼板關閉改變其內容添加一系列的項目到剪貼板之前調用open這可以防止其他應用程序從覆蓋剪貼板直到它被關閉(當向剪貼板添加單個項目時,不需要調用Open)。「 – Ampere 2013-12-16 16:41:32

回答

16

這不是Delphi問題。因爲剪貼板可以在任何時候被鎖定,即使您檢查,剪貼板當前未鎖定,它可能會在檢查後直接鎖定。

你這裏有兩種可能性:

  1. 不要使用德爾福剪貼板類。相反,使用原始API函數,您可以更細緻地控制可能的錯誤情況。
  2. 通過添加異常處理程序,期望您的代碼失敗。然後添加一些重試代碼,即在投擲自己的錯誤之前重試將文本設置三次,或許使用指數回退。

我推薦第二種解決方案,因爲它會是更類似Delphi的方法,最終會產生更簡潔的代碼。

while not Success do 
try 
    //Set the clipboard 
    Success := True; 
except 
    on Exception do 
    begin 
    Inc(RetryCount); 
    if RetryCount < 3 then 
     Sleep(RetryCount * 100) 
    else 
     raise MyException.Create('Cannot set clipboard'); 
    end; 
end; 
+3

這也不是Win32問題 - 編程併發系統時,這是一個簡單的事實。 – mghie 2009-12-07 11:11:28

1

有沒有辦法來檢查的東西,然後根據結果做其他的事情,並期望它不能失敗,因爲除非檢查和動作是一個原子操作總是有可能另一個進程或線程並行執行相同的操作。

這個擁有你是否嘗試打開剪貼板,打開一個文件,創建或刪除一個目錄 - 你應該簡單地嘗試去做,也許幾次在一個循環中,並妥善處理錯誤。

0

嘗試查看GetClipboardOwner,如果它不爲空,而不是你的Application.Handle,你不能打開修改它的內容。
即使這似乎很好去,它可能不再是當你真的這樣做。
所以在循環中添加一個try,直到你得到它或放棄很好(例如通知用戶)。

1

首先請注意,這可能不是您的應用程序中的問題。其他應用程序鎖定了剪貼板或弄亂了通知鏈,現在你的應用程序無法訪問它。當我遇到像這樣的問題時,我重新啓動計算機,然後他們神奇地離開了......好吧......至少在我再次運行導致問題的應用程序之前。

此代碼(在Delphi中不選中)可以幫助你。它不會解決問題是通知鏈被破壞(除了PC重新啓動以外,沒有其他任何修復方法),但是如果應用程序鎖定剪貼板一段時間,它將解決問題。增加MaxRetries如果那個討厭的應用程序保持剪貼板鎖定很長一段時間(秒):

procedure Str2Clipboard(CONST Str: string; iDelayMs: integer); 
CONST 
    MaxRetries= 5; 
VAR RetryCount: Integer; 
begin 
RetryCount:= 0; 
for RetryCount:= 1 to MaxRetries DO 
    TRY 
    inc(RetryCount); 
    Clipboard.AsText:= Str; 
    Break; 
    EXCEPT 
    on Exception DO 
     if RetryCount = MaxRetries 
     then RAISE Exception.Create('Cannot set clipboard') 
     else Sleep(iDelayMs) 
    END; 
end; 

而且,它可能是一個好主意,放棄了「加薪」,並將其轉換爲一個函數,並用它像這樣:

if not Str2Clipboard 
then Log.AddMsg('Dear user, other applications are blocking the clipboard. We have tried. We really did. But it didn''t work. Try again in a few seconds.'); 
+0

你的睡眠不夠長。 15毫秒不會做任何事情。 5x15ms之後,無論打開剪貼板是否還有它。 – 2011-01-10 18:08:39

+0

您可能是對的,但另一方面,如果您使用很長的延遲,則可能會因爲剪貼板正在使用而導致應用程序掛起幾秒鐘。大概每個程序員都應該決定多少「凍結」是可以接受的。 – Ampere 2011-01-12 15:58:39

+0

甚至更​​好:延遲甚至可以用作過程的參數。 ---我只是更新了代碼。 – Ampere 2011-01-12 16:00:37

8

奇怪的是我的用戶似乎 與報告更加錯誤的 Vista和Windows 7比XP

這可能與Vista/Win7如何處理剪貼板查看器通知有關。雖然他們仍然支持XP的「剪貼板查看器鏈」,它發送一個通知消息,必須依次重新發送給每個偵聽器(如果一個應用程序未能這樣做,其他應用程序不會通知)。從Vista開始,應用程序會直接通知。而且沒有什麼可以阻止他們一次嘗試訪問剪貼板。

比喻:我有3個孩子。我有一個蛋糕。通過XP規則,我告訴最大的孩子吃點蛋糕,然後告訴下一個最大的孩子吃一片。她得到她的切片,告訴她的兄弟,他得到了他的,並告訴他的兄弟,誰得到了他的,並且一切都按照有序的方式進行。
問題:中間的孩子把蛋糕帶到他的房間,不告訴最年輕的孩子,而最小的孩子錯過了。

在Vista/Windows 7中,該系統仍然存在。但是一旦蛋糕到達廚房,新的應用程序可以立即請求通知我。我大喊「蛋糕準備好了!」他們都在同一時間出現,並試圖抓住一些。但是隻有一把刀,所以他們不得不繼續拿刀,沒有拿到刀,並等待下一個機會。

0

我猜你是在Win 8或更高版本上運行你的應用程序。

只需在您的應用程序的.exe文件上右鍵單擊,去兼容性選項卡並更改兼容模式在Windows XP或更低版本。它會工作,保證!

相關問題