#まだWindows。non consoleアプリからconsoleをひらこうとしてはまってる。とりあえず、一度non consoleアプリとしてスタートしたらファイルディスクリプタ0,1,2のレベルでのi/oは不可能である、という点についてはようやく公式リファレンスを見つけた。 http://support.microsoft.com/kb/105305/en-us #で、Schemeレベルでの標準入出力ポートを、手続きポートに置き換えて、自前のコンソールに送ろうとしてるとこなんだが、AllocConsole()してるのにGetStdHandle()が返すファイルハンドルを使おうとするとinvalid file handleでエラーになる。
#上記文書には AllocConsole()を呼んだ後ならGetStdHandler()は必ず有効なハンドルを返すって書いてあるんだけどなあ。
#ちなみにGetStdHandle()で得られたハンドルを_open_osfhandleに渡してもinvalid file handleエラーになる。なので、そこらじゅうに紹介されてるこの手法もうまくいかない: http://www.halcyon.com/~ast/dload/guicon.htm #多分これが動作するための前提が何かあると思うんだけどなあ。
#ふむ。簡単なテストプログラムを書いてMinGWとVCでビルドしてみたら、VCだとちゃんと動くけどMinGWだとGetStdHandleが無効なハンドルを返す。初期化ルーチンの違いのせいかな。
#AllocConsole()の後freopen("CONOUT$", "w", stdout)としてstream ioを使う方法はMinGWでも動いた。ここだけstream ioを使うのはいまいちだけど、あまり深入りするのも時間の無駄のような気がするのでこれで妥協するかな。
#mingwのgccを4.5.0にしたら最適化でちょっとひっかかった。infinityをチェックするための double x; ((x)!=0.0&&(x)==(x)/2.0) という式がoptimize awayされてしまうようだ。isinfがあればそっちを使うから問題でないはずだけど.
#たぶん影響出てるのmingw版だけなのでxをvolatileにしてとりあえず回避。そんなにperformance criticalじゃない…はず…
#mingw版のgauche.termiosで提供されてたwindowsコンソール関数って使ってる人いるかな。windows特有の手続きをos.windowsってモジュールにまとめてしまおうと思ってるんだけど
#非コンソールアプリに於いて AllocConsole() の後に GetStdHandle(STD_OUTPUT_HANDLE) を呼ぶと INVALID_HANDLE_VALUE が返ってくるということでしょうか?
#いえ、INVALIDじゃなくてハンドルっぽい値が帰ってくるんですが、それを_open_osfhandleやWriteConsoleで使おうとするとエラーになるのです。
#全く同じコードをVC2008でコンパイルすると動作します。
#あ、非コンソール版は結局gosh-noconsole.exeという芸の無い名前にしました。
#私が試した限りでは特にエラーにはならない感じなんですけど…。
##include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <fcntl.h>
#include <windows.h>
int main(void) {
int hCrt;
FILE *hf;
HANDLE hCsle;
char message[]="Hello world\n";
DWORD d;
AllocConsole() ;
hCsle=GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsole(hCsle, message, sizeof(message), &d, 0);
hCrt = _open_osfhandle((long) hCsle, _O_TEXT);
hf = _fdopen( hCrt, "w" );
*stdout = *hf;
int i = setvbuf( stdout, NULL, _IONBF, 0 );
printf("%s", message);
int a;
Sleep(1000);
return 0;
}
#こんなので試しました。
#何かのバージョン違いとかかな? それとも私が見当違いなテストをしてる?
#私のとこだとそのコードで落ちますね。何か環境の問題っぽいですね。
#コマンドラインは
#$ gcc --version
gcc.exe (GCC) 4.5.0
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PIRPOSE.
$ gcc -o t t.c -Wl,--subsystem,windows
#-Wl,--subsystem,windowsのかわりに-mwindowsでも結果は同じです。
#MSYSとか、五月雨式にアップデートしてるからうちの環境で何かが古いとかかna.
#とりあえず、「非コンソールモードでスタートしたアプリが標準出力や標準エラー出力に何か書いたらAllocConsole()して表示する」というのはfreopenを使って出来ているのですが、うちの環境が変な可能性は潰しておきたいな。
#mingw AllocConsoleとかで検索しても問題になっているふうはないから、うちの環境の方が特殊と考えた方が自然だな…
#あ、cmd.exeから実行したら動いた。msysのシェルが何か介入してるのかな。
#ふーむ。msys.bat --norxvtで起動されたシェルから上記tを実行→落ちる
#msys.bat --rxvtで起動されたシェルから上記tを実行→落ちないけど、出力が生成されたコンソールではなくrxvfの方に行く
#この差はなんだろう。CreateProcess自体を実行してるのはどちらもbashだよなあ。
#msysのターミナル (--norxvtでも--rxvtでも) からcmd.exeを起動して、そこからtを走らせると正常動作。やっぱりCreateProcessのされ方に違いがあるのか?
#mainをWinMainに変えてVCでビルドしたもの。VCから実行→成功、cmd.exeから実行→成功、msys --norxvt →落ちる、msys --rxvt →ターミナルの方にHello world。どうやらcrtの問題ではなく、親プロセス側の処理の違いの模様。
#cmd.exeからmsysのbashを起動してそこからtを実行→落ちる。やはり親側の問題か。
#詳しく検証したいとこだけど、とりあえずGaucheについてはfreopenで動いてるからしばらく寝かせるかも。
#できればmsysコンソールとcmd.exeでのふるまいの違いを追試してもらえるとありがたいです>齊藤さん