2012-01-06 15 views
5

Mam aplikację, którą chciałbym zamknąć z gracją, gdy system Windows zostanie zamknięty (lub użytkownik wyloguje się). To działało (w xp), ale kiedyś w zeszłym roku się rozpadło, nikt nie zauważył. Jest również spłukany (ale inaczej) pod Windows 7.Zgrabne zamykanie aplikacji przy wyłączaniu systemu Windows

Nasz produkt zawiera proces główny (server.exe), który uruchamia wiele innych procesów. Pełne wdzięku wyłączenie spowodowałoby, że server.exe zażądałby całego procesu, który zaczyna się zamykać. Jednak podczas debugowania tego kodu wydaje się, że inne procesy zostały już zakończone. Nasz główny proces (server.exe) jest jedynym procesem, który obsługuje komunikaty WM_QUERYENDSESSION i WM_ENDSESSION. Kod poniżej (to używane do pracy pod XP, ale nie robi nic więcej):

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

Wydaje się, że mamy coś zmieniło się w ostatnim roku wymagałoby wszystkie procesy potomne obsłużyć wiadomość WM_QUERYENDSESSION (Naprawdę chciałbym tego uniknąć). Wydaje mi się, że nie mogę znaleźć żadnych informacji na temat tego, kiedy procesy wykonują lub nie otrzymują tej wiadomości.

Sprawiłem, że działa pod Windows 7 przy użyciu nowego API, ale chciałbym dowiedzieć się, dlaczego jest zbędne pod XP, więc mogę mieć rozwiązanie, które działa dla obu OS.

Każda pomoc?

+1

Czy to możliwe, że system Windows z jakiegoś powodu wyłącza procesy w innej kolejności? Co jest tam, co gwarantuje, że twój 'server.exe' jest pierwszą rzeczą, którą system Windows zamyka? –

+0

Jakąkolwiek możliwość posiadania tego fragmentu kodu w kontroli źródła? Mógłbyś przynajmniej sprawdzić, czy został zmieniony w zeszłym roku? –

+0

Nie jestem pewien, co spowodowało zamknięcie serwera.exe przed innymi ... –

Odpowiedz

3

Rzeczy zmieniły się w okolicach czasu Vista, nie jestem pewien jak to wpłynęłoby na twój kod. Najlepiej nie zostawiać tego w systemie Windows, aby określić kolejność wyłączania. Po prostu poproś o to, aby Twój serwer otrzymał powiadomienie o wyłączeniu przed procesami pomocniczymi:

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

To prawie działa ... –

+0

Pod XP to działa świetnie. W systemie Windows 7 zachowanie jest wciąż takie samo. –

+0

Wiem, że to działa na Win7. Coś, co cię dręczy, trudno zgadnąć. –

Powiązane problemy