UTF-8の文字列をコンソールに出そうとしたけど出せなかった

なんとなくTwitterのタイムラインをWin32 APIバリバリで取得してみようと頑張ってたんですが、どうも文字を出力するところで納得がいかなかったので憂さ晴らし。

WindowsのコンソールでUTF-8の文字列を出力しようとするとき、以下のようなパターンがあります。

  • Shift JISに変えて表示
    1. MultiByteToWideCharでUNICODE
    2. WideCharToMultiByteでShift JISに
    3. printfなどで表示
  • UNICODEに変えて表示
    1. setlocale(LC_ALL, "japanese")
    2. MultiByteToWideCharでUNICODE
    3. wprintfなどで表示
  • そのまま表示

これの3つ目がどうやってもできませんでした。setlocale(LC_ALL, "japanese_japan.65001")で出来んじゃないか?と思ったんですが、リファレンスにしっかり断り書きがありました。

The set of available languages, country/region codes, and code pages includes all those supported by the Win32 NLS API except code pages that require more than two bytes per character, such as UTF-7 and UTF-8.

Download Visual Studio 2005 Retired documentation from Official Microsoft Download Center

万事休す……と思ったんですが、chcpコマンドを使うとUTF-8の出力ができるので、ここにヒントがあるんじゃないかと考えました。chcpコマンドは以下のように使います。

chcp 65001

こうすると、出力がUTF-8になります(実際はフォントの都合で色々うまくいきませんが)。まずchcpコマンドをDependency Walkerで開き、依存している関数をチェック。

どうも SetThreadLocale 関数が気になるので、調べてみました。結果、使い方はほとんどsetlocaleと変わらない様子なので、とりあえず

//setlocale(LC_ALL, "japanese_japan.65001");
SetThreadLocale(65001);

してみました。で、結果はというとまたも失敗。GetLastErrorさんいわく「パラメータが間違っています。 」だそうです。で、他に関数ないかなーと調べてみたところ、見つけたのがこれ。

(マングルされてるけど)名前がそのものだー。というわけでMSDNさんにこの関数について聞いてみたら、この関数を使うためのインタフェースIQueryCodePageの最低動作環境がなんとWindows 7……

というわけで、setlocaleちゃんとしろ!とか思いつつ、このあたりで調査はあきらめました。文字出力したいだけならUNICODEに変換して終わりですし。