コミケ告知

サークル活動の詳細は circle タグの記事へ。
2013年9月7日土曜日

Windowsのプログラムの標準出力とリダイレクトと

 Windowsでもコンソールアプリから…

Z;\>hoge.exe > log.txt

 このようにすると、標準出力がファイルにリダイレクトできます。
 ところが微妙に複雑な仕様があるらしく、若干うまくいかなかったのでメモ。


状況


 普通に実行すると、標準出力にテキストを色々吐くプログラムがあり…
Z;\>hoge.exe
I love beef!
I love pork!
 ファイルにリダイレクトすると、出力されないものがある。どういうこっちゃ。
Z;\>hoge.exe > log.txt
Z;\>type log.txt
I love beef! 
 

解明

テスト用のソースコードは以下。
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <wincon.h>
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR *lbuf = L"I love beef!\n";
CHAR *buf = "I love pork!\n";
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO scrInfo;
DWORD wroteSize;
GetConsoleScreenBufferInfo(hStdout, &scrInfo)
? printf("GetConsoleScreenBufferInfo: OK\n")
: printf("GetConsoleScreenBufferInfo: NG\n");
SetConsoleTextAttribute(hStdout, BACKGROUND_RED | FOREGROUND_BLUE)
? printf("SetConsoleTextAttribute: OK\n")
: printf("SetConsoleTextAttribute: NG\n");
WriteConsole(hStdout, lbuf, lstrlen(lbuf), &wroteSize, nullptr)
? printf("WriteConsole: OK\n")
: printf("WriteConsole: NG\n");
SetConsoleTextAttribute(hStdout, scrInfo.wAttributes);
WriteFile(hStdout, buf, strlen(buf), &wroteSize, nullptr)
? printf("WriteFile: OK\n")
: printf("WriteFile: NG\n");
return 0;
}


リダイレクトしなかった場合の出力: (実際には微妙な色で装飾される)
GetConsoleScreenBufferInfo: OK
SetConsoleTextAttribute: OK
I love beef!
WriteConsole: OK
I love pork!
WriteFile: OK

リダイレクトした場合にファイルに書かれる内容:
I love pork!
GetConsoleScreenBufferInfo: NG
SetConsoleTextAttribute: NG
WriteConsole: NG
WriteFile: OK
  • ファイルにリダイレクトされた場合、Console関係の関数は失敗する
    • WriteConsole
    • GetConsoleScreenBufferInfo
    • SetConsoleTextAttribute
  • WriteFileはリダイレクトの有無にかかわらず成功する
  • (w)printfはリダイレクトの有無にかかわらず成功する
 リダイレクトによって挙動が変わるなんて思っていなかったので、ログ全体をうまくファイルに書き出せずに焦りました。WriteConsoleした分は引き続き画面に出る…というわけではなく、単純に消滅します。
 そういう挙動が嫌なら、WriteConsoleは使わずにWriteFileを使うのがよさそうです。着色のために呼ぶConsole関係の関数が失敗しても、気にせずWriteFile。