ReadFile
コンソール含めたファイルから読み込むには最終的にAPIのReadFileを呼ぶ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
std::string s; for(;;) { DWORD dwRead=0; if(!ReadFile(GetStdHandle(STD_INPUT_HANDLE), buff, sizeof(buff)-1, &dwRead, NULL)) { return 1; } if(dwRead==0) break; buff[dwRead]=0; s += buff; } |
入力元がコンソールの場合、この関数は改行すると制御が返る。EOFはここでは普通の文字として扱われ特別な処理はない。入力元がファイルの場合は終わりに達すると単にdwReadが0になる。
ここでコンソールに日本語を入力した時の文字コードはGetACP()と同じと思われ、レジストリHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACPの値、この値はコントロールパネルの地域と言語の設定の非ユニコードアプリの設定になると思われる。この値の変更はシステム再起動が必要。
SetConsoleCP()を使えばプロセスの入力コードページを変えられるが、CP_UTF8を設定してReadFileを呼んでもうまく読み込めない。IMEが起動しなくなりコピペで入力してもdwRead=0が返る(XPの場合)。
ReadFile()は汎用の入力APIだがコンソール用のReadConsole()がある。引数はReadFile()と大体同じだが、レファレンスによるとこの関数を使えばユニコードを読めると書いてある。そしてこの関数はAnsiとUnicodeで関数がわかれている。ReadConsoleW()を呼べばユニコード入力を受け取れる。
出力も同様にSetConsoleOutputCP(), WriteConsole()などでできると思う。
標準ライブラリ
上記はAPIレベルの話だったが、C標準ライブラリでは入力元がファイルだろうがコンソールだろうが同様に扱うので最終的にReadFile()を呼ぶ。よってコンソールからのユニコード入力はできないと思われる。
1 2 |
wchar_t buff[30]; fgetws(buff, 29, stdin); |
このコードはコンソールからReadFile()読んだデータをユニコードに変換して返す。変換のはロケールにしたがって動くのでデフォルトのCロケールだと日本語すらちゃんと変換できない。
1 |
setlocale(LC_ALL,"jpn"); |
こう書くとロケールのコードページ932が指定されユニコードに変換されるので日本語は入力できるが中国語などは入力できないしここでロケールを中国語に変えても元々が932で読み込んでるので正しく変換できないだろう。
_setmode()関数の引数にユニコード関係も追加されたがこれらは入力がファイルの場合には機能するがコンソールの場合はうまくいかないだろう。
コンソールからの入力は上記のように大変だが出力はWriteFile()でもうまく動くとの報告もあるが調べてない。