简体   繁体   English

如何将stdout重定向到Windows应用程序中的某些可见显示?

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

I have access to a third party library that does "good stuff." 我可以访问一个“好东西”的第三方库。 It issues status and progress messages to stdout. 它向stdout发出状态和进度消息。 In a Console application I can see these messages just fine. 在控制台应用程序中,我可以很好地看到这些消息。 In a Windows application they just go to the bit bucket. 在Windows应用程序中,他们只是转到位桶。

Is there a fairly simple way to redirect stdout and stderr to a text control or other visible place. 是否有一种相当简单的方法将stdout和stderr重定向到文本控件或其他可见的位置。 Ideally, this would not require any recompiles of the third party code. 理想情况下,这不需要重新编译第三方代码。 It would just intercept the steams at a low level. 它只是在低水平拦截蒸汽。 I'd like a solution where I just #include the header, call the initialization function and link the library as in... 我想要一个解决方案,我只需#include标头,调用初始化函数并链接库,如...

#include "redirectStdFiles.h"

void function(args...)
{
  TextControl* text = new TextControl(args...);
  initializeRedirectLibrary(text, ...);

  printf("Message that will show up in the TextControl\n");
  std::cout << "Another message that also shows up in TextControl\n";
}

Even better would be if it used some interface that I could override so it is not tied to any particular GUI library. 更好的是,如果它使用了一些我可以覆盖的接口,那么它就不会绑定到任何特定的GUI库。

class StdFilesRedirector
{
  public:
    writeStdout(std::string const& message) = 0;
    writeStderr(std::string const& errorMessage) = 0;
    readStdin(std::string &putReadStringHere) = 0;
};

Am I just dreaming? 我只是在做梦吗? Or does anyone know of something that can do something like this? 或者有人知道可以做这样的事情吗?

Edit after two answers: I think using freopen to redirect the files is a good first step. 在两个答案后编辑:我认为使用freopen重定向文件是一个很好的第一步。 For a complete solution there would need to be a new thread created to read the file and display the output. 要获得完整的解决方案,需要创建一个新线程来读取文件并显示输出。 For debugging, doing a 'tail -f' in a cygwin shell window would be enough. 对于调试,在cygwin shell窗口中执行'tail -f'就足够了。 For a more polished application... Which is what I want to write... there would be some extra work to create the thread, etc. 对于更精美的应用程序......我想写的是什么......创建线程会有一些额外的工作,等等。

您需要创建管(带CreatePipe() ),然后将其附加标准输出到它与写结束SetStdHandle() ,那么你可以从管道与读端读的ReadFile() ,把你从那里您想要的位置获取文本。

You can redirect stdout, stderr and stdin using freopen . 您可以使用freopen重定向stdout,stderr和stdin。

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

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

When you create a process using CreateProcess() you can choose a HANDLE to which stdout and stderr are going to be written. 使用CreateProcess()创建进程时,可以选择要写入stdout和stderr的HANDLE This HANDLE can be a file to which you direct the output. HANDLE可以是您指向输出的文件。

This will let you use the code without recompiling it. 这将允许您使用代码而无需重新编译它。 Just execute it and instead of using system() or whatnot, use CreateProcess() . 只需执行它而不是使用system()或诸如此类的东西,使用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. 您为CreateProcess()提供的HANDLE也可以是您创建的管道的HANDLE,然后您可以从管道中读取并对数据执行其他操作。

You could do something like this with cout or cerr: 你可以用cout或cerr做这样的事情:

// open a file stream
ofstream out("filename");
// save cout's stream buffer
streambuf *sb = cout.rdbuf();
// point cout's stream buffer to that of the open file
cout.rdbuf(out.rdbuf());
// now you can print to file by writing to cout
cout << "Hello, world!";
// restore cout's buffer back
cout.rdbuf(sb);

Or, you can do that with a std::stringstream or some other class derived from std::ostream . 或者,您可以使用std::stringstream或从std::ostream派生的其他类来实现。

To redirect stdout, you'd need to reopen the file handle. 要重定向stdout,您需要重新打开文件句柄。 This thread has some ideas of this nature. 这个帖子有一些这种性质的想法。

Here we'll set a new entry point consoleMain that overrides your own one. 在这里,我们将设置一个新的入口点consoleMain ,它将覆盖您自己的入口点。

  1. Determine the entry point of your application. 确定应用程序的入口点。 In VisualStudio, select Project Properties/Linker/Advanced/Entry Point . 在VisualStudio中,选择“ 项目属性/链接器/高级/入口点” Let us call it defaultMain . 我们称之为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"以防止名称损坏。

     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, eg 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 ). consoleMain设置为新的入口点( 项目属性/链接器/高级/入口点 )。

This is what I'd do: 这就是我要做的:

  1. CreatePipe(). CreatePipe()。
  2. CreateProcess() with the handle from CreatePipe() used as stdout for the new process. 带有CreatePipe()句柄的CreateProcess(),用作新进程的stdout。
  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. 创建一个定时器或一个在该句柄上不时调用ReadFile()的线程,并将读取的数据放入文本框或诸如此类的东西中。

Thanks to the gamedev link in the answer by greyfade, I was able to write and test this simple piece of code 多亏了gamedev由greyfade答案的链接,我能够编写和测试这个简单的代码

AllocConsole();

*stdout = *_tfdopen(_open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), _O_WRONLY), _T("a"));
*stderr = *_tfdopen(_open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), _O_WRONLY), _T("a"));
*stdin = *_tfdopen(_open_osfhandle((intptr_t) GetStdHandle(STD_INPUT_HANDLE), _O_WRONLY), _T("r"));


printf("A printf to stdout\n");
std::cout << "A << to std::cout\n";
std::cerr << "A << to std::cerr\n";
std::string input;
std::cin >> input;

std::cout << "value read from std::cin is " << input << std::endl;

It works and is adequate for debugging. 它工作正常,足以进行调试。 Getting the text into a more attractive GUI element would take a bit more work. 将文本转换为更具吸引力的GUI元素需要更多的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从Windows 10中的UWP控制台应用程序访问输出到stdout? - How can I access output to stdout from a UWP console application in Windows 10? 我可以重定向两个子进程的stdout吗? - Can I redirect stdout for two sub processes? 如何从我的应用程序中更改“使显示器变暗”和“使显示器亮度变暗”设置(Windows)? - How can I change the “Dim the display” and “Dimming display brightness” setting (Windows) from wihin my application? Linux C++:如何在标准输出之外显示我的文本应用程序输出? - Linux C++: How do I display my Text application output outside of stdout? 如何将标准输出重定向到标准错误 - How to redirect stdout to stderr 如何在 Windows 应用程序中截取屏幕截图? - How can I take a screenshot in a windows application? CreateProcess:在C ++ / Windows中将子stdout重定向到父stdout - CreateProcess: redirect child stdout to parent stdout in C++/Windows 尝试在Windows上重定向stdout和stderr-_fileno(stdout)返回-2 - Trying to redirect stdout and stderr on Windows - _fileno(stdout) returning -2 Windows C ++:如何重定向stderr以调用fprintf? - Windows C++: How can I redirect stderr for calls to fprintf? 如何通过编程删除stdout中的字符? - How can I delete characters in stdout by programming?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM