在 Windows 关机时保存数据

Saving Data on Windows Shutdown

我的应用程序(Windows 7,Visual C++,Release-Build)需要在 windows 关闭(重新启动,用户注销)时写入一些数据。毕竟我想做与接收 WM_CLOSE-Message 时相同的事情,该消息在我的应用程序定期关闭期间被调用(Alt-f4,关闭 window,...)

我不需要任何用户输入、对话框等。只是默写。写作本身应该持续不到一秒钟。

为此,我执行以下操作:

LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
  if (message == WM_CLOSE){
    TRACE(_T("got WM_CLOSE"));
    SaveMyData();
  }

  switch (message) {
    case WM_QUERYENDSESSION:
        TRACE(_T("findme: WM_QUERYENDSESSION"));
        {
                BOOL bShutdownBlocked = ShutdownBlockReasonCreate(theApp.m_pMainWnd->GetSafeHwnd(), _T("Save data"));
                TRACE(_T("blocked: %d, GetlastError: %d"), bShutdownBlocked, GetLastError());
        }

        //continue shutdown-sequence
        return TRUE;

    case WM_ENDSESSION:
        TRACE(_T("findme: WM_ENDSESSION. Store? %d"), FALSE != (BOOL)wParam);
        if (FALSE != (BOOL)wParam) 
        {
          long lTickStart = GetTickCount();
          TRACE(_T(">>> Sleep..."));
          ::Sleep(1000); //just a Test: do something while shutting down
          TRACE(_T("<<< Sleep: %d ms"), GetTickCount()-lTickStart);

          BOOL bUnblockShutdown = ShutdownBlockReasonDestroy(theApp.m_pMainWnd->GetSafeHwnd());
          TRACE(_T("unblock: %d"), bUnblockShutdown);
        }
        return 0L;

    default:
        return CMDIFrameWnd::WindowProc(message, wParam, lParam);
    }
}

所有跟踪都被重定向到我检查的文件中。

我在 Win7 (rmtool -S -pid) 下使用 Windows 徽标测试工具中的重启管理器对此进行了测试,它工作正常。我得到以下跟踪输出:

findme: WM_QUERYENDSESSION
blocked 1, GetlastError: 0
findme: WM_ENDSESSION. Store? 1
>>> Sleep...
<<< Sleep: 1015 ms
unblock: 1
got WM_CLOSE

注意 "got WM_CLOSE" 调用代码来保存我的数据。

但它不起作用,当我实际关闭 windows 或注销或使用 rmtool 和 -lr 选项时。在这种情况下,我只得到以下输出:

findme: WM_QUERYENDSESSION
blocked 1, GetlastError: 0
findme: WM_ENDSESSION. Store? 1
>>> Sleep...
<<< Sleep: 1000 ms
unblock: 1

此处WM_CLOSE-未收到消息。

关闭时依赖该消息是错误的还是我做错了什么?

MSDN所说

When an application returns TRUE for WM_QUERYENDSESSION, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.

MSDN 未指定 Windows 通过向其发送 WM_CLOSE 来终止您的应用程序。为了安全起见,您应该在 WM_ENDSESSION 处理程序中进行保存。

顺便说一句,您应该删除对 ShutdownBlockReasonCreate 的调用。它有什么用?如果有效,您将不会再得到 WM_ENDSESSION。如果要防止关机,应提前调用该函数。

我认为诀窍是在 WM_ENDSESSION 中做所有事情而不发送或接收任何 Windows-Messages。

此外,您不应该过分依赖 rmtool.exe,至少在不使用 -l 参数的情况下。它的行为与关闭 windows 不同。所以要测试 shutdown-scenarios 你真的必须关闭(注销,重启)而不是仅仅模拟它。