怎么样才可以在 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:(

解决方案 »

  1.   

    也就是说,你想要 GUI 的程序也可以用 cin / cout 输入输出?试试 AllocConsoleBOOL AllocConsole(VOID);不过这个 Console 不能输出 cout 和 printf 仅仅可以接受 _cprintf / _cscanf
      

  2.   

    AllocConsole();是肯定需要的,然后就不知道VC里是怎么实现了,我在BCB里可以这样实现。freopen("CONOUT$","w+t",stdout);
    freopen("CONIN$","w+t",stdin);
      

  3.   

    #include <windows.h> 
     
    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"); 
     
    }
      

  4.   


    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 );