Ho un'applicazione, chiamiamola myapp.exe, che è console/GUI dual-mode, costruita come/SUBSYSTEM: WINDOWS (C'è un piccolo 3KB shim myapp.com per causare cmd.exe di attesa per visualizzare il nuovo prompt)Dove scrivere su stdout go quando lanciato da una shell cygwin, nessun reindirizzamento
Se io lancio dal prompt dei comandi:.
myapp
-> cmd.exe corre myapp.com che corre myapp. exe. stdout è inizialmente una console scollegata, utilizzandoAttachConsole
efreopen("CONOUT$", "w", stdout)
il mio output viene visualizzato nella casella di comando. OKmyapp.exe
-> cmd.exe visualizza il prompt troppo presto (problema noto), altrimenti uguale al precedente. Non è uno scenario di utilizzo normale.myapp > log
-> stdout è un file, l'utilizzo normale distd::cout
termina nel file. OK
Se io lancio da Windows Explorer:
myapp.com
- si crea> console, stdout è console, uscita va in console. Stesso risultato dell'uso di/SUBSYSTEM: CONSOLE per l'intero programma, tranne per il fatto che ho aggiunto una pausa quandomyapp.com
è l'unico processo nella console. Non è uno scenario di utilizzo normale.myapp.exe
-> stdout è un handle NULL, lo rileva e agganciarestd::cout
a una GUI. OK
Se io lancio da shell Matlab:
system('myapp')
osystem('myapp.com')
osystem('myapp.exe')
-> Per tutte e tre le varianti, stdout viene reindirizzato al MatLab. OK
Se io lancio da una shell bash cygwin:
./myapp.com
-> Proprio come lancio dalla cmd.exe, l'output viene visualizzato nella casella di comando. OK./myapp
-> (trova./myapp.exe
). Questo è il caso rotto. stdout è un handle non NULL ma l'output non va da nessuna parte. Questa è la situazione normale per eseguire il programma da bash e deve essere risolto!./myapp > log
-> Proprio come l'avvio da cmd.exe con il reindirizzamento dei file. OK./myapp | cat
-> Simile al reindirizzamento del file, ad eccezione dell'output nella finestra della console. OK
Qualcuno sa cosa set Cygwin come stdout quando si lancia un/SUBSYSTEM: WINDOWS processo e come posso legare std::cout
ad esso? O almeno dimmi come scoprire che tipo di maniglia torno da GetStdHandle(STD_OUTPUT_HANDLE)
?
Il mio programma è stato scritto con Visual C++ 2010, senza /clr
, nel caso ciò che conta in alcun modo. Il sistema operativo è Windows 7 a 64 bit.
MODIFICA: ulteriori informazioni richieste.
La variabile di ambiente CYGWIN è vuota (o inesistente).
GetFileType()
restituisce FILE_TYPE_UNKNOWN
. GetLastError()
restituisce 6 (ERROR_INVALID_HANDLE)
. Non importa se controllo prima o dopo aver chiamato AttachConsole()
.
Tuttavia, se semplicemente ignoro l'handle non valido e freopen("CONOUT$", "w", stdout)
, allora tutto funziona alla grande. Mi mancava semplicemente un modo per distinguere tra output della console (busted) e reindirizzamento dei file, e GetFileType()
a condizione che.
EDIT: codice finale:
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) */
}
}
È quello con la console Cygwin predefinita (avviata tramite la scorciatoia "Cygwin Bash Shell")? Hai qualcosa nella variabile d'ambiente CYGWIN, in particolare 'tty'? 'GetFileType()' può dirti che tipo di maniglia hai a che fare. – ak2
@ ak2: 'GetFileType' era solo il biglietto. Se rispondi, lo accetto. –
Ho avuto un comportamento simile usando cygwin in Console2, ma andava bene usando il collegamento "Cygwin64 Terminal". Console2 aveva il suo set di shell su 'C: \ cygwin64 \ bin \ zsh.exe --login -i -c" cd ~; exec/bin/zsh "' –