Domanda

So che devo usare setconsolehandler() se voglio per gestire gli eventi di chiusura della console.

Non so come bloccare il CTRL_CLOSE_EVENT. Ho provato tornando falso / vero se le catture quell'evento, ma senza successo

Ecco quello che ho finora (grazie Anton Gogolev!)

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

public enum CtrlTypes{
    CTRL_C_EVENT = 0,
    CTRL_BREAK_EVENT,
    CTRL_CLOSE_EVENT,
    CTRL_LOGOFF_EVENT = 5,
    CTRL_SHUTDOWN_EVENT
}

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{ 
    if(ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
        return false;// I have tried true and false and viceversa with the return   
                     // true/false but I cant seem to get it right.
    return true;
}


//and then I use this to call it
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

Inoltre è possibile eseguire un nuovo thread per monitorare se la console si sta chiudendo e blocco che chiude se il thread principale è nel bel mezzo di fare qualcosa?

È stato utile?

Soluzione

La documentazione per SetConsoleCtrlHandler() dice:

  

Il sistema genera CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, e segnali CTRL_SHUTDOWN_EVENT quando l'utente chiude la console, si disconnette o spegne il sistema in modo che il processo ha l'opportunità di ripulire prima del termine.

Questo significa che a differenza di quando si maneggiano CTRL + C o CTRL + eventi si rompono, il processo non ottiene la possibilità di annullare la chiusura, disconnessione, o l'arresto.

Altri suggerimenti

In realtà si può bloccare esso (ho riprodotto questo su Windows XP, almeno). Per esempio, se nel vostro gestore di avere un infinito ciclo while con un sonno, questo sarà fermare questo processo da terminare per sempre (o almeno per un lungo periodo di tempo, o fino a quando l'utente uccide il processo attraverso il task manager).

Se davvero bisogno di avviare un thread, è possibile utilizzare una condizione di attesa (AutoResetEvent in C #) e iniziare la discussione (anche se un nuovo thread, probabilmente non è necessario nella maggior parte dei casi), quindi notificare la condizione di attesa quando il thread è finito. Tuttavia, solo fare qualsiasi pulizia nel gestore sarebbe sufficiente nella maggior parte dei casi.

Se nel peggiore dei casi avete fatto aspettare per sempre, il processo rimarranno in esecuzione e sarete in grado di vedere quando si accede indietro nel (almeno su Windows XP). Tuttavia, questo fa sì che il desktop per mettere in pausa per circa 20 secondi prima di andare alla schermata di logout (durante l'attesa per il vostro applicaiton per uscire), e poi si ferma di nuovo nella schermata di log out (suppongo mentre tenta per un 2 ° tempo) . Naturalmente, vi consiglio vivamente di non aspettare per sempre; per qualsiasi roba lunga corsa si dovrebbe davvero mettere questo in un servizio.

Ho trovato una possibile 'hackerare' che potrebbe impedire l'applicazione di chiusura, pur obbedendo perfettamente la console richiesta di chiusura. In particolare, questo è adatto, credo, per le applicazioni GUI che hanno creato una console come un 'extra'. Dalla documentazione MSDN, nel punto in cui il Ctrl Handler è chiamato un nuovo thread viene creato nel processo per chiamare il gestore. La mia soluzione, quindi, è quello di uccidere il filo assalto invasori prima che il gestore predefinito può chiamare ExitProcess. Nella routine di gestione (codice in C ++):

// Detach Console:
FreeConsole();
// Prevent closing:
ExitThread(0);
return TRUE; // Not reached

Modifica Sembra questo non causare alcuni problemi, come da aspettarsi suppongo. Una chiamata successiva a AllocConsole () si blocca a tempo indeterminato, così ho il sospetto che esce il filo non riesce prematuramente per ripulire correttamente.

EDIT 2:

Per chiarire sopra, ho trovato nessun problema con dirette continuando a eseguire il programma. Ma tenere a mente che abbiamo con forza terminato un filo che KERNEL32 ha creato, in modo da tutte le risorse all'interno kernel32 potrebbero essere in uno stato indeterminato. Questo potrebbe causare problemi imprevisti quando il programma continua a funzionare.

Per lo più, a mio avviso, questi problemi saranno correlati alle API Console. Come accennato, AllocConsole non riesce a lavorare da questo punto in poi (si bloccherà l'applicazione), in modo che il programma non può aprire una nuova console. E 'altamente possibile che le altre funzioni della console non riuscirà pure. In sostanza, qualsiasi cosa tu faccia da quel punto in poi che, in ogni modo (direttamente o indirettamente) chiama in kernel32 è soggetto a un comportamento indefinito, ma ho il sospetto che, in pratica, non ci saranno problemi al di fuori delle funzioni della console.

La mia conclusione è che si dovrebbe evitare questo metodo se a tutto il possibile, ma se cessazione anticipata è peggio, allora questo può essere pensato come una situazione di emergenza work-around, da utilizzare con parsimonia e con cautela.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top