2010-09-04 10 views
18

Sto scrivendo un'applicazione console in C++.Problema di routine SetConsoleCtrlHandler

Uso SetConsoleCtrlHandler per bloccare la chiusura e il tasto CTRL + C. Ciò consente a tutti i miei thread di fermarsi e uscire correttamente.

Uno dei thread esegue alcuni salvataggi che richiedono un po 'di tempo per il completamento e ho del codice da attendere nella routine di handle crtl della console. MSDN specifica che una finestra dovrebbe apparire dopo 5 secondi per CTRL_CLOSE_EVENT, ma invece il mio processo termina.

Questo è fastidioso per l'applicazione di debug della console anche quando il processo termina prima che tu possa passare e non so quale possa essere il problema (ho Windows 7 a 64 bit).

Inoltre, stranamente se la mia routine restituisce VERO (per disabilitare semplicemente l'azione di chiusura), chiude comunque l'applicazione. La routine viene chiamata, quindi SetConsoleCtrlHandler è stato installato correttamente.

es .:

BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType) 
{ 
    if (dwCtrlType == CTRL_CLOSE_EVENT) 
    { 
     return TRUE; 
    } 

    return FALSE; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    BOOL ret = SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE); 

    while (true) 
    { 
     Sleep(1000); 
    } 
    return 0; 
} 

Tutte le idee?

risposta

14

Sembra che non è più possibile ignorare le richieste stretti su Windows 7.

È fai ottenere l'evento CTRL_CLOSE_EVENT però, e da quel momento in poi, si arriva 10 secondi per fare tutto ciò che è necessario fare prima si chiude automaticamente. Quindi puoi fare tutto il lavoro che devi svolgere nel gestore o impostare una bandiera globale.

case CTRL_CLOSE_EVENT: // CTRL-CLOSE: confirm that the user wants to exit. 
         close_flag = 1; 
         while(close_flag != 2) 
         Sleep(100); 
         return TRUE; 

Una curiosità: Mentre il codice nel tuo evento CTRL_CLOSE_EVENT corre, il programma principale continua a correre. Quindi sarai in grado di controllare la bandiera e fare un 'close_flag = 2;' da qualche parte. Ma ricorda, hai solo 10 secondi. (Quindi tieni presente che non vuoi appendere il flusso del tuo programma principale in attesa sull'ingresso della tastiera, per esempio.)

+12

Il tempo di 10 secondi è solo metà della verità. L'applicazione verrà chiusa una volta restituito il gestore, quindi è necessario mantenere in esecuzione il gestore. –

+1

Si noti che il gestore viene eseguito nel contesto di un thread arbitrario (questa è la ragione per cui il programma continua a essere in esecuzione). Quindi è necessario utilizzare un meccanismo thread-safe per segnalare che la terminazione è in corso (ad esempio un evento). –

+0

Se il gestore restituisce false e il gestore predefinito viene chiamato, il processo viene chiuso tramite 'ExitProcess (STATUS_CONTROL_C_EXIT)'. Se il processo esce da solo prima di tornare, può utilizzare un codice di uscita diverso per indicare un arresto riuscito. Altrimenti, se il gestore restituisce true o richiede più di 5 secondi (non 10 secondi), il processo viene terminato forzatamente dal server di sessione (csrss.exe) con il codice di uscita 'STATUS_CONTROL_C_EXIT'. – eryksun

1

Stai rendendo questo più complicato di quanto dovrebbe essere. Non so esattamente il motivo per cui la vostra applicazione sta chiudendo, ma SetConsoleCtrlHandler(NULL, TRUE) dovrebbe fare ciò che si vuole:

http://msdn.microsoft.com/en-us/library/ms686016(VS.85).aspx

Se il parametro HandlerRoutine è NULL, un valore TRUE fa sì che il processo di chiamata di ignorare CTRL + C input e un valore FALSE ripristina l'elaborazione normale dell'ingresso CTRL + C.

+3

Ancora in uscita quando si preme il pulsante di chiusura sulla mia console.CTRL + C non è il problema in quanto fa anche il trucco e funziona: if (dwCtrlType == CTRL_C_EVENT) restituisce TRUE; È il pulsante di chiusura che mi sta causando problemi. – Jeremy

3

Ho il sospetto che questo è by-design su Windows 7 - se l'utente vuole uscire dalla tua applicazione, non ti è permesso dirgli "No".

+2

concordato. La finestra di dialogo che prima era visualizzata è gonzo. –

3

Il commento di Xavier è leggermente errato. Windows 7 consente il tuo codice nel gestore eventi ~ 10 secondi. Se non si è usciti dal gestore eventi in 10 secondi, si è terminato. Se si esce dal gestore eventi, si termina immediatamente. Il ritorno TRUE non pubblica una finestra di dialogo. È appena uscito.

3

Non è necessario attendere alcun flag dal thread principale, il gestore termina non appena il thread principale termina (o dopo 10 secondi).

BOOL WINAPI ConsoleHandler(DWORD dwType) 
{ 
    switch(dwType) { 
    case CTRL_CLOSE_EVENT: 
    case CTRL_LOGOFF_EVENT: 
    case CTRL_SHUTDOWN_EVENT: 

     set_done();//signal the main thread to terminate 

     //Returning would make the process exit! 
     //We just make the handler sleep until the main thread exits, 
     //or until the maximum execution time for this handler is reached. 
     Sleep(10000); 

     return TRUE; 
    default: 
     break; 
    } 
    return FALSE; 
} 
Problemi correlati