Tengo una aplicación, llamémosla myapp.exe, que es consola/GUI de modo dual, construida como/SUBSYSTEM: WINDOWS (Hay un pequeño 3KB myapp.com cuña para causar cmd.exe a esperar para mostrar la nueva petición)Donde se escribe en stdout cuando se lanza desde un shell cygwin, sin redirección
Si pongo en marcha de una línea de comandos:.
myapp
-> cmd.exe corre myapp.com que corre miaplicacion. exe. stdout es inicialmente una consola separada, usandoAttachConsole
yfreopen("CONOUT$", "w", stdout)
mi salida aparece en el cuadro de comando. OKmyapp.exe
-> cmd.exe muestra el mensaje demasiado pronto (problema conocido), de lo contrario igual que el anterior. No es un escenario de uso normal.myapp > log
-> stdout es un archivo, el uso normal destd::cout
termina en el archivo. Aceptar
Si lanzo desde Windows Explorer:
myapp.com
- se crea> consola, la salida estándar es la consola, la salida va en la consola. El mismo resultado que usar/SUBSYSTEM: CONSOLE para todo el programa, excepto que he agregado una pausa cuandomyapp.com
es el único proceso en la consola. No es un escenario de uso normal.myapp.exe
-> stdout es un controlador NULL, lo detecto y enganchostd::cout
en una GUI. Aceptar
Si pongo en marcha a partir de cáscara de Matlab:
system('myapp')
osystem('myapp.com')
osystem('myapp.exe')
-> Para las tres variantes, la salida estándar se canaliza a Matlab. Aceptar
Si pongo en marcha de un shell bash Cygwin:
./myapp.com
-> Al igual que el lanzamiento de cmd.exe, la salida aparece en el cuadro de mando. OK./myapp
-> (bash encuentra./myapp.exe
). Este es el caso roto. stdout es un controlador no NULL pero la salida no va a ninguna parte. ¡Esta es la situación normal para ejecutar el programa desde bash y necesita ser reparado!./myapp > log
-> Al igual que el inicio desde cmd.exe con la redirección de archivos. OK./myapp | cat
-> Similar a la redirección de archivos, excepto que la salida termina en la ventana de la consola. Aceptar
¿Alguien sabe lo que cygwin conjuntos como la salida estándar en el lanzamiento de un/SUBSISTEMA: proceso y procedimientos de Windows que se puede unir std::cout
a ella? ¿O al menos dime cómo averiguar qué tipo de identificador recibo de GetStdHandle(STD_OUTPUT_HANDLE)
?
Mi programa está escrito con Visual C++ 2010, sin /clr
, en caso de que importe de alguna manera. El sistema operativo es Windows 7 de 64 bits.
EDITAR: Se solicitó información adicional.
La variable de entorno CYGWIN está vacía (o no existe).
GetFileType()
devuelve FILE_TYPE_UNKNOWN
. GetLastError()
devuelve 6 (ERROR_INVALID_HANDLE)
. No importa si lo compruebo antes o después de llamar al AttachConsole()
.
Sin embargo, si simplemente ignoro el identificador no válido y freopen("CONOUT$", "w", stdout)
todo funciona bien. Me faltaba una manera de distinguir entre la salida de la consola (reventada) y la redirección de archivos, y GetFileType()
siempre que.
EDIT: código final:
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) */
}
}
¿Eso es con la consola Cygwin predeterminada (iniciada a través del acceso directo "Cygwin Bash Shell")? ¿Tiene algo en la variable de entorno CYGWIN, en particular 'tty'? 'GetFileType()' puede decirle qué tipo de manejador está tratando. – ak2
@ ak2: 'GetFileType' era solo el ticket. Si haces una respuesta, la aceptaré. –
Tuve un comportamiento similar usando cygwin en Console2, pero estaba bien usando el acceso directo "Cygwin64 Terminal". Console2 tenía su shell configurado en 'C: \ cygwin64 \ bin \ zsh.exe --login -i -c" cd ~; exec/bin/zsh "' –