From d8b9b8b26880242380caae35e6220346cc8ee10e Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Tue, 29 Mar 2011 20:59:09 +0000 Subject: [PATCH] - WINSCR: So after looking over all the logs from WCG and now from Jacob Klein a pattern started to emerge. At the end of the log files the last message logged was 0x12 which translates into WM_QUIT. The latest documentation on WM_QUIT states it should never show up in the message loop to begin with. The docs now say that WM_QUIT should not be sent to the message loop by way of PostMessage. We have been doing things this way for over 5 years. For all I know, this could have been carried over from the original screen saver sample application. Change the shutdown logic so that only the primary curtain window can call PostQuitMessage() and all other curtain windows just exit when they receive a WM_DESTROY message. I'm not sure what causes this to be a problem on some machines and not others. But preliminary results from Jacob are encouraging. clientscr/ screensaver_win.cpp, .h svn path=/trunk/boinc/; revision=23294 --- checkin_notes | 20 +++ clientscr/screensaver_win.cpp | 234 +++++++++++++++++++++++++++++----- clientscr/screensaver_win.h | 3 +- 3 files changed, 222 insertions(+), 35 deletions(-) diff --git a/checkin_notes b/checkin_notes index ae5b090bdc..96c1b2d5c1 100644 --- a/checkin_notes +++ b/checkin_notes @@ -1942,3 +1942,23 @@ Rom 29 Mar 2011 TermsOfUsePage.cpp UserDisagreesPage.cpp, .h (Deleted) WizardAttach.cpp, .h + +Rom 29 Mar 2011 + - WINSCR: So after looking over all the logs from WCG and now from Jacob + Klein a pattern started to emerge. At the end of the log files the last + message logged was 0x12 which translates into WM_QUIT. The latest + documentation on WM_QUIT states it should never show up in the message + loop to begin with. + + The docs now say that WM_QUIT should not be sent to the message loop by + way of PostMessage. We have been doing things this way for over 5 years. + + Change the shutdown logic so that only the primary curtain window can call + PostQuitMessage() and all other curtain windows just exit when they receive + a WM_DESTROY message. + + I'm not sure what causes this to be a problem on some machines and not + others. But preliminary results from Jacob are encouraging. + + clientscr/ + screensaver_win.cpp, .h diff --git a/clientscr/screensaver_win.cpp b/clientscr/screensaver_win.cpp index f19a45713b..4164e1eac7 100644 --- a/clientscr/screensaver_win.cpp +++ b/clientscr/screensaver_win.cpp @@ -825,7 +825,9 @@ BOOL CScreensaver::GetTextForError( // BOOL CScreensaver::CreateInputActivityThread() { DWORD dwThreadID = 0; + BOINCTRACE(_T("CScreensaver::CreateInputActivityThread Start\n")); + m_hInputActivityThread = CreateThread( NULL, // default security attributes 0, // use default stack size @@ -849,10 +851,13 @@ BOOL CScreensaver::CreateInputActivityThread() { // Terminate the thread that is used to monitor input activity. // BOOL CScreensaver::DestroyInputActivityThread() { + BOINCTRACE(_T("CScreensaver::DestroyInputActivityThread: Shutting Down...\n")); + if (!TerminateThread(m_hInputActivityThread, 0)) { BOINCTRACE(_T("CScreensaver::DestroyInputActivityThread: Failed to terminate input activity thread '%d'\n"), GetLastError()); return FALSE; } + return TRUE; } @@ -941,10 +946,13 @@ BOOL CScreensaver::CreateGraphicsWindowPromotionThread() { // Terminate the thread that is used to promote the graphics window. // BOOL CScreensaver::DestroyGraphicsWindowPromotionThread() { + BOINCTRACE(_T("CScreensaver::DestroyGraphicsWindowPromotionThread: Shutting Down...\n")); + if (!TerminateThread(m_hGraphicsWindowPromotionThread, 0)) { BOINCTRACE(_T("CScreensaver::DestroyGraphicsWindowPromotionThread: Failed to terminate graphics window promotion thread '%d'\n"), GetLastError()); return FALSE; } + return TRUE; } @@ -1036,7 +1044,9 @@ DWORD WINAPI CScreensaver::GraphicsWindowPromotionProc() { // BOOL CScreensaver::CreateDataManagementThread() { DWORD dwThreadID = 0; + BOINCTRACE(_T("CScreensaver::CreateDataManagementThread Start\n")); + m_hDataManagementThread = CreateThread( NULL, // default security attributes 0, // use default stack size @@ -1049,6 +1059,7 @@ BOOL CScreensaver::CreateDataManagementThread() { BOINCTRACE(_T("CScreensaver::CreateDataManagementThread: Failed to create data management thread '%d'\n"), GetLastError()); return FALSE; } + return TRUE; } @@ -1058,15 +1069,23 @@ BOOL CScreensaver::CreateDataManagementThread() { // Terminate the thread that is used to talk to the daemon. // BOOL CScreensaver::DestroyDataManagementThread() { - m_bQuitDataManagementProc = true; // Tell DataManagementProc thread to exit - for (int i = 0; i < 50; i++) { // Wait up to 5 second for DataManagementProc thread to exit - if (m_bDataManagementProcStopped) return true; + BOINCTRACE(_T("CScreensaver::DestoryDataManagementThread: Shutting down... \n")); + + m_bQuitDataManagementProc = true; + for (int i = 0; i < 50; i++) { + if (m_bDataManagementProcStopped) { + BOINCTRACE(_T("CScreensaver::DestoryDataManagementThread: Thread gracefully shutdown \n")); + return TRUE; + } boinc_sleep(0.1); } + + BOINCTRACE(_T("CScreensaver::DestoryDataManagementThread: Terminating thread... \n")); if (!TerminateThread(m_hDataManagementThread, 0)) { - BOINCTRACE(_T("CScreensaver::DestoryDataManagementThread: Failed to terminate data management thread '%d'\n"), GetLastError()); + BOINCTRACE(_T("CScreensaver::DestoryDataManagementThread: Failed to terminate thread '%d'\n"), GetLastError()); return FALSE; } + return TRUE; } @@ -1129,7 +1148,7 @@ HRESULT CScreensaver::CreateSaverWindow() { cls2.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); cls2.hInstance = m_hInstance; cls2.style = CS_VREDRAW|CS_HREDRAW; - cls2.lpfnWndProc = SaverProcStub; + cls2.lpfnWndProc = GenericSaverProcStub; cls2.cbWndExtra = 0; cls2.cbClsExtra = 0; RegisterClass(&cls2); @@ -1243,21 +1262,21 @@ VOID CScreensaver::DoConfig() { -// Handle window messages for main screensaver windows. +// Handle window messages for main screensaver window. // LRESULT CScreensaver::SaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { DWORD dwMonitor = 0; + #ifdef _DEBUG for(DWORD iIndex = 0; iIndex < m_dwNumMonitors; iIndex++) { if (hWnd == m_Monitors[iIndex].hWnd ) { dwMonitor = iIndex; } } -#endif - BOINCTRACE(_T("CScreensaver::SaverProc [%d] hWnd '%d' uMsg '%X' wParam '%d' lParam '%d'\n"), dwMonitor, hWnd, uMsg, wParam, lParam); +#endif switch (uMsg) { case WM_TIMER: @@ -1322,7 +1341,7 @@ LRESULT CScreensaver::SaverProc( m_dwSaverMouseMoveCount++; if (m_dwSaverMouseMoveCount > 5) { BOINCTRACE(_T("CScreensaver::SaverProc Received WM_MOUSEMOVE and time to InterruptSaver()\n")); - InterruptSaver(); + FireInterruptSaverEvent(); } } } @@ -1335,18 +1354,21 @@ LRESULT CScreensaver::SaverProc( case WM_MBUTTONDOWN: BOINCTRACE(_T("CScreensaver::SaverProc Received WM_KEYDOWN | WM_LBUTTONDOWN | WM_RBUTTONDOWN | WM_MBUTTONDOWN\n")); if (m_SaverMode != sm_test) { - InterruptSaver(); + FireInterruptSaverEvent(); } return 0; break; case WM_CLOSE: - case WM_DESTROY: - BOINCTRACE(_T("CScreensaver::SaverProc Received WM_CLOSE or WM_DESTROY\n")); + BOINCTRACE(_T("CScreensaver::SaverProc Received WM_CLOSE\n")); if (m_SaverMode == sm_preview || m_SaverMode == sm_test) { - ShutdownSaver(); + FireInterruptSaverEvent(); } - return 0; + break; + + case WM_DESTROY: + BOINCTRACE(_T("CScreensaver::SaverProc Received WM_DESTROY\n")); + PostQuitMessage(0); break; case WM_SYSCOMMAND: @@ -1374,7 +1396,7 @@ LRESULT CScreensaver::SaverProc( case WM_POWERBROADCAST: BOINCTRACE(_T("CScreensaver::SaverProc Received WM_POWERBROADCAST\n")); if (wParam == PBT_APMQUERYSUSPEND) - InterruptSaver(); + FireInterruptSaverEvent(); break; } @@ -1388,7 +1410,155 @@ LRESULT CScreensaver::SaverProc( } else if (WM_INTERRUPTSAVER == uMsg) { BOINCTRACE(_T("CScreensaver::SaverProc Received WM_INTERRUPTSAVER\n")); - InterruptSaver(); + ShutdownSaver(); + + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + + + + +// Handle window messages for secondary screensaver windows. +// +LRESULT CScreensaver::GenericSaverProc( + HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam +) { + DWORD dwMonitor = 0; + +#ifdef _DEBUG + for(DWORD iIndex = 0; iIndex < m_dwNumMonitors; iIndex++) { + if (hWnd == m_Monitors[iIndex].hWnd ) { + dwMonitor = iIndex; + } + } + BOINCTRACE(_T("CScreensaver::GenericSaverProc [%d] hWnd '%d' uMsg '%X' wParam '%d' lParam '%d'\n"), dwMonitor, hWnd, uMsg, wParam, lParam); +#endif + + switch (uMsg) { + case WM_TIMER: + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_TIMER\n")); + switch (wParam) { + case 1: + // Initial idle time is done, proceed with initialization. + m_bWaitForInputIdle = FALSE; + KillTimer(hWnd, 1); + return 0; + break; + case 2: + // Create a screen saver window on the primary display if + // the boinc client crashes + CreateSaverWindow(); + + // Update the position of the box every second so that it + // does not end up off the visible area of the screen. + UpdateErrorBox(); + return 0; + break; + } + break; + case WM_PAINT: + { + BOOL bErrorMode; + HRESULT hrError; + TCHAR szError[400]; + GetError(bErrorMode, hrError, szError, sizeof(szError)/sizeof(TCHAR)); + + // Show error message, if there is one + PAINTSTRUCT ps; + BeginPaint(hWnd, &ps); + + // In preview mode, just fill + // the preview window with black, and the BOINC icon. + if (!bErrorMode && m_SaverMode == sm_preview) { + RECT rc; + GetClientRect(hWnd,&rc); + FillRect(ps.hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); + DrawIcon(ps.hdc, (rc.right / 2) - 16, (rc.bottom / 2) - 16, + LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON))); + } else { + DoPaint(hWnd, ps.hdc, &ps); + } + + EndPaint(hWnd, &ps); + } + + return 0; + break; + + case WM_MOUSEMOVE: + if (m_SaverMode != sm_test) { + static INT xPrev = -1; + static INT yPrev = -1; + INT xCur = LOWORD(lParam); + INT yCur = HIWORD(lParam); + if (xCur != xPrev || yCur != yPrev) { + xPrev = xCur; + yPrev = yCur; + m_dwSaverMouseMoveCount++; + if (m_dwSaverMouseMoveCount > 5) { + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_MOUSEMOVE and time to InterruptSaver()\n")); + FireInterruptSaverEvent(); + } + } + } + return 0; + break; + + case WM_KEYDOWN: + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_KEYDOWN | WM_LBUTTONDOWN | WM_RBUTTONDOWN | WM_MBUTTONDOWN\n")); + if (m_SaverMode != sm_test) { + FireInterruptSaverEvent(); + } + return 0; + break; + + case WM_CLOSE: + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_CLOSE\n")); + if (m_SaverMode == sm_preview || m_SaverMode == sm_test) { + FireInterruptSaverEvent(); + } + break; + + case WM_SYSCOMMAND: + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_SYSCOMMAND\n")); + if (m_SaverMode == sm_full) { + switch (wParam) { + case SC_NEXTWINDOW: + case SC_PREVWINDOW: + case SC_SCREENSAVE: + case SC_CLOSE: + return 0; + } + } + break; + + case WM_SETCURSOR: + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_SETCURSOR\n")); + if (m_SaverMode == sm_full) { + // Hide cursor + SetCursor(NULL); + return TRUE; + } + break; + + case WM_POWERBROADCAST: + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_POWERBROADCAST\n")); + if (wParam == PBT_APMQUERYSUSPEND) + FireInterruptSaverEvent(); + break; + } + + if (WM_SETTIMER == uMsg) { + + BOINCTRACE(_T("CScreensaver::GenericSaverProc Received WM_SETTIMER\n")); + // All initialization messages have gone through. Allow + // 500ms of idle time, then proceed with initialization. + SetTimer(hWnd, 1, 500, NULL); } @@ -1546,6 +1716,18 @@ LRESULT CALLBACK CScreensaver::SaverProcStub( +// This function forwards all window messages to GenericSaverProc, which has +// access to the "this" pointer. +// +LRESULT CALLBACK CScreensaver::GenericSaverProcStub( + HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam +) { + return gspScreensaver->GenericSaverProc(hWnd, uMsg, wParam, lParam); +} + + + + INT_PTR CALLBACK CScreensaver::ConfigureDialogProcStub( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { @@ -1567,14 +1749,10 @@ VOID CScreensaver::ShutdownSaver() { // Kill the currently executing graphics application terminate_screensaver(m_hGraphicsApplication, &m_running_result); - // Post message to drop out of message loop - // This can be called from the data management thread, so specifically - // lookup and post to the primary window instead of calling PostQuitMessage - // since PostQuitMessage posts to the current threads message pump if it - // exists. + // Close all screensaver windows for(DWORD iIndex = 0; iIndex < m_dwNumMonitors; iIndex++) { if ( m_Monitors[iIndex].hWnd ) { - PostMessage(m_Monitors[iIndex].hWnd, WM_QUIT, NULL, NULL); + DestroyWindow(m_Monitors[iIndex].hWnd); } } @@ -1599,18 +1777,6 @@ VOID CScreensaver::FireInterruptSaverEvent() { -// A message was received (mouse move, keydown, etc.) that may mean -// the screen saver should shut down. -// -VOID CScreensaver::InterruptSaver() { - BOINCTRACE(_T("CScreensaver::InterruptSaver Function Begin\n")); - ShutdownSaver(); - BOINCTRACE(_T("CScreensaver::InterruptSaver Function End\n")); -} - - - - // Update the box that shows the error message // VOID CScreensaver::UpdateErrorBox() { diff --git a/clientscr/screensaver_win.h b/clientscr/screensaver_win.h index 807bfab8eb..56fbaa8b60 100644 --- a/clientscr/screensaver_win.h +++ b/clientscr/screensaver_win.h @@ -217,7 +217,6 @@ protected: HRESULT CreateSaverWindow(); VOID UpdateErrorBox(); VOID FireInterruptSaverEvent(); - VOID InterruptSaver(); VOID ShutdownSaver(); @@ -225,6 +224,7 @@ protected: HRESULT DoSaver(); VOID DoPaint( HWND hwnd, HDC hdc, LPPAINTSTRUCT lpps ); LRESULT SaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); + LRESULT GenericSaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); DWORD ConvertSliderPositionToTime( DWORD dwPosition ); DWORD ConvertTimeToSliderPosition( DWORD dwMinutes ); @@ -234,6 +234,7 @@ protected: INT_PTR ConfigureDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ); static LRESULT CALLBACK SaverProcStub( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); + static LRESULT CALLBACK GenericSaverProcStub( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); static INT_PTR CALLBACK ConfigureDialogProcStub( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); protected: