// Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu // Copyright (C) 2005 University of California // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any later version. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // To view the GNU Lesser General Public License visit // http://www.gnu.org/copyleft/lesser.html // or write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "boinc_win.h" #include #include #include #include #define COMPILE_MULTIMON_STUBS #include #include #include "diagnostics.h" #include "exception.h" #include "boinc_ss.h" #include "win_screensaver.h" #include "win_util.h" // // Define the stuff needed to actually do a set foreground window on // Windows 2000 or later machines. // #ifndef BSF_ALLOWSFW #define BSF_ALLOWSFW 0x00000080 #endif const UINT WM_BOINCSFW = RegisterWindowMessage(TEXT("BOINCSetForegroundWindow")); static CScreensaver* gs_pScreensaver = NULL; INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HRESULT hr; int retval; WSADATA wsdata; CScreensaver BOINCSS; #ifdef _DEBUG // Initialize Diagnostics when compiled for debug retval = boinc_init_diagnostics ( BOINC_DIAG_DUMPCALLSTACKENABLED | BOINC_DIAG_HEAPCHECKENABLED | BOINC_DIAG_MEMORYLEAKCHECKENABLED | BOINC_DIAG_ARCHIVESTDERR | BOINC_DIAG_REDIRECTSTDERROVERWRITE | BOINC_DIAG_TRACETOSTDERR ); if (retval) { BOINCTRACE("WinMain - BOINC Screensaver Diagnostic Error '%d'", retval); MessageBox(NULL, NULL, "BOINC Screensaver Diagnostic Error", MB_OK); } #endif retval = WSAStartup( MAKEWORD( 1, 1 ), &wsdata); if (retval) { BOINCTRACE("WinMain - Winsock Initialization Failure '%d'", retval); return retval; } if( FAILED( hr = BOINCSS.Create( hInstance ) ) ) { BOINCSS.DisplayErrorMsg( hr ); WSACleanup(); return 0; } retval = BOINCSS.Run(); WSACleanup(); return retval; } //----------------------------------------------------------------------------- // Name: CScreensaver() // Desc: Constructor //----------------------------------------------------------------------------- CScreensaver::CScreensaver() { gs_pScreensaver = this; m_bCheckingSaverPassword = FALSE; m_bIs9x = FALSE; m_dwSaverMouseMoveCount = 0; m_hWnd = NULL; m_hWndParent = NULL; m_hPasswordDLL = NULL; m_VerifySaverPassword = NULL; m_bAllScreensSame = FALSE; m_bWindowed = FALSE; m_bWaitForInputIdle = FALSE; m_bErrorMode = FALSE; m_hrError = S_OK; m_szError[0] = _T('\0'); LoadString( NULL, IDS_DESCRIPTION, m_strWindowTitle, 200 ); m_bPaintingInitialized = FALSE; m_bCoreNotified = FALSE; m_bResetCoreState = TRUE; m_dwTimerCounter = 0; m_iStatus = 0; m_dwBlankScreen = 0; m_dwBlankTime = 0; m_bBOINCConfigChecked = FALSE; m_bBOINCStartupConfigured = FALSE; ZeroMemory( m_Monitors, sizeof(m_Monitors) ); m_dwNumMonitors = 0; } //----------------------------------------------------------------------------- // Name: Create() // Desc: Have the client program call this function before calling Run(). //----------------------------------------------------------------------------- HRESULT CScreensaver::Create( HINSTANCE hInstance ) { HRESULT hr; BOOL bReturnValue; m_hInstance = hInstance; // Parse the command line and do the appropriate thing m_SaverMode = ParseCommandLine( GetCommandLine() ); // Figure out if we're on Win9x OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx( &osvi ); m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); // Enumerate Monitors EnumMonitors(); // Retrieve the blank screen flag so we can determine if we are // suppose to actually blank the screen at some point. bReturnValue = UtilGetRegKey( REG_BLANK_NAME, m_dwBlankScreen ); if ( bReturnValue != 0 ) m_dwBlankScreen = 0; // Retrieve the blank screen timeout // make sure you check return value of registry queries // in case the item in question doesn't happen to exist. bReturnValue = UtilGetRegKey( REG_BLANK_TIME, m_dwBlankTime ); if ( bReturnValue != 0 ) m_dwBlankTime = 5; // Save the value back to the registry in case this is the first // execution and so we need the default value later. UtilSetRegKey( REG_BLANK_TIME, m_dwBlankTime ); // Calculate the estimated blank time by adding the current time // and and the user specified time which is in minutes m_dwBlankTime = time(0) + (m_dwBlankTime * 60); // Create the screen saver window(s) if( m_SaverMode == sm_preview || m_SaverMode == sm_test || m_SaverMode == sm_full ) { if( FAILED( hr = CreateSaverWindow() ) ) { m_bErrorMode = TRUE; m_hrError = hr; } } if( m_SaverMode == sm_preview ) { // In preview mode, "pause" (enter a limited message loop) briefly // before proceeding, so the display control panel knows to update itself. m_bWaitForInputIdle = TRUE; // Post a message to mark the end of the initial group of window messages PostMessage( m_hWnd, WM_USER, 0, 0 ); MSG msg; while( m_bWaitForInputIdle ) { // If GetMessage returns FALSE, it's quitting time. if( !GetMessage( &msg, m_hWnd, 0, 0 ) ) { // Post the quit message to handle it later PostQuitMessage(0); break; } TranslateMessage( &msg ); DispatchMessage( &msg ); } } return S_OK; } //----------------------------------------------------------------------------- // Name: Run() // Desc: Starts main execution of the screen saver. //----------------------------------------------------------------------------- INT CScreensaver::Run() { HRESULT hr; // Parse the command line and do the appropriate thing switch ( m_SaverMode ) { case sm_config: { if( m_bErrorMode ) { DisplayErrorMsg( m_hrError ); } else { DoConfig(); } break; } case sm_preview: case sm_test: case sm_full: { if( FAILED( hr = DoSaver() ) ) DisplayErrorMsg( hr ); break; } case sm_passwordchange: { ChangePassword(); break; } } return 0; } //----------------------------------------------------------------------------- // Name: StartupBOINC() // Desc: Notifies BOINC that it has to start the screensaver in full screen mode. //----------------------------------------------------------------------------- VOID CScreensaver::StartupBOINC() { int iStatus = 0; if( m_SaverMode != sm_preview ) { if( (NULL != m_Monitors[0].hWnd) && (m_bCoreNotified == FALSE) ) { TCHAR szCurrentWindowStation[MAX_PATH]; TCHAR szCurrentDesktop[MAX_PATH]; BOOL bReturnValue; int iReturnValue; memset(szCurrentWindowStation, 0, sizeof(szCurrentWindowStation)/sizeof(TCHAR)); memset(szCurrentDesktop, 0, sizeof(szCurrentDesktop)/sizeof(TCHAR)); if (!m_bIs9x) { // Retrieve the current window station and desktop names bReturnValue = GetUserObjectInformation( GetProcessWindowStation(), UOI_NAME, szCurrentWindowStation, (sizeof(szCurrentWindowStation) / sizeof(TCHAR)), NULL ); if (!bReturnValue) { BOINCTRACE(_T("Failed to retrieve the current window station.\n")); } bReturnValue = GetUserObjectInformation( GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, szCurrentDesktop, (sizeof(szCurrentDesktop) / sizeof(TCHAR)), NULL ); if (!bReturnValue) { BOINCTRACE(_T("Failed to retrieve the current desktop.\n")); } } // Tell the boinc client to start the screen saver BOINCTRACE(_T("CScreensaver::StartupBOINC - Calling set_screensaver_mode - WindowStation = '%s', Desktop = '%s', BlankScreen = '%d', BlankTime = '%d'.\n"), szCurrentWindowStation, szCurrentDesktop, m_dwBlankScreen, m_dwBlankTime); if ( 0 == m_dwBlankScreen ) iReturnValue = rpc.set_screensaver_mode(true, szCurrentWindowStation, szCurrentDesktop, 0); else iReturnValue = rpc.set_screensaver_mode(true, szCurrentWindowStation, szCurrentDesktop, m_dwBlankTime); BOINCTRACE(_T("CScreensaver::StartupBOINC - set_screensaver_mode iReturnValue = '%d'\n"), iReturnValue); // We have now notified the boinc client if ( 0 == iReturnValue ) m_bCoreNotified = TRUE; else { m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCNOTDETECTED; } } } } //----------------------------------------------------------------------------- // Name: RenderBOINC() // Desc: Notifies BOINC that it has to start the screensaver in full screen mode. //----------------------------------------------------------------------------- VOID CScreensaver::ShutdownBOINC() { if( m_bCoreNotified ) { // Tell the boinc client to stop the screen saver rpc.set_screensaver_mode(false, NULL, NULL, 0.0); // We have now notified the boinc client m_bCoreNotified = FALSE; } } //----------------------------------------------------------------------------- // Name: ParseCommandLine() // Desc: Interpret command-line parameters passed to this app. //----------------------------------------------------------------------------- SaverMode CScreensaver::ParseCommandLine( TCHAR* pstrCommandLine ) { m_hWndParent = NULL; BOINCTRACE("ParseCommandLine: '%s'\n", pstrCommandLine); // Skip the first part of the command line, which is the full path // to the exe. If it contains spaces, it will be contained in quotes. if (*pstrCommandLine == _T('\"')) { pstrCommandLine++; while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T('\"')) pstrCommandLine++; if( *pstrCommandLine == _T('\"') ) pstrCommandLine++; } else { while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T(' ')) pstrCommandLine++; if( *pstrCommandLine == _T(' ') ) pstrCommandLine++; } // Skip along to the first option delimiter "/" or "-" while ( *pstrCommandLine != _T('\0') && *pstrCommandLine != _T('/') && *pstrCommandLine != _T('-') ) pstrCommandLine++; // If there wasn't one, then must be config mode if ( *pstrCommandLine == _T('\0') ) return sm_config; // Otherwise see what the option was switch ( *(++pstrCommandLine) ) { case 'c': case 'C': pstrCommandLine++; while ( *pstrCommandLine && !isdigit(*pstrCommandLine) ) pstrCommandLine++; if ( isdigit(*pstrCommandLine) ) { #ifdef _WIN64 m_hWndParent = HWND(_atoi64(pstrCommandLine)); #else m_hWndParent = HWND(_ttol(pstrCommandLine)); #endif } else { m_hWndParent = NULL; } return sm_config; case 't': case 'T': return sm_test; case 'p': case 'P': // Preview-mode, so option is followed by the parent HWND in decimal pstrCommandLine++; while ( *pstrCommandLine && !isdigit(*pstrCommandLine) ) pstrCommandLine++; if ( isdigit(*pstrCommandLine) ) { #ifdef _WIN64 m_hWndParent = HWND(_atoi64(pstrCommandLine)); #else m_hWndParent = HWND(_ttol(pstrCommandLine)); #endif } return sm_preview; case 'a': case 'A': // Password change mode, so option is followed by parent HWND in decimal pstrCommandLine++; while ( *pstrCommandLine && !isdigit(*pstrCommandLine) ) pstrCommandLine++; if ( isdigit(*pstrCommandLine) ) { #ifdef _WIN64 m_hWndParent = HWND(_atoi64(pstrCommandLine)); #else m_hWndParent = HWND(_ttol(pstrCommandLine)); #endif } return sm_passwordchange; default: // All other options => run the screensaver (typically this is "/s") return sm_full; } } //----------------------------------------------------------------------------- // Name: EnumMonitors() // Desc: Determine HMONITOR, desktop rect, and other info for each monitor. // Note that EnumDisplayDevices enumerates monitors in the order // indicated on the Settings page of the Display control panel, which // is the order we want to list monitors in, as opposed to the order // used by D3D's GetAdapterInfo. //----------------------------------------------------------------------------- VOID CScreensaver::EnumMonitors( VOID ) { DWORD iDevice = 0; DISPLAY_DEVICE_FULL dispdev; DISPLAY_DEVICE_FULL dispdev2; DEVMODE devmode; dispdev.cb = sizeof(dispdev); dispdev2.cb = sizeof(dispdev2); devmode.dmSize = sizeof(devmode); devmode.dmDriverExtra = 0; INTERNALMONITORINFO* pMonitorInfoNew; while( EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0) ) { // Ignore NetMeeting's mirrored displays if( (dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 ) { // To get monitor info for a display device, call EnumDisplayDevices // a second time, passing dispdev.DeviceName (from the first call) as // the first parameter. EnumDisplayDevices(dispdev.DeviceName, 0, (DISPLAY_DEVICE*)&dispdev2, 0); pMonitorInfoNew = &m_Monitors[m_dwNumMonitors]; ZeroMemory( pMonitorInfoNew, sizeof(INTERNALMONITORINFO) ); StringCchCopy( pMonitorInfoNew->strDeviceName, 128, dispdev.DeviceString ); StringCchCopy( pMonitorInfoNew->strMonitorName, 128, dispdev2.DeviceString ); if( dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP ) { EnumDisplaySettings( dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode ); if( dispdev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE ) { // For some reason devmode.dmPosition is not always (0, 0) // for the primary display, so force it. pMonitorInfoNew->rcScreen.left = 0; pMonitorInfoNew->rcScreen.top = 0; } else { pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x; pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y; } pMonitorInfoNew->rcScreen.right = pMonitorInfoNew->rcScreen.left + devmode.dmPelsWidth; pMonitorInfoNew->rcScreen.bottom = pMonitorInfoNew->rcScreen.top + devmode.dmPelsHeight; pMonitorInfoNew->hMonitor = MonitorFromRect( &pMonitorInfoNew->rcScreen, MONITOR_DEFAULTTONULL ); } m_dwNumMonitors++; if( m_dwNumMonitors == MAX_DISPLAYS ) break; } iDevice++; } } //----------------------------------------------------------------------------- // Name: CreateSaverWindow // Desc: Register and create the appropriate window(s) //----------------------------------------------------------------------------- HRESULT CScreensaver::CreateSaverWindow() { // Register an appropriate window class for the primary display WNDCLASS cls; cls.hCursor = LoadCursor( NULL, IDC_ARROW ); cls.hIcon = LoadIcon( m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ); cls.lpszMenuName = NULL; cls.lpszClassName = _T("BOINCPrimarySaverWndClass"); cls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); cls.hInstance = m_hInstance; cls.style = CS_VREDRAW|CS_HREDRAW; cls.lpfnWndProc = PrimarySaverProcStub; cls.cbWndExtra = 0; cls.cbClsExtra = 0; RegisterClass( &cls ); // Register an appropriate window class for the secondary display(s) WNDCLASS cls2; cls2.hCursor = LoadCursor( NULL, IDC_ARROW ); cls2.hIcon = LoadIcon( m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ); cls2.lpszMenuName = NULL; cls2.lpszClassName = _T("BOINCGenericSaverWndClass"); cls2.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); cls2.hInstance = m_hInstance; cls2.style = CS_VREDRAW|CS_HREDRAW; cls2.lpfnWndProc = GenericSaverProcStub; cls2.cbWndExtra = 0; cls2.cbClsExtra = 0; RegisterClass( &cls2 ); // Create the window RECT rc; DWORD dwStyle; switch ( m_SaverMode ) { case sm_preview: GetClientRect( m_hWndParent, &rc ); dwStyle = WS_VISIBLE | WS_CHILD; AdjustWindowRect( &rc, dwStyle, FALSE ); m_hWnd = CreateWindow( _T("BOINCPrimarySaverWndClass"), m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, m_hWndParent, NULL, m_hInstance, this ); m_Monitors[0].hWnd = m_hWnd; GetClientRect( m_hWnd, &m_rcRenderTotal ); GetClientRect( m_hWnd, &m_rcRenderCurDevice ); break; case sm_test: rc.left = rc.top = 50; rc.right = rc.left+600; rc.bottom = rc.top+400; dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; AdjustWindowRect( &rc, dwStyle, FALSE ); m_hWnd = CreateWindow( _T("BOINCPrimarySaverWndClass"), m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, m_hInstance, this ); m_Monitors[0].hWnd = m_hWnd; GetClientRect( m_hWnd, &m_rcRenderTotal ); GetClientRect( m_hWnd, &m_rcRenderCurDevice ); SetTimer(m_hWnd, 2, 60000, NULL); break; case sm_full: dwStyle = WS_VISIBLE | WS_POPUP; m_hWnd = NULL; for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ ) { INTERNALMONITORINFO* pMonitorInfo; pMonitorInfo = &m_Monitors[iMonitor]; if( pMonitorInfo->hWnd == NULL ) { if( pMonitorInfo->hMonitor == NULL ) continue; rc = pMonitorInfo->rcScreen; if( 0 == iMonitor ) { pMonitorInfo->hWnd = CreateWindowEx( WS_EX_TOPMOST, _T("BOINCPrimarySaverWndClass"), m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, m_hInstance, this ); } else { pMonitorInfo->hWnd = CreateWindowEx( WS_EX_TOPMOST, _T("BOINCGenericSaverWndClass"), m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, m_hInstance, this ); } if( pMonitorInfo->hWnd == NULL ) return E_FAIL; if( m_hWnd == NULL ) m_hWnd = pMonitorInfo->hWnd; SetTimer(pMonitorInfo->hWnd, 2, 1000, NULL); } } } if ( m_hWnd == NULL ) return E_FAIL; return S_OK; } //----------------------------------------------------------------------------- // Name: DoSaver() // Desc: Run the screensaver graphics - may be preview, test or full-on mode //----------------------------------------------------------------------------- HRESULT CScreensaver::DoSaver() { // If we're in full on mode, and on 9x, then need to load the password DLL if ( m_SaverMode == sm_full && m_bIs9x ) { // Only do this if the password is set - check registry: HKEY hKey; if ( RegOpenKey( HKEY_CURRENT_USER , REGSTR_PATH_SCREENSAVE , &hKey ) == ERROR_SUCCESS ) { DWORD dwVal; DWORD dwSize = sizeof(dwVal); if ( (RegQueryValueEx( hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL, (BYTE *)&dwVal, &dwSize ) == ERROR_SUCCESS) && dwVal ) { m_hPasswordDLL = LoadLibrary( _T("PASSWORD.CPL") ); if ( m_hPasswordDLL ) m_VerifySaverPassword = (VERIFYPWDPROC)GetProcAddress( m_hPasswordDLL, _T("VerifyScreenSavePwd") ); RegCloseKey( hKey ); } } } // Flag as screensaver running if in full on mode if ( m_SaverMode == sm_full ) { BOOL bUnused; SystemParametersInfo( SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0 ); } // Message pump BOOL bGotMsg; MSG msg; msg.message = WM_NULL; while ( msg.message != WM_QUIT ) { bGotMsg = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ); if( bGotMsg ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Sleep(10); } } return S_OK; } //----------------------------------------------------------------------------- // Name: DoConfig() // Desc: //----------------------------------------------------------------------------- VOID CScreensaver::DoConfig() { DialogBox( NULL, MAKEINTRESOURCE(DLG_CONFIG), m_hWndParent, ConfigureDialogProcStub ); } //----------------------------------------------------------------------------- // Name: PrimarySaverProc() // Desc: Handle window messages for main screensaver windows (one per screen). //----------------------------------------------------------------------------- LRESULT CScreensaver::PrimarySaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_USER: // All initialization messages have gone through. Allow // 500ms of idle time, then proceed with initialization. SetTimer( hWnd, 1, 500, NULL ); break; case WM_TIMER: switch (wParam) { case 1: // Initial idle time is done, proceed with initialization. m_bWaitForInputIdle = FALSE; KillTimer( hWnd, 1 ); break; case 2: // Loop through the update loop ( Timer 3 ) up to ten times in // the begining to allow the screensaver to get its initial // state all setup. After that the update loop will update // the data to display, if anything, every 30 seconds. // // NOTE: Sometimes it takes BOINC a few tries before it finds // an application that it can really display. An application // can state that it supports graphics but still can't start // due to permission problems when attempting to transition // accross the window station/desktop boundry. if ( 9 >= m_dwTimerCounter ) m_dwTimerCounter++; if ( 8 >= m_dwTimerCounter ) { if ( m_bErrorMode ) { m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCSCREENSAVERLOADING; } UpdateErrorBoxText(); UpdateErrorBox(); } else if ( 9 == m_dwTimerCounter ) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Starting Update Timer\n")); SetTimer(hWnd, 3, 30000, NULL); } else { if ( m_bErrorMode ) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Updating Error Box\n")); UpdateErrorBox(); } else { InvalidateRect( hWnd, NULL, TRUE ); UpdateWindow( hWnd ); } if ( 10 >= m_dwTimerCounter ) break; } case 3: // Except for the initial startup sequence, this is run every // 30 seconds. HWND hwndBOINCGraphicsWindow = NULL; HWND hwndForegroundWindow = NULL; int iReturnValue = 0; // Create a screen saver window on the primary display if the boinc client crashes CreateSaverWindow(); BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Start Status = '%d', CoreNotified = '%d', ErrorMode = '%d', ErrorCode = '%x'\n"), m_iStatus, m_bCoreNotified, m_bErrorMode, m_hrError); iReturnValue = rpc.get_screensaver_mode( m_iStatus ); BOINCTRACE(_T("CScreensaver::PrimarySaverProc - get_screensaver_mode iReturnValue = '%d'\n"), iReturnValue); if (0 != iReturnValue) { // Attempt to reinitialize the RPC client and state rpc.close(); rpc.init( NULL ); m_bResetCoreState = TRUE; if (!m_bBOINCConfigChecked) { m_bBOINCConfigChecked = TRUE; m_bBOINCStartupConfigured = IsConfigStartupBOINC(); } if(m_bBOINCStartupConfigured) { m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCNOTDETECTED; } else { m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCNOTDETECTEDSTARTUP; } m_bCoreNotified = FALSE; } else { // Reset the error flags. m_bErrorMode = FALSE; m_hrError = 0; if (m_bCoreNotified) { switch (m_iStatus) { case SS_STATUS_ENABLED: hwndBOINCGraphicsWindow = FindWindow( BOINC_WINDOW_CLASS_NAME, NULL ); if ( NULL != hwndBOINCGraphicsWindow ) { hwndForegroundWindow = GetForegroundWindow(); if ( hwndForegroundWindow != hwndBOINCGraphicsWindow ) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Graphics Window Detected but NOT the foreground window, bringing window to foreground.\n")); SetForegroundWindow(hwndBOINCGraphicsWindow); hwndForegroundWindow = GetForegroundWindow(); if ( hwndForegroundWindow != hwndBOINCGraphicsWindow ) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Graphics Window Detected but NOT the foreground window, bringing window to foreground. (Final Try)\n")); // This may be needed on Windows 2000 or better machines DWORD dwComponents = BSM_APPLICATIONS; BroadcastSystemMessage( BSF_ALLOWSFW, &dwComponents, WM_BOINCSFW, NULL, NULL ); } } } m_bErrorMode = FALSE; m_hrError = FALSE; break; case SS_STATUS_BLANKED: m_bErrorMode = FALSE; m_hrError = FALSE; break; case SS_STATUS_RESTARTREQUEST: m_bCoreNotified = FALSE; m_bErrorMode = FALSE; m_hrError = FALSE; break; case SS_STATUS_BOINCSUSPENDED: m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCSUSPENDED; break; case SS_STATUS_NOAPPSEXECUTING: m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCNOAPPSEXECUTING; break; case SS_STATUS_NOTGRAPHICSCAPABLE: case SS_STATUS_NOGRAPHICSAPPSEXECUTING: m_bErrorMode = TRUE; m_hrError = SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING; break; } } } BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Checkpoint Status = '%d', CoreNotified = '%d', ErrorMode = '%d', ErrorCode = '%x'\n"), m_iStatus, m_bCoreNotified, m_bErrorMode, m_hrError); // Lets try and get the current state of the CC if ( m_bResetCoreState && m_bCoreNotified ) { iReturnValue = rpc.get_state( state ); if ( 0 == iReturnValue ) m_bResetCoreState = FALSE; BOINCTRACE(_T("CScreensaver::PrimarySaverProc - get_state iReturnValue = '%d'\n"), iReturnValue); } if( m_bErrorMode ) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Updating Error Box Text\n")); UpdateErrorBoxText(); } else { if ( !m_bCoreNotified ) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Startup BOINC Screensaver\n")); StartupBOINC(); } else { if (SS_STATUS_QUIT == m_iStatus) { BOINCTRACE(_T("CScreensaver::PrimarySaverProc - Shutdown BOINC Screensaver\n")); ShutdownSaver(); } } } BOINCTRACE(_T("CScreensaver::PrimarySaverProc - End Status = '%d', CoreNotified = '%d', ErrorMode = '%d', ErrorCode = '%x'\n"), m_iStatus, m_bCoreNotified, m_bErrorMode, m_hrError); } break; case WM_DESTROY: if( m_SaverMode == sm_preview || m_SaverMode == sm_test ) ShutdownSaver(); break; case WM_SETCURSOR: if ( m_SaverMode == sm_full && !m_bCheckingSaverPassword ) { // Hide cursor SetCursor( NULL ); return TRUE; } break; case WM_PAINT: { // 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( !m_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 ); } EndPaint( hWnd, &ps ); return 0; } case WM_MOUSEMOVE: if( m_SaverMode != sm_test ) { static INT xPrev = -1; static INT yPrev = -1; INT xCur = GET_X_LPARAM(lParam); INT yCur = GET_Y_LPARAM(lParam); if( xCur != xPrev || yCur != yPrev ) { xPrev = xCur; yPrev = yCur; m_dwSaverMouseMoveCount++; if ( m_dwSaverMouseMoveCount > 5 ) InterruptSaver(); } } break; case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: if( m_SaverMode != sm_test ) InterruptSaver(); break; case WM_NCACTIVATE: case WM_ACTIVATEAPP: return 0; break; case WM_POWERBROADCAST: if( wParam == PBT_APMSUSPEND && m_VerifySaverPassword == NULL ) InterruptSaver(); break; case WM_SYSCOMMAND: if ( m_SaverMode == sm_full ) { switch ( wParam ) { case SC_NEXTWINDOW: case SC_PREVWINDOW: case SC_SCREENSAVE: case SC_CLOSE: return FALSE; }; } break; } BOINCTRACE(_T("PrimarySaverProc hWnd '%d' uMsg '%X' wParam '%d' lParam '%d'\n"), hWnd, uMsg, wParam, lParam); return DefWindowProc( hWnd, uMsg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: GenericSaverProc() // Desc: Handle window messages for main screensaver windows (one per screen). //----------------------------------------------------------------------------- LRESULT CScreensaver::GenericSaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_USER: // All initialization messages have gone through. Allow // 500ms of idle time, then proceed with initialization. SetTimer( hWnd, 1, 500, NULL ); break; case WM_TIMER: switch (wParam) { case 1: // Initial idle time is done, proceed with initialization. m_bWaitForInputIdle = FALSE; KillTimer( hWnd, 1 ); break; case 2: if ( 10 >= m_dwTimerCounter ) { if ( !m_bErrorMode ) { InvalidateRect( hWnd, NULL, TRUE ); UpdateWindow( hWnd ); } } } break; case WM_DESTROY: if( m_SaverMode == sm_preview || m_SaverMode == sm_test ) ShutdownSaver(); break; case WM_SETCURSOR: if ( m_SaverMode == sm_full && !m_bCheckingSaverPassword ) { // Hide cursor SetCursor( NULL ); return TRUE; } break; case WM_PAINT: { // 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( !m_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 ); } EndPaint( hWnd, &ps ); return 0; } case WM_MOUSEMOVE: if( m_SaverMode != sm_test ) { static INT xPrev = -1; static INT yPrev = -1; INT xCur = GET_X_LPARAM(lParam); INT yCur = GET_Y_LPARAM(lParam); if( xCur != xPrev || yCur != yPrev ) { xPrev = xCur; yPrev = yCur; m_dwSaverMouseMoveCount++; if ( m_dwSaverMouseMoveCount > 5 ) InterruptSaver(); } } break; case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: if( m_SaverMode != sm_test ) InterruptSaver(); break; case WM_ACTIVATEAPP: if( wParam == FALSE && m_SaverMode != sm_test ) InterruptSaver(); break; case WM_POWERBROADCAST: if( wParam == PBT_APMSUSPEND && m_VerifySaverPassword == NULL ) InterruptSaver(); break; case WM_SYSCOMMAND: if ( m_SaverMode == sm_full ) { switch ( wParam ) { case SC_NEXTWINDOW: case SC_PREVWINDOW: case SC_SCREENSAVE: case SC_CLOSE: return FALSE; }; } break; } BOINCTRACE(_T("GenericSaverProc hWnd '%d' uMsg '%X' wParam '%d' lParam '%d'\n"), hWnd, uMsg, wParam, lParam); return DefWindowProc( hWnd, uMsg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: ConfigureDialogProc() // Desc: //----------------------------------------------------------------------------- INT_PTR CScreensaver::ConfigureDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { DWORD screen_blank=0, blank_time=0; char buf[256]; int retval; switch (msg) { case WM_INITDIALOG: // make sure you check return value of registry queries // in case the item in question doesn't happen to exist. retval = UtilGetRegKey( REG_BLANK_NAME, screen_blank ); if ( retval < 0 ) { screen_blank=0; } CheckDlgButton( hwnd, IDC_BLANK, screen_blank ); retval = UtilGetRegKey( REG_BLANK_TIME, blank_time ); if ( retval < 0 ) { blank_time=0; } _ltot(blank_time, buf, 10); SetDlgItemText( hwnd, IDC_BLANK_TIME, buf ); return TRUE; case WM_COMMAND: int id=LOWORD(wParam); if (id==IDOK) { screen_blank = ( IsDlgButtonChecked( hwnd, IDC_BLANK ) == BST_CHECKED ); UtilSetRegKey( REG_BLANK_NAME, screen_blank ); GetDlgItemText( hwnd, IDC_BLANK_TIME, buf, 256 ); blank_time = atoi( buf ); UtilSetRegKey( REG_BLANK_TIME, blank_time ); } if ( id == IDOK || id == IDCANCEL ) EndDialog( hwnd, id ); break; } return FALSE; } //----------------------------------------------------------------------------- // Name: PrimarySaverProcStub() // Desc: This function forwards all window messages to SaverProc, which has // access to the "this" pointer. //----------------------------------------------------------------------------- LRESULT CALLBACK CScreensaver::PrimarySaverProcStub( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { return gs_pScreensaver->PrimarySaverProc( hWnd, uMsg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: GenericSaverProcStub() // Desc: This function forwards all window messages to SaverProc, which has // access to the "this" pointer. //----------------------------------------------------------------------------- LRESULT CALLBACK CScreensaver::GenericSaverProcStub( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { return gs_pScreensaver->GenericSaverProc( hWnd, uMsg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: ConfigureDialogProcStub() // Desc: //----------------------------------------------------------------------------- INT_PTR CALLBACK CScreensaver::ConfigureDialogProcStub( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { return gs_pScreensaver->ConfigureDialogProc( hwndDlg, uMsg, wParam, lParam ); } ////////// // Function: UtilSetRegKey // arguments: name: name of key, keyval: where to store value of key // returns: int indicating error // function: reads string value in specified key int CScreensaver::UtilSetRegKey(LPCTSTR name, DWORD value) { LONG error; HKEY boinc_key; if ( m_bIs9x ) { error = RegCreateKeyEx( HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &boinc_key, NULL ); if ( error != ERROR_SUCCESS ) return -1; } else { error = RegCreateKeyEx( HKEY_CURRENT_USER, _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &boinc_key, NULL ); if ( error != ERROR_SUCCESS ) return -1; } error = RegSetValueEx( boinc_key, name, 0, REG_DWORD, (CONST BYTE *)&value, 4 ); RegCloseKey( boinc_key ); return 0; } ////////// // Function: UtilGetRegKey // arguments: name: name of key, keyval: where to store value of key // returns: int indicating error // function: reads string value in specified key int CScreensaver::UtilGetRegKey(LPCTSTR name, DWORD &keyval) { LONG error; DWORD type = REG_DWORD; DWORD size = sizeof( DWORD ); DWORD value; HKEY boinc_key; if ( m_bIs9x ) { error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"), 0, KEY_ALL_ACCESS, &boinc_key ); if ( error != ERROR_SUCCESS ) return -1; } else { error = RegOpenKeyEx( HKEY_CURRENT_USER, _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"), 0, KEY_ALL_ACCESS, &boinc_key ); if ( error != ERROR_SUCCESS ) return -1; } error = RegQueryValueEx( boinc_key, name, NULL, &type, (BYTE *)&value, &size ); keyval = value; RegCloseKey( boinc_key ); if ( error != ERROR_SUCCESS ) return -1; return 0; } ////////// // Function: UtilGetRegStartupStr // arguments: name: name of key, str: value of string to store // if str is empty, attepts to delete the key // returns: int indicating error // function: sets string value in specified key in windows startup dir int CScreensaver::UtilGetRegStartupStr(LPCTSTR name, LPTSTR str) { LONG error; DWORD type = REG_SZ; DWORD size = 128; HKEY boinc_key; *str = 0; if ( m_bIs9x ) { error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_ALL_ACCESS, &boinc_key ); if ( error != ERROR_SUCCESS ) return -1; } else { error = RegOpenKeyEx( HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_ALL_ACCESS, &boinc_key ); if ( error != ERROR_SUCCESS ) return -1; } error = RegQueryValueEx( boinc_key, name, NULL, &type, (BYTE*)str, &size ); RegCloseKey( boinc_key ); if ( error != ERROR_SUCCESS ) return -1; return ERROR_SUCCESS; } //----------------------------------------------------------------------------- // Name: ShutdownSaver() // Desc: //----------------------------------------------------------------------------- VOID CScreensaver::ShutdownSaver() { // Unflag screensaver running if in full on mode if ( m_SaverMode == sm_full ) { BOOL bUnused; SystemParametersInfo( SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0 ); } // Unload the password DLL (if we loaded it) if ( m_hPasswordDLL != NULL ) { FreeLibrary( m_hPasswordDLL ); m_hPasswordDLL = NULL; } ShutdownBOINC(); // Post message to drop out of message loop PostQuitMessage( 0 ); } //----------------------------------------------------------------------------- // Name: InterruptSaver() // Desc: A message was received (mouse move, keydown, etc.) that may mean // the screen saver should show the password dialog and/or shut down. //----------------------------------------------------------------------------- VOID CScreensaver::InterruptSaver() { BOOL bPasswordOkay = FALSE; if( m_SaverMode == sm_test || m_SaverMode == sm_full && !m_bCheckingSaverPassword ) { if( m_bIs9x && m_SaverMode == sm_full ) { // If no VerifyPassword function, then no password is set // or we're not on 9x. if ( m_VerifySaverPassword != NULL ) { m_bCheckingSaverPassword = TRUE; bPasswordOkay = m_VerifySaverPassword( m_hWnd ); m_bCheckingSaverPassword = FALSE; if ( !bPasswordOkay ) { // Back to screen saving... SetCursor( NULL ); m_dwSaverMouseMoveCount = 0; return; } } } ShutdownSaver(); } } //----------------------------------------------------------------------------- // Name: UpdateErrorBox() // Desc: Update the box that shows the error message //----------------------------------------------------------------------------- VOID CScreensaver::UpdateErrorBox() { INTERNALMONITORINFO* pMonitorInfo; HWND hwnd; RECT rcBounds; static DWORD dwTimeLast = 0; DWORD dwTimeNow; FLOAT fTimeDelta; // Update timing to determine how much to move error box if( dwTimeLast == 0 ) dwTimeLast = timeGetTime(); dwTimeNow = timeGetTime(); fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 1000.0f; dwTimeLast = dwTimeNow; for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ ) { pMonitorInfo = &m_Monitors[iMonitor]; hwnd = pMonitorInfo->hWnd; if( hwnd == NULL ) continue; if( m_SaverMode == sm_full ) { rcBounds = pMonitorInfo->rcScreen; ScreenToClient( hwnd, (POINT*)&rcBounds.left ); ScreenToClient( hwnd, (POINT*)&rcBounds.right ); } else { rcBounds = m_rcRenderTotal; } if( pMonitorInfo->widthError == 0 ) { if( m_SaverMode == sm_preview ) { pMonitorInfo->widthError = (float) (rcBounds.right - rcBounds.left); pMonitorInfo->heightError = (float) (rcBounds.bottom - rcBounds.top); pMonitorInfo->xError = 0.0f; pMonitorInfo->yError = 0.0f; pMonitorInfo->xVelError = 0.0f; pMonitorInfo->yVelError = 0.0f; InvalidateRect( hwnd, NULL, FALSE ); // Invalidate the hwnd so it gets drawn UpdateWindow( hwnd ); } else { pMonitorInfo->widthError = 500; pMonitorInfo->heightError = 154; pMonitorInfo->xError = (rcBounds.right + rcBounds.left - pMonitorInfo->widthError) / 2.0f; pMonitorInfo->yError = (rcBounds.bottom + rcBounds.top - pMonitorInfo->heightError) / 2.0f; pMonitorInfo->xVelError = (rcBounds.right - rcBounds.left) / 10.0f; pMonitorInfo->yVelError = (rcBounds.bottom - rcBounds.top) / 20.0f; } } else { if( m_SaverMode != sm_preview ) { RECT rcOld; RECT rcNew; SetRect( &rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError, (INT)(pMonitorInfo->xError + pMonitorInfo->widthError), (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) ); // Update rect velocity if( (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta + pMonitorInfo->widthError > rcBounds.right && pMonitorInfo->xVelError > 0.0f) || (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta < rcBounds.left && pMonitorInfo->xVelError < 0.0f) ) { pMonitorInfo->xVelError = -pMonitorInfo->xVelError; } if( (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta + pMonitorInfo->heightError > rcBounds.bottom && pMonitorInfo->yVelError > 0.0f) || (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta < rcBounds.top && pMonitorInfo->yVelError < 0.0f) ) { pMonitorInfo->yVelError = -pMonitorInfo->yVelError; } // Update rect position pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta; pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta; SetRect( &rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError, (INT)(pMonitorInfo->xError + pMonitorInfo->widthError), (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) ); if( ( rcOld.left != rcNew.left || rcOld.top != rcNew.top ) && ( 10 <= (time(0) - pMonitorInfo->tLastRefresh) ) ) { pMonitorInfo->tLastRefresh = time(0); InvalidateRect( hwnd, NULL, TRUE ); UpdateWindow( hwnd ); } } } } } //----------------------------------------------------------------------------- // Name: UpdateErrorBoxText() // Desc: Update the error message //----------------------------------------------------------------------------- VOID CScreensaver::UpdateErrorBoxText() { RESULTS results; PROJECT* pProject; TCHAR szBuffer[256]; bool bIsActive = false; bool bIsExecuting = false; bool bIsDownloaded = false; int iResultCount = 0; int iIndex = 0; float fProgress = 0; // Load error string GetTextForError( m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR) ); if( SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING == m_hrError ) { if( 0 == rpc.get_results( results ) ) { iResultCount = results.results.size(); for ( iIndex = 0; iIndex < iResultCount; iIndex++ ) { bIsDownloaded = ( RESULT_FILES_DOWNLOADED == results.results.at(iIndex)->state ); bIsActive = ( results.results.at(iIndex)->active_task ); bIsExecuting = ( CPU_SCHED_SCHEDULED == results.results.at(iIndex)->scheduler_state ); if ( !( bIsActive ) || !( bIsDownloaded ) || !( bIsExecuting ) ) continue; pProject = state.lookup_project( results.results.at( iIndex )->project_url ); if ( NULL != pProject ) { StringCbPrintf( szBuffer, sizeof(szBuffer) / sizeof(TCHAR), _T("%s: %.2f%%\n"), pProject->project_name.c_str(), results.results.at(iIndex)->fraction_done * 100 ); StringCbCat( m_szError, sizeof(m_szError) / sizeof(TCHAR), szBuffer ); } else { m_bResetCoreState = TRUE; } } m_szError[ sizeof(m_szError) -1 ] = '\0'; BOINCTRACE(_T("CScreensaver::UpdateErrorBoxText - Updated Text '%s'\n"), m_szError); } } } //----------------------------------------------------------------------------- // Name: GetTextForError() // Desc: Translate an HRESULT error code into a string that can be displayed // to explain the error. A class derived from CD3DScreensaver can // provide its own version of this function that provides app-specific // error translation instead of or in addition to calling this function. // This function returns TRUE if a specific error was translated, or // FALSE if no specific translation for the HRESULT was found (though // it still puts a generic string into pszError). //----------------------------------------------------------------------------- BOOL CScreensaver::GetTextForError( HRESULT hr, TCHAR* pszError, DWORD dwNumChars ) { const DWORD dwErrorMap[][2] = { // HRESULT, stringID E_FAIL, IDS_ERR_GENERIC, E_OUTOFMEMORY, IDS_ERR_OUTOFMEMORY, SCRAPPERR_BOINCNOTDETECTED, IDS_ERR_BOINCNOTDETECTED, SCRAPPERR_BOINCNOTDETECTEDSTARTUP, IDS_ERR_BOINCNOTDETECTEDSTARTUP, SCRAPPERR_BOINCSUSPENDED, IDS_ERR_BOINCSUSPENDED, SCRAPPERR_BOINCNOAPPSEXECUTING, IDS_ERR_BOINCNOAPPSEXECUTING, SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING, IDS_ERR_BOINCNOGRAPHICSAPPSEXECUTING, SCRAPPERR_BOINCSCREENSAVERLOADING, IDS_ERR_BOINCSCREENSAVERLOADING, SCRAPPERR_NOPREVIEW, IDS_ERR_NOPREVIEW }; const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]); DWORD iError; DWORD resid = 0; for( iError = 0; iError < dwErrorMapSize; iError++ ) { if( hr == (HRESULT)dwErrorMap[iError][0] ) { resid = dwErrorMap[iError][1]; } } if( resid == 0 ) { resid = IDS_ERR_GENERIC; } LoadString( NULL, resid, pszError, dwNumChars ); if( resid == IDS_ERR_GENERIC ) return FALSE; else return TRUE; } //----------------------------------------------------------------------------- // Name: DoPaint() // Desc: //----------------------------------------------------------------------------- VOID CScreensaver::DoPaint(HWND hwnd, HDC hdc) { HMONITOR hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); INTERNALMONITORINFO* pMonitorInfo; for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) { pMonitorInfo = &m_Monitors[iMonitor]; if( pMonitorInfo->hMonitor == hMonitor ) break; } if( iMonitor == m_dwNumMonitors ) return; // Draw the error message box RECT rc; RECT rc2; RECT rcOrginal; int iTextHeight; static HBRUSH hbrushBlack = (HBRUSH)GetStockObject( BLACK_BRUSH ); static HBRUSH hbrushRed = (HBRUSH)CreateSolidBrush( RGB(255,0,0) ); static HBITMAP hbmp = LoadBitmap( m_hInstance, MAKEINTRESOURCE(IDB_BOINCSPLAT) ); // If the screensaver has switched to a blanked state or not in an error mode, // we should exit here so the screen has been erased to black. if ( (SS_STATUS_BLANKED == m_iStatus) || !m_bErrorMode ) { BOINCTRACE(_T("CScreensaver::DoPaint - Blank Screen Detected\n"), m_szError); rc = pMonitorInfo->rcScreen; ScreenToClient( hwnd, (POINT*)&rc.left ); ScreenToClient( hwnd, (POINT*)&rc.right ); FillRect(hdc, &rc, hbrushBlack ); return; } SetRect( &rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError, (INT)(pMonitorInfo->xError + pMonitorInfo->widthError), (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) ); SetRect( &rcOrginal, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError, (INT)(pMonitorInfo->xError + pMonitorInfo->widthError), (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) ); // Draw the background as black. FillRect(hdc, &rc, hbrushBlack); // Draw a frame in red. FrameRect(hdc, &rc, hbrushRed); // Draw the bitmap rectangle and copy the bitmap into // it. the bitmap is centered in the rectangle by adding 2 // to the left and top coordinates of the bitmap rectangle, // and subtracting 4 from the right and bottom coordinates. DrawTransparentBitmap(hdc, hbmp, (rc.left + 2), (rc.top + 2), RGB(129, 129, 129)); rc.left += 166; // Draw text in the center of the frame SetBkColor(hdc, RGB(0,0,0)); // Black SetTextColor(hdc, RGB(255,255,255)); // Red rc2 = rc; iTextHeight = DrawText(hdc, m_szError, -1, &rc, DT_CENTER | DT_CALCRECT ); rc = rc2; rc2.top = (rc.bottom + rc.top - iTextHeight) / 2; DrawText(hdc, m_szError, -1, &rc2, DT_CENTER ); // Erase everywhere except the error message box ExcludeClipRect( hdc, rcOrginal.left, rcOrginal.top, rcOrginal.right, rcOrginal.bottom ); rc = pMonitorInfo->rcScreen; ScreenToClient( hwnd, (POINT*)&rc.left ); ScreenToClient( hwnd, (POINT*)&rc.right ); FillRect(hdc, &rc, hbrushBlack ); } //----------------------------------------------------------------------------- // Name: ChangePassword() // Desc: //----------------------------------------------------------------------------- VOID CScreensaver::ChangePassword() { // Load the password change DLL HINSTANCE mpr = LoadLibrary( _T("MPR.DLL") ); if ( mpr != NULL ) { // Grab the password change function from it typedef DWORD (PASCAL *PWCHGPROC)( LPCSTR, HWND, DWORD, LPVOID ); PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, "PwdChangePasswordA" ); // Do the password change if ( pwd != NULL ) pwd( "SCRSAVE", m_hWndParent, 0, NULL ); // Free the library FreeLibrary( mpr ); } } //----------------------------------------------------------------------------- // Name: DisplayErrorMsg() // Desc: Displays error messages in a message box //----------------------------------------------------------------------------- HRESULT CScreensaver::DisplayErrorMsg( HRESULT hr ) { TCHAR strMsg[512]; GetTextForError( hr, strMsg, 512 ); MessageBox( m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK ); return hr; } //----------------------------------------------------------------------------- // Name: DrawTransparentBitmap() // Desc: Draws a bitmap on the screen with a transparent background. // Code orginally from Microsoft Knowledge Base Article - 79212 //----------------------------------------------------------------------------- void CScreensaver::DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, LONG xStart, LONG yStart, COLORREF cTransparentColor) { BITMAP bm; COLORREF cColor; HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave; HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld; HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave; POINT ptSize; hdcTemp = CreateCompatibleDC(hdc); SelectObject(hdcTemp, hBitmap); // Select the bitmap GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm); ptSize.x = bm.bmWidth; // Get width of bitmap ptSize.y = bm.bmHeight; // Get height of bitmap DPtoLP(hdcTemp, &ptSize, 1); // Convert from device // to logical points // Create some DCs to hold temporary data. hdcBack = CreateCompatibleDC(hdc); hdcObject = CreateCompatibleDC(hdc); hdcMem = CreateCompatibleDC(hdc); hdcSave = CreateCompatibleDC(hdc); // Create a bitmap for each DC. DCs are required for a number of // GDI functions. // Monochrome DC bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL); // Monochrome DC bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL); bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y); bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y); // Each DC must select a bitmap object to store pixel data. bmBackOld = (HBITMAP)SelectObject(hdcBack, bmAndBack); bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject); bmMemOld = (HBITMAP)SelectObject(hdcMem, bmAndMem); bmSaveOld = (HBITMAP)SelectObject(hdcSave, bmSave); // Set proper mapping mode. SetMapMode(hdcTemp, GetMapMode(hdc)); // Save the bitmap sent here, because it will be overwritten. BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY); // Set the background color of the source DC to the color. // contained in the parts of the bitmap that should be transparent cColor = SetBkColor(hdcTemp, cTransparentColor); // Create the object mask for the bitmap by performing a BitBlt // from the source bitmap to a monochrome bitmap. BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY); // Set the background color of the source DC back to the original // color. SetBkColor(hdcTemp, cColor); // Create the inverse of the object mask. BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY); // Copy the background of the main DC to the destination. BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart, SRCCOPY); // Mask out the places where the bitmap will be placed. BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND); // Mask out the transparent colored pixels on the bitmap. BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND); // XOR the bitmap with the background on the destination DC. BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT); // Copy the destination to the screen. BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY); // Place the original bitmap back into the bitmap sent here. BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY); // Delete the memory bitmaps. DeleteObject(SelectObject(hdcBack, bmBackOld)); DeleteObject(SelectObject(hdcObject, bmObjectOld)); DeleteObject(SelectObject(hdcMem, bmMemOld)); DeleteObject(SelectObject(hdcSave, bmSaveOld)); // Delete the memory DCs. DeleteDC(hdcMem); DeleteDC(hdcBack); DeleteDC(hdcObject); DeleteDC(hdcSave); DeleteDC(hdcTemp); } //----------------------------------------------------------------------------- // Name: IsConfigStatupBOINC() // Desc: Determine if BOINC is configured to automatically start at logon/startup. //----------------------------------------------------------------------------- // Define dynamically linked to function typedef HRESULT (STDAPICALLTYPE* MYSHGETFOLDERPATH)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath); BOOL CScreensaver::IsConfigStartupBOINC() { BOOL bRetVal; BOOL bCheckFileExists; TCHAR szBuffer[MAX_PATH]; HANDLE hFileHandle; HMODULE hShell32; MYSHGETFOLDERPATH pfnMySHGetFolderPath = NULL; // Lets set the default value to FALSE bRetVal = FALSE; // Attempt to link to dynamic function if it exists hShell32 = LoadLibrary(_T("SHELL32.DLL")); if ( NULL != hShell32 ) pfnMySHGetFolderPath = (MYSHGETFOLDERPATH) GetProcAddress(hShell32, _T("SHGetFolderPathA")); // Now lets begin looking in the registry if (ERROR_SUCCESS == UtilGetRegStartupStr(REG_STARTUP_NAME, szBuffer)) { bRetVal = TRUE; } else { // It could be in the global startup group ZeroMemory( szBuffer, sizeof(szBuffer) ); bCheckFileExists = FALSE; if ( NULL != pfnMySHGetFolderPath ) { if (SUCCEEDED((pfnMySHGetFolderPath)(NULL, CSIDL_STARTUP|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szBuffer))) { BOINCTRACE(_T("IsConfigStartupBOINC: pfnMySHGetFolderPath - CSIDL_STARTUP - '%s'\n"), szBuffer); if (SUCCEEDED(StringCchCatN(szBuffer, sizeof(szBuffer), BOINC_SHORTCUT_NAME, sizeof(BOINC_SHORTCUT_NAME)))) { BOINCTRACE(_T("IsConfigStartupBOINC: Final pfnMySHGetFolderPath - CSIDL_STARTUP - '%s'\n"), szBuffer); bCheckFileExists = TRUE; } else { BOINCTRACE(_T("IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_STARTUP Append Operation\n")); } } else { BOINCTRACE(_T("IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_STARTUP\n")); } } if (bCheckFileExists) { hFileHandle = CreateFile( szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFileHandle) { BOINCTRACE(_T("IsConfigStartupBOINC: CreateFile returned a valid handle '%d'\n"), hFileHandle); CloseHandle(hFileHandle); bRetVal = TRUE; } else { BOINCTRACE(_T("IsConfigStartupBOINC: CreateFile returned INVALID_HANDLE_VALUE - GetLastError() '%d'\n"), GetLastError()); // It could be in the global startup group ZeroMemory( szBuffer, sizeof(szBuffer) ); bCheckFileExists = FALSE; if ( NULL != pfnMySHGetFolderPath ) { if (SUCCEEDED((pfnMySHGetFolderPath)(NULL, CSIDL_COMMON_STARTUP|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szBuffer))) { BOINCTRACE(_T("IsConfigStartupBOINC: pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP - '%s'\n"), szBuffer); if (SUCCEEDED(StringCchCatN(szBuffer, sizeof(szBuffer), BOINC_SHORTCUT_NAME, sizeof(BOINC_SHORTCUT_NAME)))) { BOINCTRACE(_T("IsConfigStartupBOINC: Final pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP - '%s'\n"), szBuffer); bCheckFileExists = TRUE; } else { BOINCTRACE(_T("IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP Append Operation\n")); } } else { BOINCTRACE(_T("IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP\n")); } } if (bCheckFileExists) { hFileHandle = CreateFile( szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFileHandle) { BOINCTRACE(_T("IsConfigStartupBOINC: CreateFile returned a valid handle '%d'\n"), hFileHandle); CloseHandle(hFileHandle); bRetVal = TRUE; } else { BOINCTRACE(_T("IsConfigStartupBOINC: CreateFile returned INVALID_HANDLE_VALUE - GetLastError() '%d'\n"), GetLastError()); } } } } } // Free the dynamically linked to library FreeLibrary(hShell32); BOINCTRACE(_T("IsConfigStartupBOINC: Returning '%d'\n"), bRetVal); return bRetVal; } const char *BOINC_RCSID_116268c72f = "$Id$";