2010-10-26 5 views
14

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, utilizzando AttachConsole e freopen("CONOUT$", "w", stdout) il mio output viene visualizzato nella casella di comando. OK
  • myapp.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 di std::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 quando myapp.com è l'unico processo nella console. Non è uno scenario di utilizzo normale.
  • myapp.exe -> stdout è un handle NULL, lo rileva e agganciare std::cout a una GUI. OK

Se io lancio da shell Matlab:

  • system('myapp') o system('myapp.com') o system('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) */ 
    } 
} 
+0

È 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

+0

@ ak2: 'GetFileType' era solo il biglietto. Se rispondi, lo accetto. –

+0

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 "' –

risposta

3

La funzione GetFileType() permette di distinguere tra alcuni tipi di maniglie, in particolare le console, i tubi, i file e le maniglie rotte.

Problemi correlati