怎么样才可以在 GUI 里获得 stdout、stderr 的读句柄呢?打个比方,在 Maya 里,如果开发 API 的时候使用了 fprintf(stderr,"abcabc\n"); 或者 std::cerr<<"abcabc"<<std::endl;,那么 Maya 会在 Output 窗口里把 abcabc 打印出来。其实要获得 Std 的句柄在 Console 程序里并不难,只需要 ::GetStdHandle 就可以。但如果在 GUI 程序里要实现 Maya 那样的功能呢?似乎就非常困难了……………………(到目前我还没行……)在 GUI 里获得的 ::GetStdHandle 竟然是 0x00000000 …………昏死…………现在我有几种思路:
第一:用一个重定向的函数 freopen,但 freopen 只把 stdout 或 stderr 重定向到一个文件,比如freopen("c:\\error.log","wb+",stderr);这样使用重定向后如果向 stderr 输出信息(包括 cerr)的,那么就不会在 console 里显示,而是直接输出到 c:\error.log 文件里面去。顺着这个思路下来,我想到了用 Pipe ,比如:
::CreateNamedPipe("\\\\.\\pipe\\stderrtmp",....);
freopen("\\\\.\\pipe\\stderrtmp","wb+",stderr);然后用 ::ReadFile 去读 Pipe 里的内容,结果的确可以把 stderr 的信息通过 Pipe 进行传递,但只是 Pipe 传递过来的信息会有遗漏,比如我执行四次:fprintf(stderr,"abcd");
fprintf(stderr,"abcd");
fprintf(stderr,"abcd");
fprintf(stderr,"abcd");则在 Pipe 里读出来的信息是:
abcd
bcd
abcd
bcd偶数次读出来的信息会遗漏第一个字符………………第二点我又想到不如直接把 stderr 不用 Pipe 通讯(消耗太大,而且如你所说的,不适合在 Current Process 里用。那么我又想到用 FileMappping,但 FileMapping 又有问题…………一个刚建立的文件不能建立比它自身大小要大的映射…………第三点,其实我是最早想到的,就是像向 ChildProcess 获得 stderr 句柄一样,用匿名 Pipe 进行交换。HANDLE hStdErrRedir;
HANDLE hStdErrRead;::CreatePipe(&hStdErrRead, &hStdErrRedir,0);::SetStdHandle(hStdRedir,STD_OUTPUT_HANDLE);但这样在读 Pipe 的时候会提示 Access Denie …………哎呀,我的头都给想到要炸开了…………都没办法…………5555555:(
第一:用一个重定向的函数 freopen,但 freopen 只把 stdout 或 stderr 重定向到一个文件,比如freopen("c:\\error.log","wb+",stderr);这样使用重定向后如果向 stderr 输出信息(包括 cerr)的,那么就不会在 console 里显示,而是直接输出到 c:\error.log 文件里面去。顺着这个思路下来,我想到了用 Pipe ,比如:
::CreateNamedPipe("\\\\.\\pipe\\stderrtmp",....);
freopen("\\\\.\\pipe\\stderrtmp","wb+",stderr);然后用 ::ReadFile 去读 Pipe 里的内容,结果的确可以把 stderr 的信息通过 Pipe 进行传递,但只是 Pipe 传递过来的信息会有遗漏,比如我执行四次:fprintf(stderr,"abcd");
fprintf(stderr,"abcd");
fprintf(stderr,"abcd");
fprintf(stderr,"abcd");则在 Pipe 里读出来的信息是:
abcd
bcd
abcd
bcd偶数次读出来的信息会遗漏第一个字符………………第二点我又想到不如直接把 stderr 不用 Pipe 通讯(消耗太大,而且如你所说的,不适合在 Current Process 里用。那么我又想到用 FileMappping,但 FileMapping 又有问题…………一个刚建立的文件不能建立比它自身大小要大的映射…………第三点,其实我是最早想到的,就是像向 ChildProcess 获得 stderr 句柄一样,用匿名 Pipe 进行交换。HANDLE hStdErrRedir;
HANDLE hStdErrRead;::CreatePipe(&hStdErrRead, &hStdErrRedir,0);::SetStdHandle(hStdRedir,STD_OUTPUT_HANDLE);但这样在读 Pipe 的时候会提示 Access Denie …………哎呀,我的头都给想到要炸开了…………都没办法…………5555555:(
freopen("CONIN$","w+t",stdin);
VOID main(void)
{
HANDLE hStdout, hNewScreenBuffer;
SMALL_RECT srctReadRect;
SMALL_RECT srctWriteRect;
CHAR_INFO chiBuffer[160]; // [2][80];
COORD coordBufSize;
COORD coordBufCoord;
BOOL fSuccess;
// Get a handle to the STDOUT screen buffer to copy from and
// create a new screen buffer to copy to.
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
hNewScreenBuffer = CreateConsoleScreenBuffer(
GENERIC_READ | // read/write access
GENERIC_WRITE,
0, // not shared
NULL, // no security attributes
CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE
NULL); // reserved; must be NULL
if (hStdout == INVALID_HANDLE_VALUE ||
hNewScreenBuffer == INVALID_HANDLE_VALUE)
{
MyErrorExit("CreateConsoleScreenBuffer");
}
// Make the new screen buffer the active screen buffer.
if (! SetConsoleActiveScreenBuffer(hNewScreenBuffer) )
MyErrorExit("SetConsoleActiveScreenBuffer");
// Set the source rectangle.
srctReadRect.Top = 0; // top left: row 0, col 0
srctReadRect.Left = 0;
srctReadRect.Bottom = 1; // bot. right: row 1, col 79
srctReadRect.Right = 79;
// The temporary buffer size is 2 rows x 80 columns.
coordBufSize.Y = 2;
coordBufSize.X = 80;
// The top left destination cell of the temporary buffer is
// row 0, col 0.
coordBufCoord.X = 0;
coordBufCoord.Y = 0;
// Copy the block from the screen buffer to the temp. buffer.
fSuccess = ReadConsoleOutput(
hStdout, // screen buffer to read from
chiBuffer, // buffer to copy into
coordBufSize, // col-row size of chiBuffer
coordBufCoord, // top left dest. cell in chiBuffer
&srctReadRect); // screen buffer source rectangle
if (! fSuccess)
MyErrorExit("ReadConsoleOutput");
// Set the destination rectangle.
srctWriteRect.Top = 10; // top lt: row 10, col 0
srctWriteRect.Left = 0;
srctWriteRect.Bottom = 11; // bot. rt: row 11, col 79
srctWriteRect.Right = 79;
// Copy from the temporary buffer to the new screen buffer.
fSuccess = WriteConsoleOutput(
hNewScreenBuffer, // screen buffer to write to
chiBuffer, // buffer to copy from
coordBufSize, // col-row size of chiBuffer
coordBufCoord, // top left src cell in chiBuffer
&srctWriteRect); // dest. screen buffer rectangle
if (! fSuccess)
MyErrorExit("WriteConsoleOutput");
Sleep(10000);
// Restore the original active screen buffer.
if (! SetConsoleActiveScreenBuffer(hStdout))
MyErrorExit("SetConsoleActiveScreenBuffer");
}
int hCrt;
FILE *hf; AllocConsole();
hCrt = _open_osfhandle(
(long) GetStdHandle(STD_OUTPUT_HANDLE),
_O_TEXT
);
hf = _fdopen( hCrt, "w" );
*stdout = *hf;
i = setvbuf( stdout, NULL, _IONBF, 0 );