2010-09-04 9 views
18

Escribo una aplicación de consola en C++.Problema de rutina SetConsoleCtrlHandler

Uso SetConsoleCtrlHandler para capturar cerca y CTRL + botón C. Esto permite que todos mis hilos se detengan y salgan correctamente.

Uno de los subprocesos realiza algunos ahorros que requieren algo de tiempo para completarse y tengo un código para esperar en la rutina de manejo de consola crtl. MSDN especifica que debe aparecer un cuadro después de 5 segundos para CTRL_CLOSE_EVENT, pero en su lugar mi proceso se cierra.

Esto también es molesto para la aplicación de la consola de depuración, ya que el proceso finaliza antes de que pueda pasar y no sé cuál puede ser el problema (tengo Windows 64bits).

Además, extrañamente si mi rutina devuelve TRUE (simplemente deshabilita la acción de cerrar), todavía cierra la aplicación. La rutina se llama, por lo que SetConsoleCtrlHandler se instaló correctamente.

ej .:

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; 
} 

¿Alguna idea?

Respuesta

14

Parece que ya no se puede ignorar las solicitudes de cierre en Windows 7.

Usted hacer llegar el evento CTRL_CLOSE_EVENT embargo, y a partir de ese momento, se obtiene 10 segundos para hacer lo que hay que hacer antes se cierra automáticamente. Entonces puede hacer cualquier trabajo que necesite hacer en el controlador o establecer un indicador global.

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

Dato curioso: mientras que el código en su evento CTRL_CLOSE_EVENT se ejecuta, el programa principal se mantiene en marcha. Entonces, podrás verificar la bandera y hacer un 'close_flag = 2;' algun lado. Pero recuerda, solo tienes 10 segundos. (Por lo tanto, tenga en cuenta que no desea colgar el flujo principal de su programa esperando en la entrada del teclado, por ejemplo).

+12

10 segundos de tiempo es solo la mitad de la verdad. La aplicación finalizará una vez que el controlador regrese, por lo que debe mantener el controlador en funcionamiento. –

+1

Tenga en cuenta que el controlador se ejecuta en el contexto de un hilo arbitrario (esa es la razón por la cual el programa continúa ejecutándose). Por lo tanto, debe usar algún mecanismo seguro para señalar que la terminación está en progreso (por ejemplo, un evento). –

+0

Si el controlador devuelve falso y se llama al controlador predeterminado, el proceso sale por 'ExitProcess (STATUS_CONTROL_C_EXIT)'. Si el proceso sale solo antes de regresar, puede usar un código de salida diferente para indicar un cierre exitoso. De lo contrario, si el controlador devuelve verdadero o tarda más de 5 segundos (no 10 segundos), el servidor de sesión (csrss.exe) finaliza con fuerza el proceso con el código de salida 'STATUS_CONTROL_C_EXIT'. – eryksun

1

Estás haciendo esto más complicado de lo necesario. No sé exactamente por qué su aplicación se está cerrando, pero SetConsoleCtrlHandler(NULL, TRUE) debería hacer lo que quiera:

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

Si el parámetro HandlerRoutine es NULL, un valor TRUE hace que el proceso que llama a ignorar CTRL + C entrada, y un valor FALSO restaura el procesamiento normal de la entrada CTRL + C.

+3

Todavía sale cuando presiono el botón de cerrar en mi consola.CTRL + C no es el problema, ya que también funciona y funciona: if (dwCtrlType == CTRL_C_EVENT) devuelve TRUE; Es el botón de cerrar que me está causando problemas. – Jeremy

3

Sospecho que esto es un diseño de Windows 7: si el usuario desea abandonar su aplicación, no puede decirle "No".

+2

De acuerdo. El diálogo que solía mostrarse es gonzo. –

3

El comentario de Xavier es levemente incorrecto. Windows 7 permite su código en el controlador de eventos ~ 10 segundos. Si no ha salido del controlador de eventos en 10 segundos, será cancelado. Si sale del controlador de eventos, se cancela inmediatamente. Devolver TRUE no publica un diálogo. Simplemente sale.

3

No hay necesidad de esperar ningún indicador del hilo principal, el controlador finaliza tan pronto como el hilo principal sale (o después de 10 s).

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; 
} 
Cuestiones relacionadas