Windowsのクリップボードフォーマット自動変換
Windowsでクリップボードにデータをコピーした際、いくつかのフォーマットの間で自動変換が行われます。Win32APIのSetClipboardDataでも、COMのOleSetClipboardでコピーしても発生します。
基本的には互換性の維持が目的のようです。
自動変換の対象
以下の3グループに分けられ、どれかがセットされると相互に変換されます。例えば、CF_DIBをクリップボードにセットするとCF_BITMAPとCF_DIBV5でも取り出せるようになります。
- ビットマップ
- CF_BITMAP
- CF_DIB
- CF_DIBV5
- メタファイル
- CF_METAFILEPICT
- CF_ENHMETAFILE
- テキスト
- CF_UNICODE
- CF_TEXT
- CF_OEMTEXT
自動変換の注意
複数のフォーマットに自力で対応する場合
自動変換先にも対応するように自分でクリップボードにセットした場合、自動変換は起きません。あまり意味はなさそうですが、CF_TEXTとCF_UNICODEの両方に対応するようにセットしているようなソフトは現に実在します。
フォーマットが列挙されない
自動変換ではIDataObject::EnumFormatEtc
(EnumClipboardFormats
でも?)では列挙されません。IDataObject::GetDataPresents
(IsClipboardFormatAvailable
でも?)で名指しで確認することで存在を知ることができます。
ビットマップ
CF_BITMAP
GDIのHBITMAP型であり、つまりデバイス依存ビットマップ(DDB: Device Dependent Bitmap)です。CF_PALLETEに値があればCF_BITMAPのカラーパレットが格納されています。
C#からはFromHbitmapメソッドからBitmapを手軽に処理できるため、一番簡単な方式なのかもしれません。
Image.FromHbitmap メソッド (System.Drawing) - Microsoft Docs
CF_DIB/CF_DIBV5
それぞれ、デバイス独立ビットマップ(DIB)の画像データが入っています。それぞれ、BITMAPINFO構造体とBITMAPV5HEADER構造体が入っているはずです。
CF_BITMAPよりも高機能で、アルファチャンネルとかを処理するにはこちらを使う必要があるっぽいです。
現実
CF_PALLETEが使われることは稀なようです。
また、高度な画像をコピーする際にもCF_DIBV5はおすすめしません。”PNG”や”GIF”というフォーマットでその形式のバイナリを入れるか(Officeなどが採用)、CFSTR_INETURLW(Chromeが採用)やCF_HDROP(Firefoxが採用)でファイルやURLを指定するのが一般的です。
メタファイル
Windowsメタファイルも、拡張メタファイルも表現力は大して変わらないようなので、扱いやすい方を使えば良さそうです。
もうSVGでいいじゃんという気がしないでもないですが、Officeでコピーした際にベクタ形式なのは未だにメタファイルだけです。
テキスト
- CF_OEM
- 歴史の残骸。CP_OEMCPで解釈すれば良いです。
- CF_TEXT
- いわゆるANSI形式です。CF_LOCALEにLCID(C#ではSystem.Globalization.CaltureInfoが対応したクラス)が入っています。日本では1041が入っており、これをもとにShift-JISが対応するエンコーディングだと判断できます。CF_TEXTに値をセットした際にもCF_LOCALEの中身(なければ現在の言語設定?)の順に解釈し、CF_UNICODEに変換が行われます。
- CF_UNICODE
- Windowsで言うところのUNICODE、つまりUTF16-LEで格納されています。現状ではこれを使うのが一番無難です。
CF_TEXTの注意点
CF_LOCALEとCF_TEXTの中身が矛盾していると当然のことながら文字化けします。セットする際にはCF_UNICODEを使うほうが間違いが無いかと思います。
厄介なのは一部の多言語対応が甘いソフトでCF_TEXTにUTF-8、CF_LOCALEには1041(Shift-JIS)が指定されていたりすることがあります。なんにしてもクリップボードの中身は自由にセットできるので信用せず、メモリ破壊などを起こさないように気をつけましょう。
もしアプリケーション間のやり取りなどでCF_LOCALEと矛盾したデータを入れたいのであれば、CF_TEXTではない名称で登録するのが妥当かと思います。
まとめ
SetもGetも基本的にはCF_BITMAP、CF_ENHMETAFILE、CF_UNICODEの3つに対応しておくのが妥当に見えます。ブラウザやOfficeを参考にするのが一番現状にあっているかと思います。