メイリオの罠

まぁ、自分のコードがあんまりちゃんとテストされていなかったと言えばそれまでなんですが、自分の作っている仮想プリンタドライバでは、OEMTextOutをフックして、印刷されたテキストをテキストデータとして出力するような処理をしています。
一般的に、OEMTextOutに渡されるデータは、いわゆるUTF-16(Unicode)ではなく、グリフインデックス(Glyph Index)というものになって渡されます(SO_GLYPHINDEX_TEXTOUTフラグ時)。

一方で、

KB241020:How To Translate Unicode Character Codes to TrueType Glyph Indices in Windows 95

のような情報が提供されており、この情報を使えば、フォントファイルの情報を使って、グリフインデックス→Unicodeの逆変換が行えます。普通は・・・。

複数文字に対応するグリフ

まぁ、KB241020は、Unicodeからグリフインデックスへの変換を指南しているわけで、逆変換がいけるよとは一言も書いていないのですが、普通のプログラマならば、これを見て、逆変換がいけると思わないわけはないでしょう。僕もそう思いました。そして、ほとんどの場合に置いて、その逆変換コードはちゃんと動いていたわけです。メイリオを除いて・・・。

メイリオは、MS ゴシックと比べても多くの文字を収録しており、この中には、上記の逆変換の目論みを打ち砕くような文字があります。一例を挙げると、

「立」という文字があります。この文字は、普通は、U+7ACBなんですが、実は、メイリオでは、全く同じグリフを共有する、U+2F74(KANGXI RADICAL STAND:康熙部首)というものがあるらしいのです。

で、順当に逆変換を行うと、コード表がUnicode順に並んでいるために、U+2F74このコードが先に見つかるので、そちらに逆変換されてしまうのですが、そうなると、MS ゴシックを使っている普通のエディタとかにコピペすると、表示が化けてしまいます。ユーザーとしては当然化けたと思う。

一方で、メイリオフォントで見ている人には、普通に読めちゃうんですが、実は文字コードが違うので、コピペで他人にデータを送るとやっぱり化ける。

結局、どうするべきかと言えば、根本的な解決方法はないのではと。
日本人が普通に使う範囲で言えば、U+2f00-U+2FDFの範囲は、無視するとかそういう方法しかないのかもしれません。

参考:

Unicode->グリフインデックスへの変換に関しては、GetCharacterPlacementを使うのがもっとも手っ取り早いですが、普通、ExtTextOutを使おうとかいう話でもなければ、そんなことをする必要はありません。
さらに、最近は、むしろ、ExtTextOutではなく、Uniscribeを使った方が良いというのがMicrosoftの見解のはずです。ExtTextOutではサポートが怪しい言語があるということでしょう。たぶん。