我有一个在通知区域(系统托盘)中运行的 MFC 对话框应用程序。它偶尔会无缘无故地关闭。
经过多年的斗争,我认为这是内存损坏或其他原因,我添加了一些日志记录。
事实证明,我正在从某个地方收到 WM_CLOSE 消息。但我不知道在哪里。我有一些自己的强制关闭代码用于更新等,但它们记录良好并且永远不会触发。
有趣的是,我的应用程序必须进行一些清理,以确保它不在数据库操作的中间。所以在 OnClose() 内部,我实际上并没有立即关闭,而是设置了一个标志,如果 OnClose() 已被调用,则下次我的任务计时器触发时,它会再次被调用以真正关闭应用程序。
所以我在日志中看到的是六个 OnClose() 快速连续调用(相隔几毫秒),然后程序就消失了。它从不调用我实际的清理后 OnClose(),因为我的计时器间隔 5 秒,所以我的清理开始但我的关机从未被调用。
我不禁认为这些调用来自外部进程 - Windows 更新或其他东西 - 有时 Windows 系统事件日志表明安全更新或 gupdate.exe 在那个时候触发。但是计算机甚至没有重新启动。看起来好像有东西向我发送了六条关闭消息,然后杀死了程序。
我想我正在失去理智 - 是某个外部进程真正关闭了我的应用程序吗?还是我在这里完全走错了路?
也许我在某些方面没有遵循最佳实践,但我正在为此苦苦挣扎。此应用程序需要 24/7 全天候运行(更改为服务的巨大努力,顺便说一句),但我不断收到这些意外消失。
(编辑)根据要求,我在此处添加了 OnClose() 代码。第一次(在 else 中)我设置了一个标志,表明我们正在等待关闭。当计时器下一次触发时,它会看到这个标志,设置 CloseNow 并调用 OnClose()
当这种情况发生时,我在日志中看到多条“等待关闭”消息,但它永远不会进入 CloseNow 条件以正确关闭。但是应用程序被关闭。
我的代码中没有任何内容可以发送多个 OnClose 消息。起初我认为这可能是 processmessages() 的事情,但它甚至从未到达那里。
void CBPTillBotDlg::OnClose() {
// Got a close message, tell timer we're shutting down.
m_iKillingApplication = true;
InstallIcon(NIM_MODIFY,MODE_IDLE);
// if the timer has returned and says it is okay to close now
if (m_iCloseNow) {
// On a normal close when the timer sets m_iCloseNow
// we fall into here and cleanup.
// *** With the OnClose() problem, this code never gets hit.
BECLog lLog;
lLog.WriteString("CBPTillBotDlg::OnClose() Stopping Timer");
m_btTimer->StopTimer();
lLog.WriteString("CBPTillBotDlg::OnClose() Calling Getfields()");
GetFields();
lLog.WriteString("CBPTillBotDlg::OnClose() Kill Tabs");
if (m_pdImport!=NULL) {
m_pdImport->DestroyWindow();
delete m_pdImport;
m_pdImport = NULL;
}
if (m_pdExport!=NULL) {
m_pdExport->DestroyWindow();
delete m_pdExport;
m_pdExport = NULL;
}
if (m_pdBackup!=NULL) {
m_pdBackup->DestroyWindow();
delete m_pdBackup;
m_pdBackup = NULL;
}
if (m_pdError!=NULL) {
m_pdError->DestroyWindow();
delete m_pdError;
m_pdError = NULL;
}
if (m_pdReport!=NULL) {
m_pdReport->DestroyWindow();
delete m_pdReport;
m_pdReport = NULL;
}
lLog.WriteString("CBPTillBotDlg::OnClose() Save Config");
m_tbCfg->Save();
lLog.WriteString("CBPTillBotDlg::OnClose() Delete Literals");
if (m_pLiteral!=NULL) {
delete (m_pLiteral);
m_pLiteral = NULL;
}
lLog.WriteString("CBPTillBotDlg::OnClose() Shut Down Normally");
ProcessMessages();
Sleep(0);
CDialog::OnClose();
}
else {
// First time WM_CLOSE
// Set WaitToClose to indicate that we're closing.
// The next time the timer fires (which means we're done current processing) the timer knows to set m_iCloseNow
// *** With OnClose() problem, we're coming in here multiple times and not from any of our code.
m_bWaitToClose = TRUE;
BECLog lLog;
lLog.WriteString("CBPTillBotDlg::OnClose() Bot Waiting to Close");
}
}