SetStdHandle has no effect on cout/printf

后端 未结 3 671
青春惊慌失措
青春惊慌失措 2020-12-09 21:43

The title says it all. When I run the following code:

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hFile = CreateFile(TEXT(\"Foo.txt\"), GENERIC_WRI         


        
3条回答
  •  感情败类
    2020-12-09 22:08

    Here's a solution I put together (far from perfect of course). It calls a custom function for every character written to STDOUT. In my example, it forwards the stream to OutputDebugString calls.

    #include 
    #include 
    #include 
    #include 
    
    #define STDOUT_FILENO 1
    #define STDERR_FILENO 2
    
    enum StdHandleToRedirect {
        STDOUT, STDERR
    };
    
    class StdRedirect {
    public:
        /// Assumes the specified handle is still assigned to the default FILENO (STDOUT_FILENO/STDERR_FILENO)
        /// TODO allow redirection in every case
        /// callback will run in a new thread and will be notified of any character input to
        /// the specified std handle
        StdRedirect(StdHandleToRedirect h, std::function callback) : callback(callback) {
            CreatePipe(&readablePipeEnd, &writablePipeEnd, 0, 0);
            SetStdHandle(h == STDOUT ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE, writablePipeEnd);
    
            // Redirect (TODO: ERROR CHECKING)
            int writablePipeEndFileStream = _open_osfhandle((long)writablePipeEnd, 0);
            FILE* writablePipeEndFile = NULL;
            writablePipeEndFile = _fdopen(writablePipeEndFileStream, "wt");
            _dup2(_fileno(writablePipeEndFile), h == STDOUT ? STDOUT_FILENO : STDERR_FILENO);
    
            CreateThread(0, 0, (LPTHREAD_START_ROUTINE)stdreader, this, 0, 0);
        }
    
        // TODO implement destructor, cleanup, reset
    
    private:
        // DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter)
        static void WINAPI stdreader(StdRedirect* redirector) {
            while (1) {
                char c;
                DWORD read;
                ::fflush(NULL); // force current stdout to become readable
                // TODO add error handling
                ReadFile(redirector->readablePipeEnd, (void*)&c, 1, &read, 0); // this blocks until input is available
                if (read == 1)
                    redirector->callback(c);
            }
        }
    
        HANDLE readablePipeEnd, writablePipeEnd;
        const std::function callback;
    };
    
    int main() {
        std::function toOutputDebugString = [](char x) {
            char str[2] = {x, 0};
            OutputDebugStringA(str);
        };
    
        StdRedirect so(STDOUT, toOutputDebugString);
        std::cout << "test stdout\n";
        while (1); // busy loop to give the thread time to read stdout. 
        // You might want to look at "Output: Show output from: Debug" now.
        return 0;
    }
    

提交回复
热议问题