53

過去数時間にわたって、別のアプリケーションがクリップボードを開いているために発生するかなり具体的なバグを追跡してきました。基本的に、クリップボードは共有リソースであるため ( 「共有クリップボードが機能しないのはなぜですか?」のように)、実行しようとします。

Clipboard.SetText(string)

また

Clipboard.Clear().

次の例外がスローされます。

System.Runtime.InteropServices.ExternalException: 要求されたクリップボード操作は成功しませんでした。
    System.Windows.Forms.Clipboard.ThrowIfFailed (Int32 時間) で
    System.Windows.Forms.Clipboard.SetDataObject (オブジェクト データ、ブール値のコピー、Int32 retryTimes、Int32 retryDelay) で
    System.Windows.Forms.Clipboard.SetText (文字列テキスト、TextDataFormat 形式) で
    System.Windows.Forms.Clipboard.SetText (文字列テキスト) で

私の最初の解決策は、Clipboard.SetDataObject に回数と遅延の長さのフィールドがあることに気付くまで、短い一時停止の後に再試行することでした。.NET のデフォルトの動作は、100 ミリ秒の遅延で 10 回試行することです。

最後に、エンド ユーザーから指摘されたことが 1 つあります。つまり、例外がスローされても、クリップボードへのコピー操作は引き続き機能します。これがなぜなのかについて、これ以上の情報を見つけることができませんでした。

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

4

8 に答える 8

44

別の回避策は、Clipboard.SetDataObjectの代わりに使用することですClipboard.SetText

この MSDN の記事によると、このメソッドにはretryTimesとretryDelayの 2 つのパラメーターがあり、のように使用できます。

System.Windows.Forms.Clipboard.SetDataObject(
    "some text", // Text to store in clipboard
    false,       // Do not keep after our application exits
    5,           // Retry 5 times
    200);        // 200 ms delay between retries
于 2011-03-05T12:32:51.157 に答える
28

クリップボードはすべての UI アプリケーションで共有されるため、ときどきこれに遭遇します。明らかに、クリップボードへの書き込みに失敗した場合にアプリケーションがクラッシュすることは望ましくないため、ExternalException を適切に処理することは合理的です。クリップボードに書き込むための SetObjectData 呼び出しが失敗した場合は、ユーザーにエラーを提示することをお勧めします。

( P/Invokeを介して)user32!GetOpenClipboardWindowを使用して、別のアプリケーションがクリップボードを開いているかどうかを確認することをお勧めします。クリップボードが開いているウィンドウの HWND を返すか、開いIntPtr.Zeroているアプリケーションがない場合に返します。IntPtr.Zero指定された時間になるまで、値をスピンすることができます。

于 2009-05-30T18:11:59.583 に答える
12

今日、このエラーに遭遇しました。私は、アプリケーションが不正に動作している可能性があることをユーザーに伝えることで、この問題を処理することにしました。これを行うには、次のようにします。

[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」でした。それに関する情報を検索したところ、ロシア語で 1 件しかヒットしなかったことに驚きました。そのため、この回答を追加して、その文字列に別のヒットを与え、不正な動作をしている可能性のあるアプリを明らかにするためのさらなる支援を提供します。

于 2011-10-12T22:34:50.803 に答える
4

Clipboard.Clear()前にやるClipboard.SetDataObject(pasteString, true)ことはトリックをするようです。

設定の以前の提案は私にとってはうまくretryTimesいきretryDelayませんでした、そしていずれにせよデフォルトretryTimes = 10retryDelay = 100ms

于 2012-05-25T13:58:06.070 に答える
4

最初にこれを呼び出すだけです:

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

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

于 2012-10-10T19:07:42.723 に答える
3

Jeff Roe のコード ( Jeff's Code )を利用して

[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
}

非常に便利な方法でエラーを処理できます。

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

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

于 2013-07-24T13:03:25.610 に答える
0

これは少しくだらないです...しかし、それは私の問題を解決しました。

しばらくしてから clear() を再試行してください。

詳細については、ブロックされたクリップボードの処理方法 - Clipboard.Clear() エラーというブログ記事を参照してください。

于 2011-08-17T05:47:00.970 に答える
-4

私は実際に私自身の解決策を考え出しました、そしてそれは私のために働いているようです。

// 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#ですが、これらのメソッドはすべてのVisualStudioに公開されています。私は明らかにループ関数を作成し、再試行してクリップボードに強制的に挿入しようとしました。

基本的にここにフローがあります。コード内の任意の場所で、クリップボードという単語をクリップボードに配置するとします(この関数が定義されていると仮定します)。

  1. 関数ClipboardPaste( "Clipboard");を呼び出します。
  2. その後、クリップボードをクリアします
  3. 次に、文字列をクリップボードに入れようとします。
  4. 最初に0.5秒(500ミリ秒)待機します
  5. クリップボードを再度クリアします
  6. 次に、SetDataObjectを使用して文字列をクリップボードに入れようとします
  7. SetDataObjectが失敗すると、最大5回再試行し、各再試行の間に250ミリ秒の遅延が発生します。
  8. 最初の試行が失敗した場合、例外であるクラッシュがキャッチされ、再試行されます。

はい、クリップボードに何があっても常に例外があることがわかっている場合(無限ループ)、これには欠陥があります。ただし、このメソッドではまだ無限ループに遭遇していません。もう1つの欠点は、動作するまでに数秒かかる可能性があることです(基本的にアプリケーションの速度が低下します)。試行している間、アプリケーションがフリーズする可能性があります。成功すると、アプリケーションは続行されます。

于 2012-03-04T21:28:11.877 に答える