[software] TCHARはcharかwchar_tか

よく知られているように、Windows CE環境はAPIUnicodeしかサポートしていない。そのため、eVCで開発をする際、普通は_UNICODEが定義された状態であり、TCHARはwchar_tである。
また、Windows XP環境はANSIUnicodeもサポートしており、デスクトップ上のWindows環境でVisual Studioで開発をする際は普通は_MBCSが定義された状態である。この場合、TCHARはcharである。
気をつけていればあまり問題はおきないのだが、よく考えずにWindows CE上のものをWindows XPへ移植しようとするとはまることがある。筆者の経験した例を紹介しよう。
そのプロジェクトはお客様の環境(Windows CEの組込み機器)にとあるミドルウェアを納めるというものだったのだが、フォントの部分だけお客様(の発注した別のベンダーであろう)がDLLで用意する形であった。文字列に対応するフォントのビットマップデータを返すようなAPIをもっているDLLであったので、当然のように呼び出し関数の引数にはTCHAR *型のものがあった(const TCHAR *型でないところがまたやっかいだったのだが、この際置いておく)。ターゲット環境はWindows CEだったので、TCHARはwchar_tであり、要するにUnicode文字列からフォントデータを返す形である。
さて、実機の開発が終了した後、そのミドルウェアの上に載せるアプリケーション開発用に、Windows XP上で動作する同等のものが欲しいということになった。そこで、フォントのDLLもお客様よりWindows XP用のものを提供してもらったのだが、ここでハタと疑問がよぎる。APIに渡す文字列はマルチバイトなのだろうか、それともUnicodeなのだろうか?
お客様より提供されたWindows XP用のヘッダを見てみると、件のAPIのプロトタイプ宣言では引数の型がやはりTCHAR *になっている。これはWindows XPだからchar *でいいんだよな、と安易な解釈をしてミドルウェアをビルドしたところ、見事に動かない(正確にはC++だったので、引数の違いでリンカエラーがでたような。。ずいぶん前のことなので記憶があいまいだ)。どうやらこのDLLは実機に忠実にUnicode文字列を引数としてとるようになっているようだ。ミドルウェアの別の部分ではTCHARがcharであるとしてコーディングされている部分があったので、_UNICODEを定義するわけにもいかない。というか、ANSI版とUnicode版があるわけではないのだからTCHARをプロトタイプ宣言に使うのがそもそもの問題なのである。。結局お客様より提供されたヘッダ中のTCHARを全部wchar_tに書き換えることによって対応した。非常に無駄な作業である。

  • 教訓: マルチバイト版とUnicode版と両方をサポートするのでないのなら、DLLでexportするAPIのプロトタイプ宣言でTCHARを使うことは避けるべき。