Gracefully closing applications when Windows shuts down

I have an application that I would like to close gracefully when Windows shuts down (or the user shuts down). It was used for work (in xp), but sometime last year it broke and no one noticed. It also broke (but in a different way) under Windows 7.

Our product has a main process (server.exe) that runs many other processes. The graceful shutdown of server.exe causes the entire process, which it begins to close. However, when I debug this code, it seems that the other processes are already completed. Our main process (server.exe) is the only process that processes WM_QUERYENDSESSION and WM_ENDSESSION messages. The code below (this is used to work under XP, but no longer exists):

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

, - , WM_QUERYENDSESSION ( ). , , .

Windows 7 API, , XP, , .

?

+5
1

Vista, , . Windows, . , :

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

All Articles