Если у меня есть встроенная программа Windows С++ (т.е. точка входа WinMain), как я могу просмотреть вывод из функций консоли, таких как std:: cout?
Как получить консольный вывод в С++ с помощью программы Windows?
Ответ 1
Посмотрите, как добавить консольный ввод/вывод в приложение Win32 GUI. Это может помочь вам сделать то, что вы хотите.
Если у вас нет или вы не можете изменить код, попробуйте советы, найденные здесь, чтобы перенаправить вывод консоли в файл.
Редактировать: немного нить некромантии здесь. Я впервые ответил на это 9 лет назад, в первые дни SO, до того, как (хорошая) политика ответов, не связанных только с ссылками, вступила в силу. Я перепишу код из оригинальной статьи в надежде искупить мои прошлые грехи.
guicon.cpp - функция перенаправления консоли
#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <fstream>
#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif
// maximum mumber of lines the output console should have
static const WORD MAX_CONSOLE_LINES = 500;
#ifdef _DEBUG
void RedirectIOToConsole()
{
int hConHandle;
long lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;
// allocate a console for this app
AllocConsole();
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console
lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
// redirect unbuffered STDERR to the console
lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf( stderr, NULL, _IONBF, 0 );
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
// point to console as well
ios::sync_with_stdio();
}
#endif
//End of File
guicon.h - интерфейс к функции перенаправления консоли
#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG
void RedirectIOToConsole();
#endif
#endif
// End of File
test.cpp - демонстрация перенаправления консоли
#include <windows.h>
#include <iostream>
#include <fstream>
#include <conio.h>
#include <stdio.h>
#ifndef _USE_OLD_OSTREAMS
using namespace std;
#endif
#include "guicon.h"
#include <crtdbg.h>
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
#ifdef _DEBUG
RedirectIOToConsole();
#endif
int iVar;
// test stdio
fprintf(stdout, "Test output to stdout\n");
fprintf(stderr, "Test output to stderr\n");
fprintf(stdout, "Enter an integer to test stdin: ");
scanf("%d", &iVar);
printf("You entered %d\n", iVar);
//test iostreams
cout << "Test output to cout" << endl;
cerr << "Test output to cerr" << endl;
clog << "Test output to clog" << endl;
cout << "Enter an integer to test cin: ";
cin >> iVar;
cout << "You entered " << iVar << endl;
#ifndef _USE_OLD_IOSTREAMS
// test wide iostreams
wcout << L"Test output to wcout" << endl;
wcerr << L"Test output to wcerr" << endl;
wclog << L"Test output to wclog" << endl;
wcout << L"Enter an integer to test wcin: ";
wcin >> iVar;
wcout << L"You entered " << iVar << endl;
#endif
// test CrtDbg output
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
_RPT0(_CRT_WARN, "This is testing _CRT_WARN output\n");
_RPT0(_CRT_ERROR, "This is testing _CRT_ERROR output\n");
_ASSERT( 0 && "testing _ASSERT" );
_ASSERTE( 0 && "testing _ASSERTE" );
Sleep(2000);
return 0;
}
//End of File
Ответ 2
Вы также можете снова открыть потоки cout и cerr для вывода в файл. Для этого необходимо:
#include <iostream>
#include <fstream>
int main ()
{
std::ofstream file;
file.open ("cout.txt");
std::streambuf* sbuf = std::cout.rdbuf();
std::cout.rdbuf(file.rdbuf());
//cout is now pointing to a file
return 0;
}
Ответ 3
Используя комбинацию ответа luke и ответ Роджера здесь, работал у меня в моем проекте Windows Desktop Application.
void RedirectIOToConsole() {
//Create a console for this application
AllocConsole();
// Get STDOUT handle
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
int SystemOutput = _open_osfhandle(intptr_t(ConsoleOutput), _O_TEXT);
FILE *COutputHandle = _fdopen(SystemOutput, "w");
// Get STDERR handle
HANDLE ConsoleError = GetStdHandle(STD_ERROR_HANDLE);
int SystemError = _open_osfhandle(intptr_t(ConsoleError), _O_TEXT);
FILE *CErrorHandle = _fdopen(SystemError, "w");
// Get STDIN handle
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
int SystemInput = _open_osfhandle(intptr_t(ConsoleInput), _O_TEXT);
FILE *CInputHandle = _fdopen(SystemInput, "r");
//make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
ios::sync_with_stdio(true);
// Redirect the CRT standard input, output, and error handles to the console
freopen_s(&CInputHandle, "CONIN$", "r", stdin);
freopen_s(&COutputHandle, "CONOUT$", "w", stdout);
freopen_s(&CErrorHandle, "CONOUT$", "w", stderr);
//Clear the error state for each of the C++ standard stream objects. We need to do this, as
//attempts to access the standard streams before they refer to a valid target will cause the
//iostream objects to enter an error state. In versions of Visual Studio after 2005, this seems
//to always occur during startup regardless of whether anything has been read from or written to
//the console or not.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
}
Ответ 4
создание канала, выполнение программной консоли CreateProcess() и чтение с помощью ReadFile() или запись на консоль WriteFile()
HANDLE hRead ; // ConsoleStdInput
HANDLE hWrite; // ConsoleStdOutput and ConsoleStdError
STARTUPINFO stiConsole;
SECURITY_ATTRIBUTES segConsole;
PROCESS_INFORMATION priConsole;
segConsole.nLength = sizeof(segConsole);
segConsole.lpSecurityDescriptor = NULL;
segConsole.bInheritHandle = TRUE;
if(CreatePipe(&hRead,&hWrite,&segConsole,0) )
{
FillMemory(&stiConsole,sizeof(stiConsole),0);
stiConsole.cb = sizeof(stiConsole);
GetStartupInfo(&stiConsole);
stiConsole.hStdOutput = hWrite;
stiConsole.hStdError = hWrite;
stiConsole.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
stiConsole.wShowWindow = SW_HIDE; // execute hide
if(CreateProcess(NULL, "c:\\teste.exe",NULL,NULL,TRUE,NULL,
NULL,NULL,&stiConsole,&priConsole) == TRUE)
{
//readfile and/or writefile
}
}
Ответ 5
Если вы отправляете вывод своей программы в файл или канал, например
myprogram.exe > file.txt
myprogram.exe | anotherprogram.exe
или вы вызываете свою программу из другой программы и записываете ее вывод через канал, тогда вам ничего не нужно менять. Он будет работать, даже если точка входа WinMain
.
Однако, если вы запускаете свою программу на консоли или в Visual Studio, то вывод не будет отображаться в консоли или в окне вывода Visual Studio. Если вы хотите увидеть выход "live", попробуйте один из других ответов.
В основном это означает, что стандартный вывод работает так же, как с консольными приложениями, но он не подключен к консоли, в которой вы запускаете приложение, и, похоже, нет простого способа сделать это (все остальные решения представленный здесь, подключите вывод к новому консольному окну, который появится при запуске приложения, даже с другой консоли).
Ответ 6
Не цитируйте меня на этом, но Win32 консольный API может быть тем, что вы ищете. Однако, если вы просто делаете это для целей отладки, вам может быть интереснее запустить DebugView и вызвать DbgPrint.
Это, конечно, предполагает, что ваше приложение вы хотите отправить консольный вывод, а не читать его из другого приложения. В этом случае трубы могут быть вашим другом.
Ответ 7
Перейдите в Project > Project Properties > Linker > System и в правой панели установите SubSystems вариант Консоль (/SUBSYSTEM: CONSOLE)
Затем скомпилируйте свою программу и запустите ее с консоли, чтобы узнать, выводит ли командная строка ваши выходы или нет.
Ответ 8
На самом деле, существует гораздо более простое решение, чем любое предложенное до сих пор. Ваша программа для Windows будет иметь функцию WinMain, поэтому просто добавьте эту "фиктивную" основную функцию
int main()
{
return WinMain(GetModuleHandle(NULL), NULL, GetCommandLineA(), SW_SHOWNORMAL);
}
Теперь вы можете скомпилировать с помощью MSVC, как это
cl /nologo /c /EHsc myprog.c
link /nologo /out:myprog.exe /subsystem:console myprog.obj user32.lib gdi32.lib
(вам может понадобиться добавить дополнительные библиотечные ссылки)
При запуске программы любой printf
будет записан в командную строку.
Если вы используете gcc (mingw) для компиляции для Windows, вам не нужна фиктивная основная функция, просто сделайте
gcc -o myprog.exe myprog.c -luser32 -lgdi32
(т.е. избегайте использования флага -mwindows
который предотвратит запись в консоль. Этот флаг будет полезен при создании окончательного выпуска GUI) Снова вам может потребоваться указать больше библиотек, если вы используете больше возможностей Windows)
Ответ 9
Сегодня провел весь день, пытаясь заставить это работать правильно. Нашли ответы по всему Интернету, похожие на Люка и Сева.
Метод работает, но проблема возникает, когда я FreeConsole
из консоли, либо вызывая FreeConsole
либо просто нормально завершая работу приложения. В режиме отладки я вижу отладочные утверждения о недопустимых дескрипторах файлов в коде очистки CRT.
Я думаю, что проблема вызвана частично чрезмерно сложным процессом перенаправления, который используют все, и частично потому, что стандартные потоки ввода-вывода не перенаправляются перед выходом.
Я вообще не понимаю необходимости использовать _open_osfhandle
и _fdopen
в этом процессе.
Это полное решение, которое работает для меня:
Перенаправление консоли стандартного ввода-вывода:
bool RedirectConsoleIO()
{
bool result = true;
FILE* fp;
// Redirect STDIN if the console has an input handle
if (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)
if (freopen_s(&fp, "CONIN$", "r", stdin) != 0)
result = false;
else
setvbuf(stdin, NULL, _IONBF, 0);
// Redirect STDOUT if the console has an output handle
if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE)
if (freopen_s(&fp, "CONOUT$", "w", stdout) != 0)
result = false;
else
setvbuf(stdout, NULL, _IONBF, 0);
// Redirect STDERR if the console has an error handle
if (GetStdHandle(STD_ERROR_HANDLE) != INVALID_HANDLE_VALUE)
if (freopen_s(&fp, "CONOUT$", "w", stderr) != 0)
result = false;
else
setvbuf(stderr, NULL, _IONBF, 0);
// Make C++ standard streams point to console as well.
ios::sync_with_stdio(true);
// Clear the error state for each of the C++ standard streams.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
return result;
}
Выпуск Консоли:
bool ReleaseConsole()
{
bool result = true;
FILE* fp;
// Just to be safe, redirect standard IO to NUL before releasing.
// Redirect STDIN to NUL
if (freopen_s(&fp, "NUL:", "r", stdin) != 0)
result = false;
else
setvbuf(stdin, NULL, _IONBF, 0);
// Redirect STDOUT to NUL
if (freopen_s(&fp, "NUL:", "w", stdout) != 0)
result = false;
else
setvbuf(stdout, NULL, _IONBF, 0);
// Redirect STDERR to NUL
if (freopen_s(&fp, "NUL:", "w", stderr) != 0)
result = false;
else
setvbuf(stderr, NULL, _IONBF, 0);
// Detach from console
if (!FreeConsole() || !result)
return false;
return true;
}
Изменение размера консольного буфера:
void AdjustConsoleBuffer(int16_t minLength)
{
// Set the screen buffer to be big enough to scroll some text
CONSOLE_SCREEN_BUFFER_INFO conInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo);
if (conInfo.dwSize.Y < minLength)
conInfo.dwSize.Y = minLength;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize);
}
Выделение новой консоли:
bool CreateNewConsole(int16_t minLength)
{
bool result = false;
// Release any current console and redirect IO to NUL
ReleaseConsole();
// Attempt to create new console
if (AllocConsole())
{
AdjustConsoleBuffer(minLength);
result = RedirectConsoleIO();
}
return result;
}
Присоединение к родительской консоли:
bool AttachParentConsole(int16_t minLength)
{
bool result = false;
// Release any current console and redirect IO to NUL
ReleaseConsole();
// Attempt to attach to parent process console
if (AttachConsole(ATTACH_PARENT_PROCESS))
{
AdjustConsoleBuffer(minLength);
result = RedirectConsoleIO();
}
return result;
}
Звонок из WinMain:
Связь с /SUBSYSTEM:Windows
int APIENTRY WinMain(
HINSTANCE /*hInstance*/,
HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/,
int /*cmdShow*/)
{
if (CreateNewConsole(1024))
{
int i;
// test stdio
fprintf(stdout, "Test output to stdout\n");
fprintf(stderr, "Test output to stderr\n");
fprintf(stdout, "Enter an integer to test stdin: ");
scanf("%d", &i);
printf("You entered %d\n", i);
// test iostreams
cout << "Test output to cout" << endl;
cerr << "Test output to cerr" << endl;
clog << "Test output to clog" << endl;
cout << "Enter an integer to test cin: ";
cin >> i;
cout << "You entered " << i << endl;
std::cout << endl << "Press any key to continue..." << endl;
_getch();
ReleaseConsole();
}
return 0;
};
Ответ 10
Поскольку нет консольного окна, это невозможно сложно. (Узнайте что-то новое каждый день - я никогда не знал о функциях консоли!)
Возможно ли заменить ваши выходные вызовы? Я часто использую TRACE или OutputDebugString для отправки информации в окно вывода Visual Studio.
Ответ 11
Как уже упоминалось там и там самое простое решение заключается в использовании вашего проекта Страницы свойств переключаться назад и вперед между CONSOLE
и WINDOWS
SubSytems, чтобы включить или выключить вывод на консоль по собственному желанию.
Вашей программе просто потребуются точки входа main
и WinMain
чтобы убедиться, что обе конфигурации компилируются. main
функция просто вызывает WinMain
как показано ниже, например:
int main()
{
cout << "Output standard\n";
cerr << "Output error\n";
return WinMain(GetModuleHandle(NULL), NULL, GetCommandLineA(), SW_SHOWNORMAL);
}