Clipboardで起きる例外だけは握りつぶしていい理由

こんにちは、働くC#プログラマーのさんさめです。

この記事を呼んでいるあなたは、
「OpenClipboard に失敗しました」という
例外の対処に困っているのではないでしょうか。

この例外は、
起きない人の元では全く起きないのに、
なぜかある人のところでは頻発して、
アプリケーションを落としてくる
とても厄介な例外です。

ところがこの例外、
実は「握りつぶして良い」のです。

私は仕事数年C#を使って
アプリケーション開発をしていますが、
Clipboard例外を握りつぶしているために
困ったことは一切ありません

本記事では、
なぜClipboard例外を握りつぶして良いかの解説と、
効率的に握りつぶすための方法について
紹介します。

スポンサーリンク

「OpenClipboard に失敗しました」はいつ起きるのか

そもそもこの
「OpenClipboard に失敗しました」の
例外はなぜ起きるのでしょうか。

これは、コピーや貼り付けなどを実装しようとして
クリップボードを使おうとしている
複数のアプリケーションが
同時にクリップボードにアクセス
してしまったときに発生します。

フリーソフトなどでクリップボードの履歴を
監視するようなツール
を使用している環境の場合、
発生頻度が非常に高まります。

このようなソフトは、
クリップボードの内容を周期的に
確認しています。

そのために、
他のアプリケーションによる
クリップボードのアクセスと
かち合いやすいのです。

また、逆に自身のアプリケーションが
クリップボードの内容を監視している場合も
同様のことが言えます。

なぜ握りつぶしても良いのか

例外の発生する原因は分かったとして、
なぜ例外を握りつぶしても良いのか
について掘り下げましょう。

3つの理由があります

  • 単にアクセスに失敗したのを例外で報告してるだけ
  • 本当はアクセスできていることもある
  • 本当にダメな場合でもユーザーに気づかれにくい

単にアクセスに失敗したのを例外で報告してるだけ

一番の根拠はこれです。

例外といっても、
使い方が間違ってるだとか、
これ以上動作保証が取れないといったような
「アプリケーションに致命的な欠陥」が
あるわけではないのです。

「たまたま今回ダメだった」だけです。
catchするのも重いので、
正直言って成否をboolで返してほしいくらいです。

本当はアクセスできていることもある

Clipboard.SetTextのように、
何らかの文字をクリップボードにコピーしたい
だけの処理だった場合、
なんなら例外を吐いていても
ちゃんとコピーできている
ことがあります。

なかなかやんちゃな実装ですね。

本当にダメな場合でもユーザーに気づかれにくい

例外を握りつぶして、
かつ本当にコピーできてなかったパターンでも、
ユーザーは単にうまくボタンが押せなかっただけと
誤認してくれる可能性が高いです。

コピー処理は大抵Ctrl+Cにキーバインド
していることでしょう。

その場合、例外が起きて握りつぶしたとしても、
ユーザーは
「あ、Ctrlキー押せてなかったのかな」
くらいにしか思いません。

そして、いくら他にクリップボード監視ツールが
起動していたとしても、
そう立て続けに何度も起きるものではないのです。

つまり、大抵はもう一度試せば成功します。

よって、本当に失敗した場合でも、
ユーザー体験が極端に悪くなる
ようなことはありません

DispatcherUnhandledExceptionイベントで握りつぶすと楽

以上がClipboard例外を
握りつぶして良い理由です。

最後に、
楽に握りつぶす方法を紹介して締めたいと思います。

WPFアプリケーションの場合、
DispatcherUnhandledException
握りつぶしてしまうのが楽です。

コード例は以下のようになります。

// 以下をできるだけエントリポイントに近いところで呼ぶ想定
// Application.Current.DispatcherUnhandledException += OnDispatcherUnhandledException;

private void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    // Clipboardの例外は握りつぶす
    if (e.Exception is COMException com
        && com.ErrorCode == -2147221040) // 0x800401D0
    {
        e.Handled = true;
    }
}

trycatch構文ですと、
Clipboardを使っている全ての個所で
同じことを書かないといけないので、
囲い忘れが発生しえます。

その点、UIスレッドの未処理例外が確実に通る
DispatcherUnhandledException
あれば握りつぶすことが容易です。

ただし、元々の処理は最後まで回らないので、

コピーではなく、ペースト…
つまりClipboard.GetTextした結果を使って
何らかの処理を行う関数では
きちんとtrycatchした方が無難ですね。

まとめ

まとめです。

  • 「OpenClipboardに失敗しました」は
    実害がないくせにすぐアプリケーションを
    異常終了させる困った例外
  • 握りつぶすのが一番確実な対処法
  • WPFならDispatcherUnhandledExceptionで
    まとめて握りつぶすと楽

最後までお読みいただき、ありがとうございました。

コメント

タイトルとURLをコピーしました