【问题标题】:Graceful application shutdown when Windows shuts downWindows 关闭时应用程序正常关闭
【发布时间】:2012-02-04 08:10:04
【问题描述】:

我想在 Windows 关闭(或用户注销)时正常关闭一个应用程序。这曾经有效(在 xp 中),但在去年的某个时候,它在没有人注意到的情况下坏了。在 Windows 7 下它也坏了(但不同)。

我们的产品有一个启动许多其他进程的主进程 (server.exe)。正常关闭将使 server.exe 询问它开始关闭的所有进程。但是,当我调试此代码时,似乎其他进程已被终止。我们的主进程 (server.exe) 是唯一处理 WM_QUERYENDSESSION 和 WM_ENDSESSION 消息的进程。下面的代码(以前在 XP 下可以工作,但现在不行了):

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 消息(我真的很想避免这种情况)。我似乎无法找到有关进程何时收到或未收到此消息的任何信息。

我已经使用新的 API 让它在 Windows 7 下工作,但想弄清楚为什么它在 XP 下坏了,所以我可以有一个适用于两种操作系统的解决方案。

有什么帮助吗?

【问题讨论】:

  • 会不会是 Windows 出于某种原因以不同的顺序关闭进程?有什么可以保证您的 server.exe 是 Windows 关闭的第一件事?
  • 你有没有可能在源代码管理中有这段代码?您至少可以看看它是否在去年发生了变化?
  • 不确定是什么让 server.exe 先于其他人关闭...
  • 根据颠覆日志,2010 年 2 月 10 日添加了检查标志以检查用户是否正在注销或 Windows 是否正在关闭的代码。从那时起它就没有改变。

标签: windows windows-7


【解决方案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);
   }

【讨论】:

  • 在 XP 下这很好用。在 Windows 7 下,行为仍然相同。
  • 我知道这适用于 Win7。其他事情困扰着你,很难猜到。
  • 双重检查了我的代码,确实在 Windows 7 下我没有调用它...修复了代码,是的,它可以工作。谢谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多