У меня есть приложение, назовем его myapp.exe, который представляет собой двухрежимную консоль / GUI, построенную как / SUBSYSTEM: WINDOWS (есть небольшая 3-килобайтная шайба myapp.com, заставляющая cmd.exe ждать, пока не отобразится новый подскажите.)
Если я запускаю из командной строки:
myapp
-> cmd.exe запускает myapp.com, который запускает myapp.exe. Первоначально стандартный вывод - это отдельная консоль, при использовании AttachConsole
и freopen("CONOUT$", "w", stdout)
мой вывод появляется в окне команд. OK
myapp.exe
-> cmd.exe отображает приглашение слишком рано (известная проблема), в остальном то же, что и предыдущий. Не обычный сценарий использования.
myapp > log
-> stdout - это файл, обычное использование std::cout
заканчивается в файле. OK
Если я запускаю из проводника Windows:
myapp.com
-> консоль создана, stdout - консоль, вывод - в консоль. Результат такой же, как при использовании / SUBSYSTEM: CONSOLE для всей программы, за исключением того, что я добавил паузу, когда myapp.com
- единственный процесс в консоли. Не обычный сценарий использования.
myapp.exe
-> stdout - это дескриптор NULL, я обнаруживаю это и подключаю std::cout
к GUI. OK
Если я запускаю из оболочки Matlab:
system('myapp')
или system('myapp.com')
или system('myapp.exe')
-> Для всех трех вариантов стандартный вывод передается в MatLab. OK
Если я запускаю из оболочки Cygwin Bash:
./myapp.com
-> Так же, как запуск из cmd.exe, вывод появляется в командной строке. OK
./myapp
-> (bash находит ./myapp.exe
). Это сломанный случай . stdout - это ненулевой дескриптор, но вывод идет в никуда. Это нормальная ситуация для запуска программы из bash, которую необходимо исправить!
./myapp > log
-> Так же, как запуск из cmd.exe с перенаправлением файла. OK
./myapp | cat
-> Аналогично перенаправлению файла, за исключением того, что вывод заканчивается в окне консоли. OK
Кто-нибудь знает, что cygwin устанавливает как стандартный вывод при запуске процесса / SUBSYSTEM: WINDOWS и как я могу связать std::cout
с ним? Или, по крайней мере, скажите мне, как узнать, какую ручку я получаю от GetStdHandle(STD_OUTPUT_HANDLE)
?
Моя программа написана с использованием Visual C ++ 2010, без /clr
, на случай, если это имеет какое-либо значение. ОС Windows 7 64-битная.
РЕДАКТИРОВАТЬ: запрашивается дополнительная информация.
Переменная окружения CYGWIN пуста (или не существует).
GetFileType()
возвращает FILE_TYPE_UNKNOWN
. GetLastError()
возвращает 6 (ERROR_INVALID_HANDLE)
. Неважно, проверяю ли я до или после звонка AttachConsole()
.
Однако, если я просто игнорирую неверный дескриптор и freopen("CONOUT$", "w", stdout)
, тогда все работает отлично. Мне просто не хватало способа различить (отключенный) вывод консоли и перенаправление файлов, и GetFileType()
при условии, что.
РЕДАКТИРОВАТЬ: окончательный код:
bool is_console(HANDLE h)
{
if (!h) return false;
::AttachConsole(ATTACH_PARENT_PROCESS);
if (FILE_TYPE_UNKNOWN == ::GetFileType(h) && ERROR_INVALID_HANDLE == GetLastError()) {
/* workaround cygwin brokenness */
h = ::CreateFile(_T("CONOUT$"), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h) {
::CloseHandle(h);
return true;
}
}
CONSOLE_FONT_INFO cfi;
return ::GetCurrentConsoleFont(h, FALSE, &cfi) != 0;
}
bool init( void )
{
HANDLE out = ::GetStdHandle(STD_OUTPUT_HANDLE);
if (out) {
/* stdout exists, might be console, file, or pipe */
if (is_console(out)) {
#pragma warning(push)
#pragma warning(disable: 4996)
freopen("CONOUT$", "w", stdout);
#pragma warning(pop)
}
//std::stringstream msg;
//DWORD result = ::GetFileType(out);
//DWORD lasterror = ::GetLastError();
//msg << result << std::ends;
//::MessageBoxA(NULL, msg.str().c_str(), "GetFileType", MB_OK);
//if (result == FILE_TYPE_UNKNOWN) {
// msg.str(std::string());
// msg << lasterror << std::ends;
// ::MessageBoxA(NULL, msg.str().c_str(), "GetLastError", MB_OK);
//}
return true;
}
else {
/* no text-mode stdout, launch GUI (actual code removed) */
}
}