在 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 你真的必须关闭(注销,重启)而不是仅仅模拟它。
我的应用程序(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 你真的必须关闭(注销,重启)而不是仅仅模拟它。