Windows 응용 프로그램에서 보이는 디스플레이로 stdout을 리디렉션하려면 어떻게 해야 합니까?
"좋은 일"을 하는 타사 라이브러리에 액세스할 수 있습니다.stdout에 상태 및 진행률 메시지를 발행합니다.콘솔 응용 프로그램에서 이러한 메시지를 볼 수 있습니다.Windows 애플리케이션에서는 비트 버킷으로 이동합니다.
stdout 및 stderr를 텍스트 컨트롤 또는 다른 보이는 위치로 리디렉션하는 상당히 간단한 방법이 있습니까?이상적으로는 타사 코드의 재컴파일이 필요하지 않습니다.그것은 낮은 수준에서 증기를 차단할 것입니다.헤더를 #포함하고 초기화 함수를 호출하여 라이브러리를 링크하는 솔루션을 원합니다.
#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";
}
특정 GUI 라이브러리에 연결되지 않도록 오버라이드할 수 있는 인터페이스를 사용한다면 더욱 좋을 것입니다.
class StdFilesRedirector
{
public:
writeStdout(std::string const& message) = 0;
writeStderr(std::string const& errorMessage) = 0;
readStdin(std::string &putReadStringHere) = 0;
};
나는 그냥 꿈을 꾸고 있는 건가요?아니면 이런 일을 할 수 있는 것을 아는 사람이 있습니까?
두 개의 답변 뒤에 편집:freopen을 사용하여 파일을 리디렉션하는 것이 좋은 첫 단계라고 생각합니다.전체 솔루션을 사용하려면 파일을 읽고 출력을 표시하기 위해 새 스레드가 생성되어야 합니다.디버깅의 경우, cygwin 쉘 창에서 'tail-f'를 수행하면 충분할 것입니다.좀 더 세련된 응용을 위해서는제가 쓰고 싶은 것은...스레드를 만드는 등 추가 작업이 있을 것입니다.
파이프를 만든 다음(CreatePipe()를 사용하여) SetStdHandle()을 사용하여 파이프의 쓰기 끝에 stdout을 연결한 다음 ReadFile()을 사용하여 파이프의 읽기 끝에서 읽고 원하는 위치에 텍스트를 넣을 수 있습니다.
freopen을 사용하여 stdout, stderr 및 stdin을 리디렉션할 수 있습니다.
위 링크에서:
/* 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;
}
다음과 같은 명령 프롬프트를 통해 프로그램을 실행할 수도 있습니다.
a.exe > stdout.txt 2> stderr.txt
당신은 아마도 다음과 같은 것을 찾고 있을 것입니다.
#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;
}
이 클래스는 다음 작업을 수행합니다.
#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;
}
결과는 다음과 같습니다.
1: stdout
3: stdout
5: stdout
Redirected outputs:
2: redirected stdout
4: redirected stdout
CreateProcess()를 사용하여 프로세스를 생성할 때 다음을 선택할 수 있습니다.HANDLE
될 .stdout과 stderr이 됩니다. 것이.HANDLE
출력을 지시하는 파일일 수 있습니다.
이렇게 하면 코드를 다시 컴파일하지 않고 사용할 수 있습니다.사용하지 않고 실행하기만 하면 됩니다.system()
또는 무엇을 사용하지 않음CreateProcess()
.
이 주핸들는에게 .CreateProcess()
작성한 파이프의 파이프일 수도 있습니다. 그런 다음 파이프에서 데이터를 읽고 다른 작업을 수행할 수 있습니다.
당신은 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);
아니면, 당신은 그것을 할 수 있습니다.std::stringstream
또는 에서 파생된 다른 클래스.std::ostream
.
stdout을 리디렉션하려면 파일 핸들을 다시 열어야 합니다.이 실은 이런 종류의 아이디어를 가지고 있습니다.
제가 할 일은 다음과 같습니다.
- 파이프를 만듭니다.
- 새 프로세스에 대한 stdout으로 사용된 CreatePipe()의 핸들을 사용하여 CreateProcess().
- 때때로 해당 핸들에서 ReadFile()을 호출하고 읽은 데이터를 텍스트 상자에 넣는 타이머나 스레드를 만듭니다.
여기서 새로운 진입점을 설정합니다.consoleMain
당신 자신의 것을 무시합니다.
- 응용프로그램의 시작 지점을 결정합니다.Visual Studio에서 Project Properties/Linker/Advanced/Entry Point를 선택합니다.끝내자꾸나
defaultMain
. 원본 코드의 어딘가에서 원래 진입점(체인으로 연결할 수 있도록)과 새 진입점을 선언합니다.둘 다 선언해야 합니다.
extern "C"
이름의 망글링을 방지하기 위해.extern "C" { int defaultMain (void); int consoleMain (void); }
진입점 기능을 구현합니다.
__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(); }
예를 들어 버튼 클릭 동작에서 테스트 코드를 추가합니다.
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);
- 세트
consoleMain
새 진입점(프로젝트 속성/링커/고급/진입점)으로 지정합니다.
그레이페이드의 답변에 있는 게임 개발 링크 덕분에, 저는 이 간단한 코드 조각을 쓰고 테스트할 수 있었습니다.
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;
작동하며 디버깅에 적합합니다.텍스트를 더 매력적인 GUI 요소로 전환하려면 작업이 조금 더 필요합니다.
언급URL : https://stackoverflow.com/questions/573724/how-can-i-redirect-stdout-to-some-visible-display-in-a-windows-application
'programing' 카테고리의 다른 글
Android - 사용자 지정 글꼴 사용 (0) | 2023.09.05 |
---|---|
match()를 사용하여 ()에 대해 Mariadb 쿼리의 메모리가 부족합니다. (0) | 2023.08.26 |
텍스트 보기에서 글꼴을 변경하는 방법은 무엇입니까? (0) | 2023.08.26 |
MySQL: 이번 주 기록을 어떻게 선택합니까? (0) | 2023.08.26 |
아무것도 찾을 수 없을 때 예외를 던지지 않는 파이썬용 list.index() 함수 (0) | 2023.08.26 |