Win32APIとUnicode
文字コードとか勉強していたらいつのまにかWindowsのUnicode対応などに首を突っ込んでしまったのでまとめ。
Windowsは内部的にはUnicodeを使っている、とどっかで見たきがする。
VisualC++でソースの文字コードにUnicodeを使っても正常にコンパイルできるし、#define UNICODEと書いておけばWin32APIに文字列を渡してもきちんと動く。
Win32APIではAPIの最後にWを付けた関数がUnicode用、Aを付けたものがANSI CodePage用になっている。
たとえばMessageBoxExの場合、#define UNICODEするとMessageBoxExWがMessageBoxExとして定義され、してなければMessageBoxExAが定義される。
この仕掛けにより、渡された文字列がUnicodeなのか、そうでないのかを判別しているわけだ。
じゃあ、OSから届くウィンドウメッセージで渡される文字列は、どのように判別されて変換されるんだろう。
ウィンドウを作るとき、Win32APIではRegisterClassしてからCreateWindowする。
RegisterClassにもWとAがあって、Wで作られたウィンドウクラスのウィンドウプロシージャには文字列がUnicodeで届くようになるのだ。
うまいことできている。
さらに、ウィンドウをサブクラス化するときにSetWindowLongを使う。
これにもWとAがあって、サブクラス化して追加したウィンドウプロシージャに届く文字コードも指定できる。
元のウィンドウプロシージャがANSIだったとしても、フックしたウィンドウプロシージャはUnicodeとかできるわけだ。
たとえばBUTTONクラスで作ったウィンドウだった場合は、BUTTONクラスはシステム提供のクラスだから文字コードがどっちかわかんないわけだが、ウィンドウプロシージャのチェインはCallWindowProcを使い、これにもちゃんとWとAがあって、それとクラス情報を頼りにUnicode⇔ANSIを適切に変換してくれる。
なるほど、実にうまいことできている。
Unicodeで書かれたプログラムはいまのところ見たことないんだけど、内部UnicodeでユーザーがANSI CodePageでもこういう仕組みで問題なく動いているのだな。