Ответ 1
Функция GetFileType() позволяет различать некоторые типы дескрипторов, в частности консолей, труб, файлов и сломанных дескрипторов.
У меня есть приложение, позвольте мне его myapp.exe, который представляет собой двухрежимную консоль/графический интерфейс, построенный как /SUBSYSTEM: WINDOWS (там крошечный 3KB shim myapp.com, чтобы заставить cmd.exe ждать, чтобы отобразить новое строка.)
Если я запускаю из командной строки:
myapp
→ cmd.exe запускает myapp.com, который запускает myapp.exe. Сначала stdout представляет собой отдельную консоль, используя AttachConsole
и freopen("CONOUT$", "w", stdout)
мой вывод появляется в поле команды. OKmyapp.exe
→ cmd.exe отображает подсказку слишком рано (известная проблема), в противном случае она аналогична предыдущей. Не обычный сценарий использования.myapp > log
→ stdout - это файл, нормальное использование std::cout
заканчивается в файле. OKЕсли я запускаю из проводника Windows:
myapp.com
→ консоль создана, stdout - консоль, вывод идет в консоль. Тот же результат, что и использование /SUBSYSTEM: CONSOLE для всей программы, за исключением того, что я добавил паузу, когда myapp.com
- единственный процесс в консоли. Не обычный сценарий использования.myapp.exe
→ stdout является дескриптором NULL, я обнаруживаю это и привязываю std::cout
к графическому интерфейсу. OKЕсли я запускаю из оболочки Matlab:
system('myapp')
или system('myapp.com')
или system('myapp.exe')
→ Для всех трех вариантов stdout передается по каналу в MatLab. OKЕсли я запускаю из оболочки cygwin bash:
./myapp.com
→ Как и запуск из cmd.exe, вывод появляется в поле команды. OK./myapp
→ (bash находит ./myapp.exe
). Это сломанный случай. stdout - это не-NULL-дескриптор, но выход не проходит. Это нормальная ситуация для запуска программы из bash и ее необходимо исправлять!./myapp > log
→ Также как запуск из cmd.exe с перенаправлением файлов. OK./myapp | cat
→ Аналогично перенаправлению файлов, кроме вывода в окне консоли. OKКто-нибудь знает, что cygwin устанавливает как stdout при запуске процесса /SUBSYSTEM: WINDOWS и как я могу привязать к нему std::cout
? Или, по крайней мере, скажите мне, как узнать, какую ручку я получаю от GetStdHandle(STD_OUTPUT_HANDLE)
?
Моя программа написана с Visual С++ 2010 без /clr
, в случае, если это имеет значение. ОС - 64-разрядная версия Windows 7.
EDIT: запрошена дополнительная информация.
Переменная среды CYGWIN пуста (или не существует).
GetFileType()
возвращает FILE_TYPE_UNKNOWN
. GetLastError()
возвращает 6 (ERROR_INVALID_HANDLE)
. Неважно, проверяю ли я до или после вызова AttachConsole()
.
Однако, если я просто игнорирую недействительный дескриптор и freopen("CONOUT$", "w", stdout)
, тогда все отлично работает. Мне просто не хватало возможности различать (выгруженный) вывод консоли и перенаправление файлов, а GetFileType()
при условии, что.
EDIT: Конечный код:
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) */
}
}
Функция GetFileType() позволяет различать некоторые типы дескрипторов, в частности консолей, труб, файлов и сломанных дескрипторов.