Windowsは好きではないのだが、仕事で使わざるを得ないので使っている。
今回は、Windowsアプリの国際化について、調べたこととわからないことを書く。
基本的なこと
- Unix系のOSでは、文字/文字列を表す型として、char/wchar_t があり、中にどんな文字コードの文字が入っているかはプログラマが理解して使う。charの文字列リテラルは "abc" のように表記し、wchar_t の文字列リテラルは L"abc" のように表記する。
- Windows のC/C++では、そもそもプロジェクトの設定に「文字セット」と言う項目があり、「指定なし」「マルチ バイト文字セットを使用する」「Unicode 文字セットを使用する」を選ぶ。
- Windowsで文字を表す型としては、char/WCHAR/TCHAR がある。
- WCHAR は wchar_t のtypedef であり、TCHAR は上記プロジェクト設定によって、char または WCHAR の typedef となる。
- char の文字列に何が入っているかはプログラマ依存であるが、WCHAR の文字列には UTF-16LE の文字列が入っていることになっている。
- MFCを使用する場合の「文字セット」の「マルチ バイト文字セットを使用する」はVisualStudio 2013 から非推奨となっており、将来的なサポートは保証されない。
Windows のAPIセット
- Windows のシステムコールやMFCの関数群は、「マルチ バイト文字セット(もしくは指定なし)」用と「Unicode 文字セット」用で別のものが用意されている。
- 通常のシステムコールは「マルチ バイト文字セット(もしくは指定なし)」用は関数名の後ろに「A」(AはmbcsではなくANSIから来ているらしい)が付き、「Unicode 文字セット」用は「W」が付く。そして、「文字セット」の設定によってAもWも付かない関数名にdefineされる。
- なので、普通に char/WCHAR どちらでもビルドできるプログラムを作るには、char/WCHAR を使わずに TCHAR を使い、AやWがつかない関数名を使えば良い。
- のだが、ここにMicrosoftの迷走があって、綺麗に行かないことが多い。
- 例えば、文字列の長さを調べる関数を例に取ると、Cの標準関数ではstrlenと言うものがあるが、Windowsだとこれに該当するものとして strlen, _mbslen, wcslen の3つがある。そして、上記の AやWがつかないもの相当として、_tcslen, _tcsclen の二つがある。(そして、_mbstrlenとか、後ろに_lがついたものもある)
- 基本的にはマルチバイト用は mbs が接頭につき、ワイドキャラ用は wcs が接頭につくのだが、関数によって _ が付くものと付かないものがある。
- 後ろに w が付いたり付かなかったり、前にwが付いたりするものもある。
- ものによっては、ANSI版が用意されているのにUnicode版が用意されていないものもある(_gcvtとか)
MFCのMBCS
- Microsoft の現在の推奨は、「文字セット」に「Unicode 文字セット」を指定しろ、と言うものである。
- 推奨設定であれば、レガシーなライブラリであるMFCを使っていても、一応国際化があまり悩まずにできる。
- 問題は、「マルチ バイト文字セット(もしくは指定なし)」設定のプロジェクトでは、使える言語がOSのシステム ロケールの設定に引きずられてしまい、別の言語の文字の表示ができなくなること。
- OSのシステム ロケールは、コントロールパネルの「地域と言語」を開き、「管理」タブの「Unicode 対応ではないプログラムの言語」にある「システム ロケールの変更(C)...」で変更する。この設定を変更すると、OSの再起動を要求される。
- 「形式」タブで設定できる内容は、日付や通貨の設定だけで、実際の言語は切り替えられない。
- ロケールを切り替えなくても、WideCharToMultiByte 等の関数を使えば、文字コードの変換はできる。
- Windowsにも setlocale とか、_setmbcp とかすごく効きそうな関数があるのに、これらを呼んでも上記「システム ロケールの変更」と同等のことは実現できない。
- つまり、MBCSで書いたMFCアプリは、動的に言語を切り替えたりできない。
このくらいまで調べて手詰まりなのである。
WCSを使うようにアプリを書き換えない限り、MFCのアプリに未来はないのか?