How can I redirect stdout to some visible display in a Windows Application?

后端 未结 8 1300
时光取名叫无心
时光取名叫无心 2020-11-27 03:31

I have access to a third party library that does \"good stuff.\" It issues status and progress messages to stdout. In a Console application I can see these messages just f

相关标签:
8条回答
  • 2020-11-27 04:01

    You're probably looking for something along those lines:

        #define OUT_BUFF_SIZE 512
    
        int main(int argc, char* argv[])
        {
            printf("1: stdout\n");
    
            StdOutRedirect stdoutRedirect(512);
            stdoutRedirect.Start();
            printf("2: redirected stdout\n");
            stdoutRedirect.Stop();
    
            printf("3: stdout\n");
    
            stdoutRedirect.Start();
            printf("4: redirected stdout\n");
            stdoutRedirect.Stop();
    
            printf("5: stdout\n");
    
            char szBuffer[OUT_BUFF_SIZE];
            int nOutRead = stdoutRedirect.GetBuffer(szBuffer,OUT_BUFF_SIZE);
            if(nOutRead)
                printf("Redirected outputs: \n%s\n",szBuffer);
    
            return 0;
        }
    

    This class will do it:

    #include <windows.h>
    
    #include <stdio.h>
    #include <fcntl.h>
    #include <io.h>
    #include <iostream>
    
    #ifndef _USE_OLD_IOSTREAMS
    using namespace std;
    #endif
    
    #define READ_FD 0
    #define WRITE_FD 1
    
    #define CHECK(a) if ((a)!= 0) return -1;
    
    class StdOutRedirect
    {
        public:
            StdOutRedirect(int bufferSize);
            ~StdOutRedirect();
    
            int Start();
            int Stop();
            int GetBuffer(char *buffer, int size);
    
        private:
            int fdStdOutPipe[2];
            int fdStdOut;
    };
    
    StdOutRedirect::~StdOutRedirect()
    {
        _close(fdStdOut);
        _close(fdStdOutPipe[WRITE_FD]);
        _close(fdStdOutPipe[READ_FD]);
    }
    StdOutRedirect::StdOutRedirect(int bufferSize)
    {
        if (_pipe(fdStdOutPipe, bufferSize, O_TEXT)!=0)
        {
            //treat error eventually
        }
        fdStdOut = _dup(_fileno(stdout));
    }
    
    int StdOutRedirect::Start()
    {
        fflush( stdout );
        CHECK(_dup2(fdStdOutPipe[WRITE_FD], _fileno(stdout)));
        ios::sync_with_stdio();
        setvbuf( stdout, NULL, _IONBF, 0 ); // absolutely needed
        return 0;
    }
    
    int StdOutRedirect::Stop()
    {
        CHECK(_dup2(fdStdOut, _fileno(stdout)));
        ios::sync_with_stdio();
        return 0;
    }
    
    int StdOutRedirect::GetBuffer(char *buffer, int size)
    {
        int nOutRead = _read(fdStdOutPipe[READ_FD], buffer, size);
        buffer[nOutRead] = '\0';
        return nOutRead;
    }
    

    Here's the result:

    1: stdout
    3: stdout
    5: stdout
    Redirected outputs:
    2: redirected stdout
    4: redirected stdout
    
    0 讨论(0)
  • 2020-11-27 04:04

    Here we'll set a new entry point consoleMain that overrides your own one.

    1. Determine the entry point of your application. In VisualStudio, select Project Properties/Linker/Advanced/Entry Point. Let us call it defaultMain.
    2. Somewhere in your source code declare the original entry point (so we can chain to it) and the new entry point. Both must be declared extern "C" to prevent name mangling.

      extern "C"
      {
        int defaultMain (void);
        int consoleMain (void);
      }
      
    3. Implement the entry point function.

      __declspec(noinline) int consoleMain (void)
      {
        // __debugbreak(); // Break into the program right at the entry point!
        AllocConsole();    // Create a new console
        freopen("CON", "w", stdout);
        freopen("CON", "w", stderr);
        freopen("CON", "r", stdin); // Note: "r", not "w".
        return defaultMain();
      }
      
    4. Add your test code somewhere, e.g. in a button click action.

      fwprintf(stdout, L"This is a test to stdout\n");
      fwprintf(stderr, L"This is a test to stderr\n");
      cout<<"Enter an Integer Number Followed by ENTER to Continue" << endl;
      _flushall();
      int i = 0;
      int Result = wscanf( L"%d", &i);
      printf ("Read %d from console. Result = %d\n", i, Result);
      
    5. Set consoleMain as the new entry point (Project Properties/Linker/Advanced/Entry Point).
    0 讨论(0)
  • 2020-11-27 04:10

    You can redirect stdout, stderr and stdin using freopen.

    From the above link:

    /* freopen example: redirecting stdout */
    #include <stdio.h>
    
    int main ()
    {
      freopen ("myfile.txt","w",stdout);
      printf ("This sentence is redirected to a file.");
      fclose (stdout);
      return 0;
    }
    

    You can also run your program via command prompt like so:

    a.exe > stdout.txt 2> stderr.txt
    
    0 讨论(0)
  • 2020-11-27 04:12

    You need to create pipe (with CreatePipe()), then attach stdout to it's write end with SetStdHandle(), then you can read from pipe's read end with ReadFile() and put text you get from there anywhere you like.

    0 讨论(0)
  • 2020-11-27 04:14

    When you create a process using CreateProcess() you can choose a HANDLE to which stdout and stderr are going to be written. This HANDLE can be a file to which you direct the output.

    This will let you use the code without recompiling it. Just execute it and instead of using system() or whatnot, use CreateProcess().

    The HANDLE you give to CreateProcess() can also be that of a pipe you created, and then you can read from the pipe and do something else with the data.

    0 讨论(0)
  • 2020-11-27 04:16

    This is what I'd do:

    1. CreatePipe().
    2. CreateProcess() with the handle from CreatePipe() used as stdout for the new process.
    3. Create a timer or a thread that calls ReadFile() on that handle every now and then and puts the data read into a text-box or whatnot.
    0 讨论(0)
提交回复
热议问题