Да, конечно, это возможно. Несколько месяцев назад я столкнулся с подобной проблемой, когда какое-то (неизвестное, но, вероятно, моё) приложение препятствовало завершению работы, поэтому я написал быстрый код, использующий EnumWindows для перечисления всех окон верхнего уровня, отправив каждому сообщение WM_QUERYENDSESSION, отметив, что возвращаемое значение Значение из SendMessage было и остановило перечисление, если кто-нибудь вернул FALSE. Заняло около десяти минут в C ++ / MFC. Это было мужество этого:
void CQes_testDlg::OnBtnTest()
{
// enumerate all the top-level windows.
m_ctrl_ListMsgs.ResetContent();
EnumWindows (EnumProc, 0);
}
BOOL CALLBACK EnumProc (HWND hTarget, LPARAM lParam)
{
CString csTitle;
CString csMsg;
CWnd * pWnd = CWnd::FromHandle (hTarget);
BOOL bRetVal = TRUE;
DWORD dwPID;
if (pWnd)
{
pWnd->GetWindowText (csTitle);
if (csTitle.GetLength() == 0)
{
GetWindowThreadProcessId (hTarget, &dwPID);
csTitle.Format ("<PID=%d>", dwPID);
}
if (pWnd->SendMessage (WM_QUERYENDSESSION, 0, ENDSESSION_LOGOFF))
{
csMsg.Format ("window 0x%X (%s) returned TRUE", hTarget, csTitle);
}
else
{
csMsg.Format ("window 0x%X (%s) returned FALSE", hTarget, csTitle);
bRetVal = FALSE;
}
mg_pThis->m_ctrl_ListMsgs.AddString (csMsg);
}
else
{
csMsg.Format ("Unable to resolve HWND 0x%X to a CWnd", hTarget);
mg_pThis->m_ctrl_ListMsgs.AddString (csMsg);
}
return bRetVal;
}
mg_pЭто была просто локальная копия указателя this диалога, поэтому вспомогательный обратный вызов мог получить к нему доступ. Я сказал вам, это было быстро и грязно: -)