2012-01-06 9 views
5

Tengo una aplicación que me gustaría cerrar con gracia cuando Windows se apaga (o el usuario cierra la sesión). Esto solía funcionar (en xp) pero en algún momento del año pasado se rompió sin que nadie lo notara. También está roto (pero de manera diferente) en Windows 7.Agraciado cierre de la aplicación cuando Windows se apaga

Nuestro producto tiene un proceso principal (server.exe) que inicia muchos otros procesos. Un apagado correcto haría que server.exe le pidiera a todo el proceso que comience a cerrarse. Sin embargo, cuando depuro este código, parece que los otros procesos ya han finalizado. Nuestro proceso principal (server.exe) es el único proceso que maneja los mensajes WM_QUERYENDSESSION y WM_ENDSESSION. Código de abajo (esto solía trabajar en XP, pero no más hace):

LRESULT CALLBACK master_wnd_proc 
(
    HWND hwnd,  /* (in) handle to window */ 
    UINT uMsg,  /* (in) message identifier */ 
    WPARAM wParam, /* (in) first message parameter */ 
    LPARAM lParam /* (in) second message parameter */ 
) 
{ 
    LRESULT result; /* return value */ 
    long msg_code; 

    switch (uMsg) 
    { 
     case WM_ENDSESSION: 
     if (wParam) 
     { 
      msg_code = PCS_WINDOWS_SHUTDOWN; 
      if(lParam & 0x01L) 
       msg_code = WINDOWS_SHUT_CLOSE; 
      if(lParam & 0x40000000L) 
       msg_code = WINDOWS_SHUT_CRIT; 
      if((unsigned long)lParam & 0x80000000) 
       msg_code = WINDOWS_SHUT_LOGOFF; 
      MsgGenerate(msg_code, MSG_SEVERE, MSG_LOG, ""); 

      ipc_declare_shutdown(msg_code); 

      //We need one more message in the message queue 
      //to force the message loop, below, to exit. 
      PostQuitMessage(EXIT_SUCCESS); 

      /* WARNING: Don't call MsgGenerate() after this point! */ 
     } 
     result = 0; 
     break; 

     case WM_QUERYENDSESSION: 

     /* return TRUE to say "okay to shutdown" 
      * If FALSE is returned, then other processes are not stopped 
      * and the session isn't ended. 
      */ 
     result = TRUE; 
     break; 

     /* for a Windows TIMER or for an IPC prompt, handle 
     * the old server code and tcall messages and 
     * once-per-second work. Notice that the 
     * once-per-second work could just be done on the WM_TIMER 
     * and the tcall work could just be done on the WM_APP_IPC_POSTED 
     * but I've merged them together here. The merge isn't 
     * necessary to fix a bug or anything, but rather to 
     * make the code more robust in the face of unexpected 
     * conditions. 
     */ 
     case WM_TIMER: 
     case WM_APP_IPC_POSTED: 
     /* now handle tcall messages */ 
     (void) server(); 

     result = FALSE; 
     break; 

     default: 
     result = DefWindowProc (hwnd, uMsg, wParam, lParam); 
     break; 
    } 

    return result; 
} 

Parece que hemos cambiado algo en el último año el requeriría que todos los procesos hijos a manejar el mensaje WM_QUERYENDSESSION (Realmente me gustaría evitar esto). Parece que no puedo encontrar ninguna información sobre cuándo los procesos reciben o no este mensaje.

He hecho que funcione en Windows 7 utilizando la nueva API, pero me gustaría descubrir por qué está roto bajo XP, así que puedo tener una solución que funcione para ambos sistemas operativos.

¿Algún ayuda?

+1

¿Podría ser solo que Windows está cerrando los procesos en un orden diferente por alguna razón? ¿Qué hay que garantice que su 'server.exe' sea lo primero que Windows apaga? –

+0

¿Alguna posibilidad de que tengas este código en el control de código fuente? Al menos podría ver si ha cambiado en el último año? –

+0

No estoy seguro de qué fue lo que hacía que Server.exe se detenga antes que los demás ... –

Respuesta

3

Las cosas cambiaron en torno al tiempo de Vista, no estoy seguro de cómo afectaría eso a tu código. Lo mejor que puede hacer es no dejarlo en manos de Windows para determinar el orden de cierre. Simplemente solicite que su servidor reciba la notificación de cierre antes de que el ayudante procese:

DWORD dwLevel, dwFlags; 
    BOOL fOkay = GetProcessShutdownParameters(&dwLevel, &dwFlags); 
    ASSERT(fOkay); 
    if (fOkay && dwLevel > 0x100) { 
     fOkay = SetProcessShutdownParameters(dwLevel + 1, SHUTDOWN_NORETRY); 
     ASSERT(fOkay); 
    } 
+0

Esto casi funciona ... –

+0

Bajo XP esto funciona genial. En Windows 7, el comportamiento sigue siendo el mismo. –

+0

Sé que esto funciona en Win7. Algo más que te molesta, difícil de adivinar. –

Cuestiones relacionadas