2009-05-30 21 views
45

時間の最後の数時間にわたって、別のアプリケーションでクリップボードが開いているために発生するかなりの特定のバグを追跡しています。クリップボード("Why does my shared clipboard not work?"あたりなど)の共有リソースであり、あなたがブロックされたクリップボードとその他の奇妙さを処理する方法

Clipboard.SetText(string) 

または

Clipboard.Clear(). 

を実行しようとして、基本的に次の例外がスローされます。

 
System.Runtime.InteropServices.ExternalException: Requested Clipboard operation did not succeed. 
    at System.Windows.Forms.Clipboard.ThrowIfFailed(Int32 hr) 
    at System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32 retryTimes, Int32 retryDelay) 
    at System.Windows.Forms.Clipboard.SetText(String text, TextDataFormat format) 
    at System.Windows.Forms.Clipboard.SetText(String text) 

私の最初のソリューションでした私はClipboard.SetDataObjectが時間の長さと遅延の長さのフィールドを持っていることに気付くまで、短い一時停止後に再試行するために、.NETのデフォルトの動作は試してみることです100msecの遅延で10回。

エンドユーザーが気づいたことは1つあります。つまり、クリップボードへのコピー操作が実行されても例外がありますが、これがなぜ発生するのかについての詳しい情報は見つかりませんでした。

問題に対する私の現在の解決策は、例外を黙って無視することです...これは本当に最善の方法ですか?

答えて

23

クリップボードはすべてのUIアプリケーションで共有されているため、時折これを実行しますが、クリップボードへの書き込みに失敗した場合はアプリケーションがクラッシュしないようにするため、私は、クリップボードに書き込むためのsetobjectdata呼び出しが失敗した場合、ユーザにプレゼンテーションとエラーを提案します。

user32!GetOpenClipboardWindowを使用して別のアプリケーションでクリップボードが開いているかどうかを確認し、開いているアプリケーションがない場合はIntPtr.ZeroのHWNDを返し、あなたは指定された時間の間IntPtr.Zeroになるまで値を回すことができます。

+0

私はGetOpenClipboardWindowの周りを読んでいますが、これはクリップボードアクセスの問題に最適な解決策だと思われます。お返事をありがとうございます。 –

+0

プロセスを取得してクリップボードをブロックする方法 - http://stackoverflow.com/questions/6583642/determine-which-process-is-locking-the-clipboard – toong

+1

クリップボードを最初に閉じます。私の答えを見てください。 – Triynko

38

古い質問を復活させて申し訳ありませんが、もう1つの回避策はClipboard.SetTextの代わりにClipboard.SetDataObjectを使用することです。retryTimesとはretryDelay - -

this msdn articleによると、この方法は、2つのパラメータがあるあなたは、このように使用できることを:

Clipboard.SetDataObject(
    "some text", //text to store in clipboard 
    false,  //do not keep after our app exits 
    5,   //retry 5 times 
    200);  //200ms delay between retries 
+0

まあまあ良い場所。 –

+0

私が直面している問題は、retryTimesとretryDelay(20/500)の両方が高い数値であっても、Firefoxを開いていてもこれが失敗するということです。とても奇妙です... – aaaidan

+0

良い答え、助けてくれました – apomene

0

これは少し安っぽいです..しかし、それは私の問題を解決しました。

遅延の後にclear()を再試行してください。

詳細情報@thisブログ。

10

今日このエラーが発生しました。私は、ユーザーに不正行為の可能性があるアプリケーションについて伝えることで対応することにしました。そのためには、このような何かを行うことができます。

[System.Runtime.InteropServices.DllImport("user32.dll")] 
static extern IntPtr GetOpenClipboardWindow(); 

[System.Runtime.InteropServices.DllImport("user32.dll")] 
static extern int GetWindowText(int hwnd, StringBuilder text, int count); 

private void btnCopy_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     Clipboard.Clear(); 
     Clipboard.SetText(textBox1.Text); 
    } 
    catch (Exception ex) 
    { 
     string msg = ex.Message; 
     msg += Environment.NewLine; 
     msg += Environment.NewLine; 
     msg += "The problem:"; 
     msg += Environment.NewLine; 
     msg += getOpenClipboardWindowText(); 
     MessageBox.Show(msg); 
    } 
} 

private string getOpenClipboardWindowText() 
{ 
    IntPtr hwnd = GetOpenClipboardWindow(); 
    StringBuilder sb = new StringBuilder(501); 
    GetWindowText(hwnd.ToInt32(), sb, 500); 
    return sb.ToString(); 
    // example: 
    // skype_plugin_core_proxy_window: 02490E80 
} 

は私にとっては、問題のウィンドウタイトルは「skype_plugin_core_proxy_window」でした。私はそれについての情報を探し、それがただ一つのヒットをもたらしたことに驚いた、それはロシア語であった。だから私は、この答えを追加して、その文字列にもう一度ヒットし、潜在的に不正なアプリケーションを起動するためのさらなる助けを提供します。

+0

他の類似した話題で、(共有された)クリップボードに関しては、Skypeのバージョンが非常に悪いと言われました – cacau

-3

私は実際に私自身の解決策を考え出しました。私は少し遅れていることを知っている、しかし、これは私のために働いているようだ。

// This allows the clipboard to have something copied to it. 
    public static void ClipboardPaste(String pasteString) 
    { 
     // This clears the clipboard 
     Clipboard.Clear(); 

     // This is a "Try" of the statement inside {}, if it fails it goes to "Catch" 
     // If it "Catches" an exception. Then the function will retry itself. 
     try 
     { 
      // This, per some suggestions I found is a half second second wait before another 
      // clipboard clear and before setting the clipboard 
      System.Threading.Thread.Sleep(500); 
      Clipboard.Clear(); 
      // This is, instead of using SetText another method to put something into 
      // the clipboard, it includes a retry/fail set up with a delay 
      // It retries 5 times with 250 milliseconds (0.25 second) between each retry. 
      Clipboard.SetDataObject(pasteString, false, 5, 250); 
     } 
     catch (Exception) 
     { 
      ClipboardPaste(pasteString); 
     } 
    } 

これは明らかにC#ですが、これらのメソッドはすべてのVisual Studioに公開されています。私は明らかにループ機能を作成しただけでなく、再試行でクリップボードに強制しようとしました。

本質的にここに流れがあります。この関数が定義されているとすれば、クリップボードにクリップボードという単語を置くことができます。

  1. コール関数ClipboardPaste( "Clipboard");
  2. これでクリップボードが消去されます
  3. 次に、文字列をクリップボードに挿入しようとします。
  4. まずそれが半秒(500ミリ秒)を待つ
  5. 再びクリップボードをクリアし、それはで、5回まで再試行します失敗した場合、それはSetDataObject
  6. SetDataObject
  7. を使用してクリップボードに文字列を入れしようとします各再試行の間に250ミリ秒の遅延があります。
  8. 最初の試行が失敗した場合は、クラッシュが発生したことを受け取り、再び試行します。

はいこれは、クリップボードが何(無限ループ)に関係なく常に例外を持つことがわかっている場合、欠陥があります。しかし、私はまだこの方法で無限ループに陥っていません。もう1つの欠点は、動作する前に数秒(基本的にアプリケーションの速度を落とす)がかかることがあり、アプリケーションをフリーズさせようとしている間に、アプリケーションが成功した後もアプリケーションが続行されるということです。

+3

クリップボードの設定では常に例外が発生する場合、無限ループは発生しませんが、あなたが再帰しているので、スタックオーバーフロー例外。 – dsolimano

1

Clipboard.Clear()を実行する前に、Clipboard.SetDataObject(pasteString, true)のようになります。

retryTimesretryDelayを設定する以前の提案が私のために、デフォルトはretryTimes = 10

+1

Clipboard.Clearはエラーも発生させます。 – Triynko

0

retryDelay = 100msをしているどのような場合には動作しませんでしたただ、最初にこれを呼び出す:

[System.Runtime.InteropServices.DllImport("user32.dll")] 
static extern IntPtr CloseClipboard(); 

私は気づいたあなたが」 TextChangedイベント中を含む、貼り付け操作(WM_PASTEメッセージ)の途中で、クリップボードはイベントを受け取ったウィンドウ(TextBox)によってロックされたままです。したがって、イベントハンドラ内でその "CloseClipboard"メソッドを呼び出すだけであれば、問題や遅延なしに、マネージClipboard.ClearメソッドとClipboard.SetTextメソッドを呼び出すことができます。ジェフ・ローのコードを利用することにより

0

[System.Runtime.InteropServices.DllImport("user32.dll")] 
static extern IntPtr GetOpenClipboardWindow(); 

[System.Runtime.InteropServices.DllImport("user32.dll")] 
static extern int GetWindowText(int hwnd, StringBuilder text, int count); 

private void btnCopy_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     Clipboard.Clear(); 
     Clipboard.SetText(textBox1.Text); 
    } 
    catch (Exception ex) 
    { 
     string msg = ex.Message; 
     msg += Environment.NewLine; 
     msg += Environment.NewLine; 
     msg += "The problem:"; 
     msg += Environment.NewLine; 
     msg += getOpenClipboardWindowText(); 
     MessageBox.Show(msg); 
    } 
} 

private string getOpenClipboardWindowText() 
{ 
    IntPtr hwnd = GetOpenClipboardWindow(); 
    StringBuilder sb = new StringBuilder(501); 
    GetWindowText(hwnd.ToInt32(), sb, 500); 
    return sb.ToString(); 
    // example: 
    // skype_plugin_core_proxy_window: 02490E80 
} 

Jeff's Code

あなたはかなり便利な方法でエラーを処理することができます。

System.Windows.Clipboardの代わりにSystem.Windows.Forms.Clipboardを使用することで、エラーの頻度を減らすことができました。

これは問題を解決するものではありませんが、アプリケーションの発生を減らしていることを強調します。

関連する問題