文字コードが違う場合のテキストクリップボード対応

2012/10/04
[ 確認事項 ]
此処の話は Windows のプログラムチップですから 一般的な文字コード体系の話では無く ウィンドウズ内部の話だと 認識しておいて下さい。
日本語 ウィンドウズ内部 でやりとりして扱っている文字コードは クリップボードフォーマット CF_TEXT で表される MultiByte 文字 Shift-JIS ( MS932 ) と CF_UNICODETEXT で表される WideChar 文字 Unicode ( UTC-16 ) だけです。他の文字コードは外部でのフォーマットの話だと言う事を確認しておいて下さい。従って 此処で Unicode ( ウィンドウズの API の解説文書でも wide-character (Unicode) と言っているので ) と言えば CTF-16 の事だと思っていただけると誤解が少なくなると思います。

[ 2012 / 06 / 30 ]
此処の所 HTML 編集の機会が多く 色々な HTML を書いていると色々な文字コードを扱う事が多くなってきました。 此の ソフトの小物たち は結構古くから有るので Shift JIS で書いていて 此処にある ソフトも全てが ユニコードでない Windows 標準の Shift JIS ( 厳密には MS932 と言うのだそうですが ) で内部動作を させています。
此は此で 全く問題は無く Windows API も Shift JIS or UNICODE 両方のサポートをしています。従って こと Windows 相手にして テキストをもらったり セットしたりしている分には Shift JIS 一本で何の問題も無かったし これからも Windows が此の形をサポートする限り問題は無いはずです。
 ちょっと前までは ( 何年前かは ??? ) 殆どの Windows 関係のテキスト関係の文字コードは Shift JIS 以外は 考えられなかったのですが 最近は ( 此も 何年前からは ??? ) 色々な OS の関係やら 大きいのは Web ページの 標準の 文字コードが 変わって来た事によって ユニコード以外の文字コードが多様化してきました。
 今更プログラムをしている人には言うまでも無い事ですが Windows のテキストクリップボードの様式は CF_TEXT と CF_UNICODETEXT 両形式が有ります。確かめて見れば解りますが テキストクリップボード に入れる時に CF_TEXT だけ入れれば CF_UNICODETEXT にも入るし CF_UNICODETEXT に入れれば CF_TEXT にも自動的に と言うか適当に入れてきます。( CF_ENHMETAFILE と CF_METAFILEPICT の関係に似ています。)
この時 相互に自動変換して入れてくる文字コードは Shift JIS ←→UNICODE になります。従って 例えば UTF-8 で CF_TEXT だけに入れれば CF_UNICODETEXT にも入りますが Shift JIS だとして変換しますから文字化けします。
 此処まで書いてそれではプログラム的にどういう対応をすれば良いかと言う事になりますが 単純な話ですが 内部的に Shift JIS しか扱わないプログラムが テキストクリップボードに代入する時には 単純に CF_TEXT だけに 入れれば良いと言う事になります。此だけなら話は終わりです。
 それでは 内部的に Shift JIS を使用している プログラムが テキストクリップボード からテキストをもらう時は どうでしょうか。Shift JIS だけなら CF_TEXT を取得してそれを利用すれば良いのですが 現在の所 CF_TEXT は どのコードで入っているか確認は出来ません。テキストクリップボードにテキストを入れたプログラムが CF_TEXT だけでなく CF_UNICODETEXT も入れてくれていれば 此は特に問題は有りません。Shift JIS データが必要なら CF_UNICODETEXT データを Shift JIS に変換すれば良いからです。Windows には 此の API WideCharToMultiByte が 有るので此で変換してもらえば問題は有りません。
 結論的には テキストクリップボードに代入する時に 保持データが Shift JIS なら CF_TEXT だけに入れておけば 特に問題は無し。テキストクリップボードテキストを取得する時には クリップボードテキストに代入したソフトの お行儀を信じて CF_UNICODETEXT を取得して それを WideCharToMultiByte で Shift JIS に変換した方が CF_TEXT で Shift JIS だとの前提で取得するより間違えが少ない。( 此も テキストクリップボードに代入する時にどういう コードをどういうふうに代入したかによると思います。 )
 それでは お行儀が悪いプログラムが Shift JIS でないコードなのに CF_UNICODETEXT に入れなかった時とか 不幸にして なぜか自分が保持しているテキストデータがコード体系がはっきりしない時はどうしたら良いの でしょうか。此については あのプログラムの固まりの様なインターネットブラウザも文字化けを起こして外す事が 有る文字コード種の認識の問題にも関わってきますのでどうしようか と言う良い考えは現在浮かびません。
此のコード種認識については続編を書くのが妥当だと思いますので 今回は此処までに留めて 当面は テキストクリップボード を取得するのも CF_TEXT で Shift JIS 決め打ちで取得するより 確実に Shift JIS に 確定できる方法が良さそうだという事で ソフトの対応もそれなりに改善しなくてはならなそうだと言う所で 本日は終わりたいと思います。

[ 2012 / 09 / 23 ]
文字コードが違う場合のテキストクリップボード対応 の続編です。
前回 の懸案事項であった なぜか自分が保持しているテキストデータがコード体系がはっきりしない時の対応に ついてですが 一番確かなのは保持している データを 筋の通ったテキストエディター等に貼り付けて結果を 見るのが一番簡単な事ですが 此では プログラム的に意味が有りません。此の保持している データを直に テキストクリップボードに代入する時にはどうしたら良いのでしょうか。
現在 ウィンドウズで使用されていて 良く使用されていて 出現頻度も高い コード体系の中では Shift JIS ( CP932 ) / Unicode ( UTF-16 ) / UTF-8 で事足りるのではないかと思います。 UTF-8 は html css js とかの インターネット関連のファイルに多くなって来ている様です。
現在保持しているテキスト関連データが 此の 3 種のどれに当たるかを判別する方法ですが 色々難しいやり方が 有るようです。実際にインターネットを調べて 判断コードも書いてみたのですが 割と大きく重い物になって しまいました。
そこで出来るだけ簡単に実用的にと言う事で考えた結果まず UTF-16 かどうか判断する。UTF-16 のBOM が付いて いれば簡単なのですが付いていなくても UTF-16 の ASCII コードの並びは 0 A 0 B 0 1 0 2 or A 0 B 0 1 0 2 0 等ですから保持しているデータの最後の ゼロまで探して途中に 0 が出現して此の前後どちらかが ASCII コードなら すれば UTF-16 と言う事で良いと考えられます。( 全く ASCII 文字の無い場合は 取り違えそうですが そういうデータは殆ど無いと言う前提で考えています。)
UTF-16 が外れたら 後は UTF-8 or ANSI ( S-JIS ) と言う事になりますが UTF-8 に BOM が付いていれば判断は 簡単ですが 殆ど付いていないし 付いている事を期待してプログラム判断をする訳にもいきません。( BOM が 付加されている可能性が有る事へのプログラムの対応は必要だとは思いますが。)
Windows API で MultiByteToWideChar と言うのが有って MultiByte コードを Unicode UTF-16 にしてくれる 割と良く使用する API が有ります。此を
MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS,
MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS,
のかたちで使用すると If the function encounters an invalid input character, it fails と有る様に 変換出来ないキャラクターが有ると 0 が帰ります。
UTF-8 or ANSI は ASCII 文字だけなら全くの互換ですが 漢字( MultiByte ) になると 並びが違って きますから MultiByteToWideChar( , MB_ERR_INVALID_CHARS でどちらかで 出来てどちらかが出来なければ UTF-8 or ANSI の区別は付く事になり 又 最終的な変換は 此の MultiByteToWideChar のお世話になりますから する事も単純になります。
区別が付けば MultiByteToWideChar で UTF-16 にして利用するのも良し ANSI ならそのまま Windows API で 直に 使用するのも良いと言う事になります。
 ごく簡単に此の 3 種類と言う事にしましたが やっているうちに iso-2022-jp も並びが特殊なので すぐに判断 出来る為 此も入れています。現在のプログラミング用途では これだけ押さえておけば特に問題は無いだろうと 言う妥協的な所で今回は終わろうかと思います。プログラミングの為のプログラムならもっときちっとした隙のない 事をすべきなのでしょうが 便利に使用できるプログラム制作にはこのぐらいで良いのではないかと思っています。
もう一つ きちっとしたものをやめた理由は MultiByteToWideChar が EUC を変換出来ないので全てがサポート 出来ないのなら実用的な所で留めて置こうと思ったのも事実です。( IE のサポート系の DLL を使用すれば 出来そうですが そうすると 全ての バージョンの Windows で出来る訳では無くなってしまうのが痛し痒しです。)
もっと優れた考え方が浮かんだりしたら 続々編も考えてみたいと思います。

[ 2012 / 10 / 04 ] [ 2012 / 10 / 04 ]
文字コードが違う場合のテキストクリップボード対応 の続続編です。
前回 は実用的な所で MultiByteToWideChar にコード判断をさせて 変換もさせるという事になりましたが 此では プログラム的にはやはり面白くないのと 大きな ファイルの時に時間がかかってしまう ( とは言っても 1Mb のファイルで 150ms ぐらいですが ) 事と EUC を変換出来無いのでやはり不完全なのはいけないのではないかと 思う様になりました。
幸いな 事に IE 5.5 以降では System フォルダーの mlang.dll ( Multi Language Support DLL ) が外部関数として ConvertINetMultiByteToUnicode と言うのをサポートしていて EUC → UTF-16 も変換出来る様です。
従って 完成形 としては 文字コードは自分で判断して UTF-16 ならそのまま Shift-JIS 以外の MultiByte コードなら MultiByteToWideChar か mlang.dll で MultiByte→UTF-16 変換後 CF_UNICODETEXT で クリップボードに入れる。 CF_UNICODETEXT でクリップボードに入れれば クリップボードを閉じた時点で システムが CF_TEXT の方も変換して 代入してくれます。コードが Shift-JIS の時は クリップボードには CF_TEXT で入れれば CF_UNICODETEXT の方も システムが補填してくれるので Shift-JIS の時だけは変換無しで と言う方針でプログラムをする事にしました。
上記の様な考え方で コードを組んで行くと やはり自前のコードでの判断の方が 3 倍以上速い様です。 又 MultiByteToWideChar の方が mlang.dll の ConvertINetMultiByteToUnicode より若干速い事も解りました。 mlang.dll は全ての環境で有る訳では無いので ( Win 95 98 Me では無し 2000 で有るかも ) 使用は EUC → UTF-16 に限る事にしました。此で コードを書いて終了なのですが 大きくなったコードをどうしようとかの 問題解決をした物をそのうち アップしたいと思います。
 此処まで テキストクリップボードを扱ってきて テキストクリップボード を取得する時も CF_TEXT ←→ CF_UNICODETEXT はそれぞれ システムに制御が戻った時に ( プログラムがクリップボードを閉じた時に ) 無い方を 補填してしまうので 常に CF_UNICODETEXT だけ確認していれば良さそうです。此も 今までのプログラムは CF_UNICODETEXT を取得出来なかったら CF_TEXT を取得する事にしていましたが此の必要は無さそうで そのうち こちらを修正した物もアップかなと考えています。

-チップスに戻る- -トップページに戻る-