2011-01-18 4 views
5

è possibile creare un programma che funziona come applicazione console se avviato dalla console e funziona come programma Windows (con GUI) se avviato diversamente?Problema console Win32

Se è possibile, come posso farlo?

riguarda Tobias

risposta

2

Se è necessario il programma per agire come un'applicazione di console (ad esempio, stampare le informazioni di utilizzo sulla console) è necessario compliant come un'applicazione console. Un'applicazione Windows non avrà accesso alla console e cmd.exe non aspetterà che finisca prima di stampare il prompt e accettare il comando successivo.

La soluzione migliore è disporre di due versioni, una per la riga di comando e una per la GUI (che gli utenti di solito eseguono tramite un collegamento sul desktop o dal menu Start).

Se si insiste sull'utilizzo di un singolo binario, è necessario vivere con una finestra della console visualizzata, almeno per un breve periodo. Si può sbarazzarsi della finestra della console utilizzando

FreeConsole(); 

Si può dire che l'applicazione è stato eseguito dalla GUI se è l'unico processo collegato alla console. È possibile utilizzare GetConsoleProcessList per trovare l'elenco dei processi collegati alla console.

+0

bella idea. Grazie. –

0

Il programma in sé non saprà mai come è stato avviato. A meno che non si sia disposti a passare argomenti di esecuzione al programma. Ad esempio: program.exe -GUI ... è possibile acquisire i parametri passati e decidere come deve essere eseguito il programma in base ai parametri passati.

vostro programma whould essere qualcosa del tipo:

class MainClass 
{ 
    public static int Main(string[] args) 
    { 
     // Test if input arguments were supplied: 
     if(args[0]=="GUI") 
      new myGUI().show(); //runs an instance of your gui 
     else 
      //you know what should go here 
    } 
} 
+2

si può controllare il processo genitore della shell comando per determinare se è stato avviato tramite cmd o altrimenti. Il problema principale è la finestra cmd che viene mostrata se il flag è impostato nell'intestazione pe. –

+0

È possibile nascondere la finestra di cmd. È possibile. – deadlock

+0

puoi controllare l'handle std con GetStartUpInfo. (http://msdn.microsoft.com/en-us/library/ms683230(v=vs.85).aspx) più la grande idea di Len's Holgate. quindi ti sbagli, ci sono modi. – Andrey

0

È possibile ordinare di indovinare se si sono avviati dalla console o no in questo modo:

CONSOLE_SCREEN_BUFFER_INFO csbi; 
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 
fConsole = csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y; 

E 'una supposizione - se il vostro la posizione del cursore non è 0,0 di quella di una console e può funzionare come un'app console. Altrimenti vai e crea le tue finestre.

Un altro modo per indovinare è guardare l'albero del processo e vedere quale processo ha avviato la tua app. Se è cmd.exe vai in modalità console, altrimenti vai in modalità GUI.

3

Se si imposta il programma come un programma GUI, è possibile tentare di collegarlo alla console utilizzando AttachConsole(). Si collega OK, si è avviato da una console e si può procedere a reindirizzare i propri handle standard alla console appena collegata.

In questo modo è possibile avviare e vedere se si è avviato da una console a cui è possibile collegarsi e in tal caso diventare un programma di console. Se non puoi allegare puoi mostrare una GUI.

Ho avuto un po 'di successo con questo, il problema principale che ho è la visualizzazione del prompt della finestra di comando quando il mio programma si chiude (che è come funzionano i normali programmi della console), ma mi aspetto che tu possa fare qualcosa di intelligente (leggi la console buffer all'avvio e trovare la richiesta di rivisualizzare quando si esce?) se si voleva davvero ...

+0

Utilizzare invece AllocConsole(). –

+0

Ma non creerai una nuova finestra console invece di connetterti al prompt dei comandi che ha lanciato la tua finestra della console? –

+0

Sì. Non esiste alcuna restrizione documentata sulla chiamata di 'AttachConsole' da un programma della GUI; non è solo l'impostazione predefinita. – MSalters

0

Ne fanno un'applicazione console e mettere questo nel codice:

void ConsoleWindowVisible(bool show) 
{ 
    DWORD dummy; 
    if 
    (
     !show && // Trying to hide 
     GetConsoleProcessList(&dummy, 1) == 1 // Have our own console window 
    ) 
     ShowWindow(GetConsoleWindow, SW_HIDE); // Hide the window 
    else // Trying to show or use parent console window 
     ShowWindow(GetConsoleWindow, SW_NORMAL); // Show the window 
} 

int main(int argc, char** argv) 
{ 
    ConsoleWindowVisible(false); 
} 

Cin cin.

[email protected]

0

Questa è la risposta di Dan Tillett ed è notevolmente efficace. Niente flash, niente .com e .exe per ingannare cmd.exe. Sembra funzionare in modo impeccabile digitando il comando, in un file .bat, con lo stato attivo, senza messa a fuoco e come applicazione con doppio clic sull'interfaccia grafica.

Sono le api le ginocchia!

Questa è la pagina web che la descrive, ma l'ho postata qui perché se quella pagina diventasse 404 il mese prossimo o 2 anni da oggi, la soluzione eccellente e "più completa" che ho visto sarebbe "fuori dalla rete" ".

http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/

#define WINVER 0x0501 // Allow use of features specific to Windows XP or later. 
#define _WIN32_WINNT 0x0501 
#define WIN32_LEAN_AND_MEAN 
#include <windows.h> 
#include <io.h> 
#include <fcntl.h> 
#include <stdio.h> 
#pragma comment(lib, "User32.lib") 

// Attach output of application to parent console 
static BOOL attachOutputToConsole(void) { 
HANDLE consoleHandleOut, consoleHandleError; 
int fdOut, fdError; 
FILE *fpOut, *fpError; 

if (AttachConsole(ATTACH_PARENT_PROCESS)) { 
    //redirect unbuffered STDOUT to the console 
    consoleHandleOut = GetStdHandle(STD_OUTPUT_HANDLE); 
    fdOut = _open_osfhandle((intptr_t)consoleHandleOut, _O_TEXT); 
    fpOut = _fdopen(fdOut, "w"); 
    *stdout = *fpOut; 
    setvbuf(stdout, NULL, _IONBF, 0); 

    //redirect unbuffered STDERR to the console 
    consoleHandleError = GetStdHandle(STD_ERROR_HANDLE); 
    fdError = _open_osfhandle((intptr_t)consoleHandleError, _O_TEXT); 
    fpError = _fdopen(fdError, "w"); 
    *stderr = *fpError; 
    setvbuf(stderr, NULL, _IONBF, 0); 

    return TRUE; 
    } 
//Not a console application 
return FALSE; 
} 

//Send the "enter" to the console to release the command prompt on the parent console 
static void sendEnterKey(void) { 
INPUT ip; 
// Set up a generic keyboard event. 
ip.type = INPUT_KEYBOARD; 
ip.ki.wScan = 0; // hardware scan code for key 
ip.ki.time = 0; 
ip.ki.dwExtraInfo = 0; 

//Send the "Enter" key 
ip.ki.wVk = 0x0D; // virtual-key code for the "Enter" key 
ip.ki.dwFlags = 0; // 0 for key press 
SendInput(1, &ip, sizeof(INPUT)); 

// Release the "Enter" key 
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release 
SendInput(1, &ip, sizeof(INPUT)); 
} 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) { 
int argc = __argc; 
char **argv = __argv; 
UNREFERENCED_PARAMETER(hInstance); 
UNREFERENCED_PARAMETER(hPrevInstance); 
UNREFERENCED_PARAMETER(lpCmdLine); 
UNREFERENCED_PARAMETER(nCmdShow); 
BOOL console; 
int i; 

//Is the program running as console or GUI application 
console = attachOutputToConsole(); 

if (console) { 
    //Print to stdout 
    printf("Program running as console application\n"); 
    for (i = 0; i < argc; i++) { 
     printf("argv[%d] %s\n", i, argv[i]); 
     } 

    //Print to stderr 
    fprintf(stderr, "Output to stderr\n"); 
    } 
else { 
    MessageBox(NULL, "Program running as windows gui application", 
    "Windows GUI Application", MB_OK | MB_SETFOREGROUND); 
} 

//Send "enter" to release application from the console 
//This is a hack, but if not used the console doesn't know the application has returned 
//"enter" only sent if the console window is in focus 
if (console && GetConsoleWindow() == GetForegroundWindow()){ 
    sendEnterKey(); 
    } 
return 0; 
}