クリップボード内のデータが変更されたときにそれを知る方法はないのでしょうか? もし知ることができればネットから効率よく情報を得ることができます。コピーしてペーストしなくてもコピーするだけで自動的にデータを保存することも可能になります。

C#でClipboard監視(Windows API) – Qiitaをみるとやり方が紹介されています。また原理的なことはビューアチェインをみるとわかりやすいです。

ではさっそくこれらを参考に作成してみましょう。

SetClipboardViewer() 関数

クリップボードに変更があるとビューアにWM_DRAWCLIPBOARD メッセージが通知されます。アプリを通知の対象にするためには手続きが必要です。それがSetClipboardViewer() 関数です。

Windows は1つのビューアにしかメッセージを通知しません。しかしビューアはひとつとは限りません。他のビューアに対してはどのように通知がおこなわれるのでしょうか?

SetClipboardViewer() 関数を実行するとビューアの次に登録されているビューアのハンドルを返します。SetClipboardViewer() が返したウィンドウにWM_DRAWCLIPBOARD メッセージを送信することで鎖にようにビューアプログラムがメッセージを流します。この構造をクリップボードビューアチェインと呼びます。

SetClipboardViewer() 関数を実行するということはクリップボードビューアチェインを意識しなければなりません。

ChangeClipboardChain() 関数

ビューアは、クリップボードビューアチェインから自分自身を削除することができます。終了するときや必要がなくなったときはChangeClipboardChain()でチェインから自分自身を削除してしまいましょう。

この関数には引数がふたつあります。ひとつめはチェインから削除したいウィンドウのハンドル、二つ目の引数は自分の次のチェインのハンドルを指定します。

ChangeClipboardChain()関数が呼ばれるとOSはチェインの最上のウィンドウにWM_CHANGECBCHAIN メッセージを送信します。

WM_CHANGECBCHAIN メッセージのサブメッセージはWPARAM にはチェインから外れるウィンドウのハンドルが、LPARAM には WPARAM のウィンドウ(チェインから外れるウィンドウ)の次のウィンドウのハンドルが格納されています。このメッセージをうまく処理しないとクリップボードビューアチェインがおかしくなります。

WM_CHANGECBCHAIN メッセージが送られてきたら、WPARAMの値を調べます。これが次のウィンドウのハンドルと同じであれば次のウィンドウはクリップボードビューアチェインから外れたことになります。そこで今後はLPARAM のハンドルに対してメッセージを送らなければなりません。

WPARAM が次のウィンドウでなければ、そのまま自分の次のウィンドウにWM_CHANGECBCHAIN メッセージを送るだけでOKです。

NativeWindow クラスを使ってみる

C#でClipboard監視(Windows API) – Qiitaでは、NativeWindow クラスを利用しています。

そのままサンプルプログラムをコピペするのでは面白くないのでちょっと変化をつけてみます。

ライブラリにすることで

あとはListener_DrawClipboardのなかでやりたいことをやります。

一例として・・・

クリップボードがイメージの場合、urlの場合は画像をファイルとして保存します。

GetFileName(int i)は保存用のファイル名をつくるメソッドです。またSaveFileFromUrl(string filePath, string url)はurlからjpgファイルを保存するためのメソッドです。

urlが本当にjpg画像なのか確認しないといけないのですが、省略しています。

もっと簡単な驚愕の方法

文章を書いてから調べてみるともっと簡単な方法がありました。

Vista以降はAddClipboardFormatListener関数をつかったほうがよいです。チェイン管理をOSがやってくれます。WindowメッセージWM_DRAWCLIPBOARDとWM_CHANGECBCHAINを処理してチェインの維持をする必要はないようです。