Win32APIとUnicode

文字コードとか勉強していたらいつのまにかWindowsUnicode対応などに首を突っ込んでしまったのでまとめ。


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があって、それとクラス情報を頼りにUnicodeANSIを適切に変換してくれる。
なるほど、実にうまいことできている。
Unicodeで書かれたプログラムはいまのところ見たことないんだけど、内部UnicodeでユーザーがANSI CodePageでもこういう仕組みで問題なく動いているのだな。