1
// Berkeley Open Infrastructure for Network Computing
2
// http://boinc.berkeley.edu
3
// Copyright (C) 2005 University of California
5
// This is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation;
8
// either version 2.1 of the License, or (at your option) any later version.
10
// This software is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
// See the GNU Lesser General Public License for more details.
15
// To view the GNU Lesser General Public License visit
16
// http://www.gnu.org/copyleft/lesser.html
17
// or write to the Free Software Foundation, Inc.,
18
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
// DirectX 8.1 Screen Saver Framework from Microsoft.
22
// Microsoft Knowledge Base Article - 79212
25
#include "boinc_win.h"
32
#define COMPILE_MULTIMON_STUBS
35
#include "diagnostics.h"
36
#include "common_defs.h"
38
#include "gui_rpc_client.h"
39
#include "screensaver.h"
40
#include "screensaver_win.h"
49
static HMODULE gshUser32 = NULL;
50
static HMODULE gshPasswordCPL = NULL;
51
static VERIFYPWDPROC gspfnMyVerifyPwdProc = NULL;
52
static MYGETLASTINPUTINFO gspfnMyGetLastInputInfo = NULL;
53
static MYISHUNGAPPWINDOW gspfnMyIsHungAppWindow = NULL;
54
static MYBROADCASTSYSTEMMESSAGE gspfnMyBroadcastSystemMessage = NULL;
55
static CScreensaver* gspScreensaver = NULL;
57
const UINT WM_SETTIMER = RegisterWindowMessage(TEXT("BOINCSetTimer"));
58
const UINT WM_INTERRUPTSAVER = RegisterWindowMessage(TEXT("BOINCInterruptScreensaver"));
59
const UINT WM_BOINCSFW = RegisterWindowMessage(TEXT("BOINCSetForegroundWindow"));
63
HINSTANCE hInstance, HINSTANCE UNUSED(hPrevInstance), LPSTR UNUSED(lpCmdLine), int UNUSED(nCmdShow)
72
DWORD dwSize = sizeof(dwVal);
76
// Initialize Diagnostics
77
retval = diagnostics_init (
78
BOINC_DIAG_DUMPCALLSTACKENABLED |
79
BOINC_DIAG_HEAPCHECKENABLED |
80
BOINC_DIAG_MEMORYLEAKCHECKENABLED |
81
BOINC_DIAG_ARCHIVESTDOUT |
82
BOINC_DIAG_REDIRECTSTDOUTOVERWRITE |
83
BOINC_DIAG_REDIRECTSTDERROVERWRITE |
84
BOINC_DIAG_TRACETOSTDOUT,
89
BOINCTRACE("WinMain - BOINC Screensaver Diagnostic Error '%d'\n", retval);
90
MessageBox(NULL, NULL, "BOINC Screensaver Diagnostic Error", MB_OK);
94
// Figure out if we're on Win9x
96
osvi.dwOSVersionInfoSize = sizeof(osvi);
98
bIs9x = osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;
99
bIs95 = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
100
((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0));
102
// Load dynamically linked modules
103
gshUser32 = LoadLibrary(_T("USER32.DLL"));
105
gshPasswordCPL = LoadLibrary(_T("PASSWORD.CPL"));
108
// Map function pointers
110
gspfnMyGetLastInputInfo = (MYGETLASTINPUTINFO) GetProcAddress(gshUser32, _T("GetLastInputInfo"));
111
gspfnMyIsHungAppWindow = (MYISHUNGAPPWINDOW) GetProcAddress(gshUser32, _T("IsHungAppWindow"));
113
gspfnMyBroadcastSystemMessage = (MYBROADCASTSYSTEMMESSAGE) GetProcAddress(gshUser32, _T("BroadcastSystemMessage"));
115
gspfnMyBroadcastSystemMessage = (MYBROADCASTSYSTEMMESSAGE) GetProcAddress(gshUser32, _T("BroadcastSystemMessageA"));
118
if (gshPasswordCPL) {
119
if (RegOpenKey(HKEY_CURRENT_USER , REGSTR_PATH_SCREENSAVE , &hKey) == ERROR_SUCCESS) {
120
if ((RegQueryValueEx(hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL, (BYTE *)&dwVal, &dwSize) == ERROR_SUCCESS) && dwVal) {
121
gspfnMyVerifyPwdProc = (VERIFYPWDPROC)GetProcAddress(gshPasswordCPL, _T("VerifyScreenSavePwd"));
127
// Initialize the CRT random number generator.
128
srand((unsigned int)time(0));
130
// Initialize the Windows sockets interface.
131
retval = WSAStartup(MAKEWORD(1, 1), &wsdata);
133
BOINCTRACE("WinMain - Winsock Initialization Failure '%d'\n", retval);
137
if (FAILED(hr = BOINCSS.Create(hInstance))) {
138
BOINCSS.DisplayErrorMsg(hr);
143
retval = BOINCSS.Run();
145
// Cleanup the Windows sockets interface.
148
// Clean up function pointers.
149
gspfnMyGetLastInputInfo = NULL;
150
gspfnMyIsHungAppWindow = NULL;
151
gspfnMyBroadcastSystemMessage = NULL;
152
gspfnMyVerifyPwdProc = NULL;
155
FreeLibrary(gshUser32);
156
if (gshPasswordCPL) {
157
FreeLibrary(gshPasswordCPL);
158
gshPasswordCPL = NULL;
165
CScreensaver::CScreensaver() {
166
gspScreensaver = this;
168
m_bCheckingSaverPassword = FALSE;
170
m_dwSaverMouseMoveCount = 0;
174
m_bAllScreensSame = FALSE;
176
m_bWaitForInputIdle = FALSE;
178
m_bErrorMode = FALSE;
180
m_szError[0] = _T('\0');
182
LoadString(NULL, IDS_DESCRIPTION, m_strWindowTitle, 200);
184
m_bPaintingInitialized = FALSE;
189
m_hDataManagementThread = NULL;
190
m_hGraphicsApplication = NULL;
191
m_bResetCoreState = TRUE;
192
m_QuitDataManagementProc = FALSE;
193
m_bBOINCConfigChecked = FALSE;
194
m_bBOINCStartupConfigured = FALSE;
195
memset(&m_running_result, 0, sizeof(m_running_result));
197
ZeroMemory(m_Monitors, sizeof(m_Monitors));
200
m_dwLastInputTimeAtStartup = 0;
201
m_tThreadCreateTime = 0;
205
// Have the client program call this function before calling Run().
207
HRESULT CScreensaver::Create(HINSTANCE hInstance) {
211
m_hInstance = hInstance;
213
// Parse the command line and do the appropriate thing
214
m_SaverMode = ParseCommandLine(GetCommandLine());
216
// Figure out if we're on Win9x
218
osvi.dwOSVersionInfoSize = sizeof(osvi);
220
m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
222
// Store last input value if it exists
223
if (gspfnMyGetLastInputInfo) {
225
lii.cbSize = sizeof(LASTINPUTINFO);
227
gspfnMyGetLastInputInfo(&lii);
229
m_dwLastInputTimeAtStartup = lii.dwTime;
232
// Enumerate Monitors
235
// Retrieve the blank screen flag so we can determine if we are
236
// suppose to actually blank the screen at some point.
237
bReturnValue = UtilGetRegKey(REG_BLANK_NAME, m_dwBlankScreen);
238
BOINCTRACE("CScreensaver::Create - Get Reg Key REG_BLANK_NAME return value '%d'\n", bReturnValue);
239
if (bReturnValue != 0) m_dwBlankScreen = 0;
241
// Retrieve the blank screen timeout
242
// make sure you check return value of registry queries
243
// in case the item in question doesn't happen to exist.
244
bReturnValue = UtilGetRegKey(REG_BLANK_TIME, m_dwBlankTime);
245
BOINCTRACE("CScreensaver::Create - Get Reg Key REG_BLANK_TIME return value '%d'\n", bReturnValue);
246
if (bReturnValue != 0) m_dwBlankTime = 5;
248
// Save the value back to the registry in case this is the first
249
// execution and so we need the default value later.
250
bReturnValue = UtilSetRegKey(REG_BLANK_NAME, m_dwBlankScreen);
251
BOINCTRACE("CScreensaver::Create - Set Reg Key REG_BLANK_NAME return value '%d'\n", bReturnValue);
253
bReturnValue = UtilSetRegKey(REG_BLANK_TIME, m_dwBlankTime);
254
BOINCTRACE("CScreensaver::Create - Set Reg Key REG_BLANK_TIME return value '%d'\n", bReturnValue);
256
// Calculate the estimated blank time by adding the current time
257
// and and the user specified time which is in minutes
258
m_dwBlankTime = (DWORD)time(0) + (m_dwBlankTime * 60);
260
// Create the infrastructure mutexes so we can properly aquire them to report
262
if (!CreateInfrastructureMutexes()) {
266
if (rpc == NULL) rpc = new RPC_CLIENT;
268
// Create the screen saver window(s)
269
if (m_SaverMode == sm_preview ||
270
m_SaverMode == sm_full
272
if (FAILED(hr = CreateSaverWindow())) {
277
if (m_SaverMode == sm_preview) {
278
// In preview mode, "pause" (enter a limited message loop) briefly
279
// before proceeding, so the display control panel knows to update itself.
280
m_bWaitForInputIdle = TRUE;
282
// Post a message to mark the end of the initial group of window messages
283
PostMessage(m_hWnd, WM_SETTIMER, 0, 0);
286
while(m_bWaitForInputIdle) {
287
// If GetMessage returns FALSE, it's quitting time.
288
if (!GetMessage(&msg, m_hWnd, 0, 0)) {
289
// Post the quit message to handle it later
294
TranslateMessage(&msg);
295
DispatchMessage(&msg);
305
// Starts main execution of the screen saver.
307
INT CScreensaver::Run() {
311
// Parse the command line and do the appropriate thing
312
switch (m_SaverMode) {
315
DisplayErrorMsg(m_hrError);
322
rpc->get_host_info(hostinfo);
326
// In Windows, preview mode is for the mini-view of the screensaver.
327
// For BOINC we just display the icon, so there is no need to
328
// startup the data management thread which in turn will
329
// launch a graphics application.
330
if (FAILED(hr = DoSaver())) {
335
// Create the data management thread to talk with the daemon
336
if (!CreateDataManagementThread()) {
340
if (FAILED(hr = DoSaver())) {
344
// Create the data management thread to talk with the daemon
346
if (!DestroyDataManagementThread()) {
355
case sm_passwordchange:
366
// Displays error messages in a message box
368
HRESULT CScreensaver::DisplayErrorMsg(HRESULT hr) {
371
GetTextForError(hr, strMsg, 512);
373
MessageBox(m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK);
381
// Interpret command-line parameters passed to this app.
383
SaverMode CScreensaver::ParseCommandLine(TCHAR* pstrCommandLine) {
386
BOINCTRACE("ParseCommandLine: '%s'\n", pstrCommandLine);
388
// Skip the first part of the command line, which is the full path
389
// to the exe. If it contains spaces, it will be contained in quotes.
390
if (*pstrCommandLine == _T('\"')) {
392
while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T('\"')) {
395
if (*pstrCommandLine == _T('\"')) {
399
while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T(' ')) {
402
if (*pstrCommandLine == _T(' ')) {
407
// Skip along to the first option delimiter "/" or "-"
408
while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T('/') && *pstrCommandLine != _T('-')) {
412
// If there wasn't one, then must be config mode
413
if (*pstrCommandLine == _T('\0')) {
417
// Otherwise see what the option was
418
switch (*(++pstrCommandLine)) {
422
while (*pstrCommandLine && !isdigit(*pstrCommandLine)) {
425
if (isdigit(*pstrCommandLine)) {
427
m_hWndParent = (HWND)_atoi64(pstrCommandLine);
429
m_hWndParent = (HWND)_ttol(pstrCommandLine);
442
// Preview-mode, so option is followed by the parent HWND in decimal
444
while (*pstrCommandLine && !isdigit(*pstrCommandLine)) {
447
if (isdigit(*pstrCommandLine)) {
449
m_hWndParent = (HWND)_atoi64(pstrCommandLine);
451
m_hWndParent = (HWND)_ttol(pstrCommandLine);
458
// Password change mode, so option is followed by parent HWND in decimal
460
while (*pstrCommandLine && !isdigit(*pstrCommandLine)) {
463
if (isdigit(*pstrCommandLine)) {
465
m_hWndParent = (HWND)_atoi64(pstrCommandLine);
467
m_hWndParent = (HWND)_ttol(pstrCommandLine);
470
return sm_passwordchange;
473
// All other options => run the screensaver (typically this is "/s")
481
// Determine HMONITOR, desktop rect, and other info for each monitor.
482
// Note that EnumDisplayDevices enumerates monitors in the order
483
// indicated on the Settings page of the Display control panel, which
484
// is the order we want to list monitors in, as opposed to the order
485
// used by D3D's GetAdapterInfo.
487
VOID CScreensaver::EnumMonitors(VOID) {
489
DISPLAY_DEVICE_FULL dispdev;
490
DISPLAY_DEVICE_FULL dispdev2;
492
dispdev.cb = sizeof(dispdev);
493
dispdev2.cb = sizeof(dispdev2);
494
devmode.dmSize = sizeof(devmode);
495
devmode.dmDriverExtra = 0;
496
INTERNALMONITORINFO* pMonitorInfoNew;
497
while(EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0)) {
498
// Ignore NetMeeting's mirrored displays
499
if ((dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0) {
500
// To get monitor info for a display device, call EnumDisplayDevices
501
// a second time, passing dispdev.DeviceName (from the first call) as
502
// the first parameter.
503
EnumDisplayDevices(dispdev.DeviceName, 0, (DISPLAY_DEVICE*)&dispdev2, 0);
505
pMonitorInfoNew = &m_Monitors[m_dwNumMonitors];
506
ZeroMemory(pMonitorInfoNew, sizeof(INTERNALMONITORINFO));
507
StringCchCopy(pMonitorInfoNew->strDeviceName, 128, dispdev.DeviceString);
508
StringCchCopy(pMonitorInfoNew->strMonitorName, 128, dispdev2.DeviceString);
510
if (dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
511
EnumDisplaySettings(dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode);
512
if (dispdev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
513
// For some reason devmode.dmPosition is not always (0, 0)
514
// for the primary display, so force it.
515
pMonitorInfoNew->rcScreen.left = 0;
516
pMonitorInfoNew->rcScreen.top = 0;
518
pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x;
519
pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y;
521
pMonitorInfoNew->rcScreen.right = pMonitorInfoNew->rcScreen.left + devmode.dmPelsWidth;
522
pMonitorInfoNew->rcScreen.bottom = pMonitorInfoNew->rcScreen.top + devmode.dmPelsHeight;
523
pMonitorInfoNew->hMonitor = MonitorFromRect(&pMonitorInfoNew->rcScreen, MONITOR_DEFAULTTONULL);
526
if (m_dwNumMonitors == MAX_DISPLAYS) {
537
// arguments: name: name of key, keyval: where to store value of key
538
// returns: int indicating error
539
// function: reads string value in specified key
541
int CScreensaver::UtilSetRegKey(LPCTSTR name, DWORD value) {
546
error = RegCreateKeyEx(
548
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),
551
REG_OPTION_NON_VOLATILE,
552
KEY_READ | KEY_WRITE,
557
if (error != ERROR_SUCCESS) return -1;
559
error = RegCreateKeyEx(
561
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),
564
REG_OPTION_NON_VOLATILE,
565
KEY_READ | KEY_WRITE,
570
if (error != ERROR_SUCCESS) return -1;
573
error = RegSetValueEx(boinc_key, name, 0, REG_DWORD, (CONST BYTE *)&value, 4);
575
RegCloseKey(boinc_key);
583
// arguments: name: name of key, keyval: where to store value of key
584
// returns: int indicating error
585
// function: reads string value in specified key
587
int CScreensaver::UtilGetRegKey(LPCTSTR name, DWORD &keyval) {
589
DWORD type = REG_DWORD;
590
DWORD size = sizeof(DWORD);
595
error = RegOpenKeyEx(
597
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),
602
if (error != ERROR_SUCCESS) return -1;
604
error = RegOpenKeyEx(
606
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),
611
if (error != ERROR_SUCCESS) return -1;
614
error = RegQueryValueEx(boinc_key, name, NULL, &type, (BYTE *)&value, &size);
618
RegCloseKey(boinc_key);
620
if (error != ERROR_SUCCESS) return -1;
628
// arguments: name: name of key, str: value of string to store
629
// if str is empty, attepts to delete the key
630
// returns: int indicating error
631
// function: sets string value in specified key in windows startup dir
633
int CScreensaver::UtilGetRegStartupStr(LPCTSTR name, LPTSTR str) {
642
error = RegOpenKeyEx(
644
_T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
649
if (error != ERROR_SUCCESS) return -1;
651
error = RegOpenKeyEx(
653
_T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
658
if (error != ERROR_SUCCESS) return -1;
661
error = RegQueryValueEx(boinc_key, name, NULL, &type, (BYTE*)str, &size);
663
RegCloseKey(boinc_key);
665
if (error != ERROR_SUCCESS) return -1;
667
return ERROR_SUCCESS;
673
// Determine if BOINC is configured to automatically start at logon/startup.
675
BOOL CScreensaver::IsConfigStartupBOINC() {
677
BOOL bCheckFileExists;
678
TCHAR szBuffer[MAX_PATH];
679
TCHAR szShortcutBuffer[MAX_PATH];
682
MYSHGETFOLDERPATH pfnMySHGetFolderPath = NULL;
685
// Lets set the default value to FALSE
688
// Load the shortcut filename into the shortcut buffer.
689
LoadString(NULL, IDS_SHORTCUTNAME, szShortcutBuffer, sizeof(szShortcutBuffer)/sizeof(TCHAR));
691
// Attempt to link to dynamic function if it exists
692
hShell32 = LoadLibrary(_T("SHELL32.DLL"));
693
if (NULL != hShell32)
694
pfnMySHGetFolderPath = (MYSHGETFOLDERPATH) GetProcAddress(hShell32, _T("SHGetFolderPathA"));
697
// Now lets begin looking in the registry
698
if (ERROR_SUCCESS == UtilGetRegStartupStr(REG_STARTUP_NAME, szBuffer)) {
701
// It could be in the global startup group
702
ZeroMemory(szBuffer, sizeof(szBuffer));
703
bCheckFileExists = FALSE;
704
if (NULL != pfnMySHGetFolderPath) {
705
if (SUCCEEDED((pfnMySHGetFolderPath)(NULL, CSIDL_STARTUP|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szBuffer))) {
706
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: pfnMySHGetFolderPath - CSIDL_STARTUP - '%s'\n"), szBuffer);
707
StringCchCatN(szBuffer, sizeof(szBuffer), _T("\\"), sizeof(_T("\\"))/sizeof(TCHAR));
708
if (SUCCEEDED(StringCchCatN(szBuffer, sizeof(szBuffer), szShortcutBuffer, sizeof(szShortcutBuffer)/sizeof(TCHAR)))) {
709
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: Final pfnMySHGetFolderPath - CSIDL_STARTUP - '%s'\n"), szBuffer);
710
bCheckFileExists = TRUE;
712
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_STARTUP Append Operation\n"));
715
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_STARTUP\n"));
720
if (bCheckFileExists) {
721
hFileHandle = CreateFile(
727
FILE_ATTRIBUTE_NORMAL,
730
if (INVALID_HANDLE_VALUE != hFileHandle) {
731
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned a valid handle '%d'\n"), hFileHandle);
732
CloseHandle(hFileHandle);
735
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned INVALID_HANDLE_VALUE - GetLastError() '%d'\n"), GetLastError());
737
// It could be in the global startup group
738
ZeroMemory(szBuffer, sizeof(szBuffer));
739
bCheckFileExists = FALSE;
740
if (NULL != pfnMySHGetFolderPath) {
741
if (SUCCEEDED((pfnMySHGetFolderPath)(NULL, CSIDL_COMMON_STARTUP|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szBuffer))) {
742
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP - '%s'\n"), szBuffer);
743
StringCchCatN(szBuffer, sizeof(szBuffer), _T("\\"), sizeof(_T("\\"))/sizeof(TCHAR));
744
if (SUCCEEDED(StringCchCatN(szBuffer, sizeof(szBuffer), szShortcutBuffer, sizeof(szShortcutBuffer)/sizeof(TCHAR)))) {
745
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: Final pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP - '%s'\n"), szBuffer);
746
bCheckFileExists = TRUE;
748
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP Append Operation\n"));
751
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP\n"));
756
if (bCheckFileExists) {
757
hFileHandle = CreateFile(
763
FILE_ATTRIBUTE_NORMAL,
766
if (INVALID_HANDLE_VALUE != hFileHandle) {
767
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned a valid handle '%d'\n"), hFileHandle);
768
CloseHandle(hFileHandle);
771
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned INVALID_HANDLE_VALUE - GetLastError() '%d'\n"), GetLastError());
778
// Free the dynamically linked to library
779
FreeLibrary(hShell32);
781
BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: Returning '%d'\n"), bRetVal);
788
// Desc: Create the infrastructure for thread safe acccess to the infrastructure
789
// layer of the screen saver.
791
BOOL CScreensaver::CreateInfrastructureMutexes() {
792
m_hErrorManagementMutex = CreateMutex(NULL, FALSE, NULL);
793
if (NULL == m_hErrorManagementMutex) {
794
BOINCTRACE(_T("CScreensaver::CreateInfrastructureMutexes: Failed to create m_hErrorManagementMutex '%d'\n"), GetLastError());
803
// Provide a thread-safe implementation for retrieving the current
806
BOOL CScreensaver::GetError(
807
BOOL& bErrorMode, HRESULT& hrError, TCHAR* pszError, size_t iErrorSize
810
BOOL bRetVal = FALSE;
812
// Request ownership of mutex.
813
dwWaitResult = WaitForSingleObject(
814
m_hErrorManagementMutex, // handle to mutex
815
5000L); // five-second time-out interval
817
switch (dwWaitResult) {
818
// WAIT_OBJECT_0 - The thread got mutex ownership.
820
bErrorMode = m_bErrorMode;
823
if (NULL != pszError) {
824
StringCbCopyN(pszError, iErrorSize, m_szError, sizeof(m_szError) * sizeof(TCHAR));
830
// WAIT_TIMEOUT - Cannot get mutex ownership due to time-out.
831
// WAIT_ABANDONED - Got ownership of the abandoned mutex object.
837
ReleaseMutex(m_hErrorManagementMutex);
845
// Provide a thread-safe implementation for setting the current
846
// error condition. This API should only be called in the data management
847
// thread, any other thread may cause a race condition.
849
BOOL CScreensaver::SetError(BOOL bErrorMode, HRESULT hrError) {
851
BOOL bRetVal = FALSE;
853
// Request ownership of mutex.
854
dwWaitResult = WaitForSingleObject(
855
m_hErrorManagementMutex, // handle to mutex
856
5000L // five-second time-out interval
859
switch (dwWaitResult) {
860
// WAIT_OBJECT_0 - The thread got mutex ownership.
862
m_bErrorMode = bErrorMode;
865
// Update the error text, including a possible RPC call
867
UpdateErrorBoxText();
872
// WAIT_TIMEOUT - Cannot get mutex ownership due to time-out.
873
// WAIT_ABANDONED - Got ownership of the abandoned mutex object.
878
ReleaseMutex(m_hErrorManagementMutex);
884
// Update the error message
886
VOID CScreensaver::UpdateErrorBoxText() {
888
bool bIsActive = false;
889
bool bIsExecuting = false;
890
bool bIsDownloaded = false;
891
size_t iResultCount = 0;
895
if ((SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING == m_hrError)
896
|| (SCRAPPERR_DAEMONALLOWSNOGRAPHICS == m_hrError)
898
if (m_updating_results) return; // results vector is currently being updated by rpc
900
iResultCount = results.results.size();
902
for (iIndex = 0; iIndex < iResultCount; iIndex++) {
903
// cycle through the active results starting from the last one
904
iModIndex = (iIndex + m_iLastResultShown+1) % iResultCount;
905
bIsDownloaded = (RESULT_FILES_DOWNLOADED == results.results.at(iModIndex)->state);
906
bIsActive = (results.results.at(iModIndex)->active_task);
907
bIsExecuting = (CPU_SCHED_SCHEDULED == results.results.at(iModIndex)->scheduler_state);
908
if (!(bIsActive) || !(bIsDownloaded) || !(bIsExecuting)) continue;
909
pProject = state.lookup_project(results.results.at(iModIndex)->project_url);
910
if (NULL != pProject) {
911
RESULT* pResult = state.lookup_result(pProject, results.results.at(iModIndex)->name);
912
if ( pResult != NULL ) {
913
BOINCTRACE(_T("CScreensaver::UpdateErrorBoxText - Display result. iIndex=%d, iModIndex=%d, lastResult=%d\n"), iIndex, iModIndex, m_iLastResultShown);
914
StringCbPrintf(m_szError, sizeof(m_szError) / sizeof(TCHAR),
915
_T("\nComputing for %s\nApplication: %s\nTask: %s\n%.2f%% complete\n"),
916
pProject->project_name.c_str(),
917
pResult->app->user_friendly_name.c_str(),
918
pResult->wu_name.c_str(),
919
results.results.at(iModIndex)->fraction_done*100
921
if ( m_tLastResultChangeTime+10 < time(0) ) {
922
m_iLastResultShown = iModIndex;
923
m_tLastResultChangeTime = time(0);
927
m_bResetCoreState = TRUE;
928
GetTextForError(IDS_ERR_GENERIC, m_szError, sizeof(m_szError) / sizeof(TCHAR));
931
m_bResetCoreState = TRUE;
932
GetTextForError(IDS_ERR_GENERIC, m_szError, sizeof(m_szError) / sizeof(TCHAR));
935
m_szError[ sizeof(m_szError) -1 ] = '\0';
938
GetTextForError(m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR));
940
BOINCTRACE(_T("CScreensaver::UpdateErrorBoxText - Updated Text '%s'\n"), m_szError);
946
// Translate an HRESULT error code into a string that can be displayed
947
// to explain the error. A class derived from CD3DScreensaver can
948
// provide its own version of this function that provides app-specific
949
// error translation instead of or in addition to calling this function.
950
// This function returns TRUE if a specific error was translated, or
951
// FALSE if no specific translation for the HRESULT was found (though
952
// it still puts a generic string into pszError).
954
BOOL CScreensaver::GetTextForError(
955
HRESULT hr, TCHAR* pszError, DWORD dwNumChars
957
const DWORD dwErrorMap[][2] = {
959
E_FAIL, IDS_ERR_GENERIC,
960
E_OUTOFMEMORY, IDS_ERR_OUTOFMEMORY,
961
SCRAPPERR_BOINCNOTDETECTED, IDS_ERR_BOINCNOTDETECTED,
962
SCRAPPERR_BOINCNOTDETECTEDSTARTUP, IDS_ERR_BOINCNOTDETECTEDSTARTUP,
963
SCRAPPERR_BOINCSUSPENDED, IDS_ERR_BOINCSUSPENDED,
964
SCRAPPERR_BOINCNOAPPSEXECUTING, IDS_ERR_BOINCNOAPPSEXECUTING,
965
SCRAPPERR_BOINCNOPROJECTSDETECTED, IDS_ERR_BOINCNOAPPSEXECUTINGNOPROJECTSDETECTED,
966
SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING, IDS_ERR_BOINCNOGRAPHICSAPPSEXECUTING,
967
SCRAPPERR_BOINCSCREENSAVERLOADING, IDS_ERR_BOINCSCREENSAVERLOADING,
968
SCRAPPERR_BOINCAPPFOUNDGRAPHICSLOADING, IDS_ERR_BOINCAPPFOUNDGRAPHICSLOADING,
969
SCRAPPERR_BOINCSHUTDOWNEVENT, IDS_ERR_BOINCSHUTDOWNEVENT,
970
SCRAPPERR_NOPREVIEW, IDS_ERR_NOPREVIEW,
971
SCRAPPERR_DAEMONALLOWSNOGRAPHICS, IDS_ERR_DAEMONALLOWSNOGRAPHICS
973
const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]);
978
for(iError = 0; iError < dwErrorMapSize; iError++) {
979
if (hr == (HRESULT)dwErrorMap[iError][0]) {
980
resid = dwErrorMap[iError][1];
984
resid = IDS_ERR_GENERIC;
987
LoadString(NULL, resid, pszError, dwNumChars);
989
if (resid == IDS_ERR_GENERIC) {
998
// Create the thread that is used to talk to the daemon.
1000
BOOL CScreensaver::CreateDataManagementThread() {
1001
DWORD dwThreadID = 0;
1002
BOINCTRACE(_T("CScreensaver::CreateDataManagementThread Start\n"));
1003
m_QuitDataManagementProc = FALSE;
1004
m_hDataManagementThread = CreateThread(
1005
NULL, // default security attributes
1006
0, // use default stack size
1007
DataManagementProcStub, // thread function
1008
NULL, // argument to thread function
1009
0, // use default creation flags
1010
&dwThreadID ); // returns the thread identifier
1012
if (m_hDataManagementThread == NULL) {
1013
BOINCTRACE(_T("CScreensaver::CreateDataManagementThread: Failed to create data management thread '%d'\n"), GetLastError());
1022
// Terminate the thread that is used to talk to the daemon.
1024
BOOL CScreensaver::DestroyDataManagementThread() {
1025
m_QuitDataManagementProc = TRUE; // Tell RPC Thread to exit
1027
// Wait up to 5 seconds for DataManagementThread to exit
1028
for (int i=0; i<50; i++) {
1029
DWORD dwStatus = STILL_ACTIVE;
1030
BOOL bRetVal = FALSE;
1033
bRetVal = GetExitCodeThread(m_hDataManagementThread, &dwStatus);
1034
BOINCTRACE(_T("CScreensaver::DestroyDataManagementThread - GetExitCodeThread RetVal = '%d', Status = '%d'\n"), bRetVal, dwStatus);
1035
if (bRetVal && (dwStatus != STILL_ACTIVE)) {
1045
// This function forwards to DataManagementProc, which has access to the
1048
DWORD WINAPI CScreensaver::DataManagementProcStub(LPVOID UNUSED(lpParam)) {
1049
return gspScreensaver->DataManagementProc();
1055
void CScreensaver::HandleRPCError()
1057
// Attempt to reinitialize the RPC client and state
1060
m_bResetCoreState = TRUE;
1062
if (!m_bBOINCConfigChecked) {
1063
m_bBOINCConfigChecked = TRUE;
1064
m_bBOINCStartupConfigured = IsConfigStartupBOINC();
1067
if ((time(0) - m_tThreadCreateTime) > 3) {
1068
if (m_bBOINCStartupConfigured) {
1069
SetError(TRUE, SCRAPPERR_BOINCNOTDETECTED);
1071
SetError(TRUE, SCRAPPERR_BOINCNOTDETECTEDSTARTUP);
1080
void CScreensaver::CheckForegroundWindow()
1082
BOOL bForegroundWindowIsScreensaver;
1083
HWND hwndBOINCGraphicsWindow = NULL;
1084
HWND hwndForeWindow = NULL;
1085
HWND hwndForeParent = NULL;
1087
INTERNALMONITORINFO* pMonitorInfo = NULL;
1089
// When running in screensaver mode the only two valid conditions for z-order
1090
// is that either the screensaver or graphics application is the foreground
1091
// application. If this is not true, then blow out of the screensaver.
1092
hwndBOINCGraphicsWindow = FindWindow(BOINC_WINDOW_CLASS_NAME, NULL);
1093
if (hwndBOINCGraphicsWindow) {
1094
// Graphics Application.
1095
hwndForeWindow = GetForegroundWindow();
1096
// If the graphics application is not the top most window try and force it
1098
if (hwndForeWindow != hwndBOINCGraphicsWindow) {
1099
BOINCTRACE(_T("CScreensaver::CheckForegroundWindow - Graphics Window Detected but NOT the foreground window, bringing window to foreground.\n"));
1100
SetForegroundWindow(hwndBOINCGraphicsWindow);
1101
hwndForeWindow = GetForegroundWindow();
1102
if (hwndForeWindow != hwndBOINCGraphicsWindow) {
1103
BOINCTRACE(_T("CScreensaver::CheckForegroundWindow - Graphics Window Detected but NOT the foreground window, bringing window to foreground. (Final Try)\n"));
1105
// This may be needed on Windows 2000 or better machines
1106
if (gspfnMyBroadcastSystemMessage) {
1107
DWORD dwComponents = BSM_APPLICATIONS;
1108
gspfnMyBroadcastSystemMessage(
1118
// Science application has focus, and is visible.
1120
// Some science application take a really long time to display something on their
1121
// window, during this time the window will appear to eat keyboard and mouse event
1122
// messages and not respond to other system events. These windows are considered
1123
// ghost windows, normally they have an outline and can be moved around and resized.
1124
// In the science application case where the borders are hidden from view, the
1125
// window just takes on the background of the previous window which happens to be
1126
// the black screensaver window owned by this process.
1128
// Verify that their hasn't been any keyboard or mouse activity. If there has
1129
// we should hide the window from this process and exit out of the screensaver to
1130
// return control back to the user as quickly as possible.
1131
BOINCTRACE(_T("CScreensaver::CheckForegroundWindow - Graphics Window Detected and is the foreground window.\n"));
1132
if (gspfnMyGetLastInputInfo) {
1133
BOINCTRACE(_T("CScreensaver::CheckForegroundWindow - Checking idle actvity.\n"));
1135
lii.cbSize = sizeof(LASTINPUTINFO);
1137
gspfnMyGetLastInputInfo(&lii);
1139
if (m_dwLastInputTimeAtStartup != lii.dwTime) {
1140
BOINCTRACE(_T("CScreensaver::CheckForegroundWindow - Activity Detected.\n"));
1141
ShowWindow(hwndBOINCGraphicsWindow, SW_MINIMIZE);
1142
ShowWindow(hwndBOINCGraphicsWindow, SW_FORCEMINIMIZE);
1143
SetError(TRUE, SCRAPPERR_BOINCSHUTDOWNEVENT);
1144
SendMessage(m_Monitors[iMonitor].hWnd, WM_INTERRUPTSAVER, NULL, NULL);
1149
// Graphics application does not exist. So check that one of the windows
1150
// assigned to each monitor is the foreground window.
1151
bForegroundWindowIsScreensaver = FALSE;
1152
hwndForeWindow = GetForegroundWindow();
1153
hwndForeParent = GetParent(hwndForeWindow);
1154
for(iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) {
1155
pMonitorInfo = &m_Monitors[iMonitor];
1156
if ((pMonitorInfo->hWnd == hwndForeWindow) ||
1157
(pMonitorInfo->hWnd == hwndForeParent))
1159
bForegroundWindowIsScreensaver = TRUE;
1162
if (!bForegroundWindowIsScreensaver) {
1163
// This can happen because of a personal firewall notifications or some
1164
// funky IM client that thinks it has to notify the user even when in
1165
// screensaver mode.
1166
BOINCTRACE(_T("CScreensaver::CheckForegroundWindow - Unknown foreground window detected, shutdown the screensaver.\n"));
1167
SetError(TRUE, SCRAPPERR_BOINCSHUTDOWNEVENT);
1168
SendMessage(m_Monitors[0].hWnd, WM_INTERRUPTSAVER, NULL, NULL);
1175
// Register and create the appropriate window(s)
1177
HRESULT CScreensaver::CreateSaverWindow() {
1178
// Register an appropriate window class for the primary display
1180
cls.hCursor = LoadCursor(NULL, IDC_ARROW);
1181
cls.hIcon = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));
1182
cls.lpszMenuName = NULL;
1183
cls.lpszClassName = _T("BOINCPrimarySaverWndClass");
1184
cls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
1185
cls.hInstance = m_hInstance;
1186
cls.style = CS_VREDRAW|CS_HREDRAW;
1187
cls.lpfnWndProc = SaverProcStub;
1190
RegisterClass(&cls);
1192
// Register an appropriate window class for the secondary display(s)
1194
cls2.hCursor = LoadCursor(NULL, IDC_ARROW);
1195
cls2.hIcon = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));
1196
cls2.lpszMenuName = NULL;
1197
cls2.lpszClassName = _T("BOINCGenericSaverWndClass");
1198
cls2.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
1199
cls2.hInstance = m_hInstance;
1200
cls2.style = CS_VREDRAW|CS_HREDRAW;
1201
cls2.lpfnWndProc = SaverProcStub;
1202
cls2.cbWndExtra = 0;
1203
cls2.cbClsExtra = 0;
1204
RegisterClass(&cls2);
1206
// Create the window
1209
switch (m_SaverMode) {
1211
GetClientRect(m_hWndParent, &rc);
1212
dwStyle = WS_VISIBLE | WS_CHILD;
1213
AdjustWindowRect(&rc, dwStyle, FALSE);
1214
m_hWnd = CreateWindow(_T("BOINCPrimarySaverWndClass"),
1215
m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right-rc.left,
1216
rc.bottom-rc.top, m_hWndParent, NULL, m_hInstance, this
1218
m_Monitors[0].hWnd = m_hWnd;
1219
GetClientRect(m_hWnd, &m_rcRenderTotal);
1220
GetClientRect(m_hWnd, &m_rcRenderCurDevice);
1224
rc.left = rc.top = 50;
1225
rc.right = rc.left+600;
1226
rc.bottom = rc.top+400;
1227
dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
1228
AdjustWindowRect(&rc, dwStyle, FALSE);
1229
m_hWnd = CreateWindow(_T("BOINCPrimarySaverWndClass"),
1230
m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right-rc.left,
1231
rc.bottom-rc.top, NULL, NULL, m_hInstance, this
1233
m_Monitors[0].hWnd = m_hWnd;
1234
GetClientRect(m_hWnd, &m_rcRenderTotal);
1235
GetClientRect(m_hWnd, &m_rcRenderCurDevice);
1236
SetTimer(m_hWnd, 2, 60000, NULL);
1240
dwStyle = WS_VISIBLE | WS_POPUP;
1242
for(DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) {
1243
INTERNALMONITORINFO* pMonitorInfo;
1244
pMonitorInfo = &m_Monitors[iMonitor];
1245
if (pMonitorInfo->hWnd == NULL) {
1246
if (pMonitorInfo->hMonitor == NULL)
1248
rc = pMonitorInfo->rcScreen;
1249
if (0 == iMonitor) {
1250
pMonitorInfo->hWnd = CreateWindowEx(NULL, _T("BOINCPrimarySaverWndClass"),
1251
m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left,
1252
rc.bottom - rc.top, NULL, NULL, m_hInstance, this);
1254
pMonitorInfo->hWnd = CreateWindowEx(NULL, _T("BOINCGenericSaverWndClass"),
1255
m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left,
1256
rc.bottom - rc.top, NULL, NULL, m_hInstance, this);
1258
if (pMonitorInfo->hWnd == NULL) {
1262
if (m_hWnd == NULL) {
1263
m_hWnd = pMonitorInfo->hWnd;
1266
SetTimer(pMonitorInfo->hWnd, 2, 250, NULL);
1270
if (m_hWnd == NULL) {
1279
// Run the screensaver graphics - may be preview, test or full-on mode
1281
HRESULT CScreensaver::DoSaver() {
1282
// Flag as screensaver running if in full on mode
1283
if (m_SaverMode == sm_full) {
1285
SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0);
1292
msg.message = WM_NULL;
1293
while (msg.message != WM_QUIT) {
1294
bGotMsg = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
1296
TranslateMessage(&msg);
1297
DispatchMessage(&msg);
1309
VOID CScreensaver::DoConfig() {
1310
DialogBox(NULL, MAKEINTRESOURCE(DLG_CONFIG), m_hWndParent, ConfigureDialogProcStub);
1315
// Handle window messages for main screensaver windows.
1317
LRESULT CScreensaver::SaverProc(
1318
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
1320
DWORD dwMonitor = 0;
1322
for(DWORD iIndex = 0; iIndex < m_dwNumMonitors; iIndex++) {
1323
if (hWnd == m_Monitors[iIndex].hWnd ) {
1329
BOINCTRACE(_T("CScreensaver::SaverProc [%d] hWnd '%d' uMsg '%X' wParam '%d' lParam '%d'\n"), dwMonitor, hWnd, uMsg, wParam, lParam);
1333
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_TIMER\n"));
1336
// Initial idle time is done, proceed with initialization.
1337
m_bWaitForInputIdle = FALSE;
1342
// Create a screen saver window on the primary display if
1343
// the boinc client crashes
1344
CreateSaverWindow();
1346
// Update the position of the box every second so that it
1347
// does not end up off the visible area of the screen.
1358
GetError(bErrorMode, hrError, szError, sizeof(szError)/sizeof(TCHAR));
1360
// Show error message, if there is one
1362
BeginPaint(hWnd, &ps);
1364
// In preview mode, just fill
1365
// the preview window with black, and the BOINC icon.
1366
if (!bErrorMode && m_SaverMode == sm_preview) {
1368
GetClientRect(hWnd,&rc);
1369
FillRect(ps.hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
1370
DrawIcon(ps.hdc, (rc.right / 2) - 16, (rc.bottom / 2) - 16,
1371
LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON)));
1373
DoPaint(hWnd, ps.hdc, &ps);
1376
EndPaint(hWnd, &ps);
1383
if (m_SaverMode != sm_test) {
1384
static INT xPrev = -1;
1385
static INT yPrev = -1;
1386
INT xCur = GET_X_LPARAM(lParam);
1387
INT yCur = GET_Y_LPARAM(lParam);
1388
if (xCur != xPrev || yCur != yPrev) {
1391
m_dwSaverMouseMoveCount++;
1392
if (m_dwSaverMouseMoveCount > 5) {
1393
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_MOUSEMOVE and time to InterruptSaver()\n"));
1402
case WM_LBUTTONDOWN:
1403
case WM_RBUTTONDOWN:
1404
case WM_MBUTTONDOWN:
1405
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_KEYDOWN | WM_LBUTTONDOWN | WM_RBUTTONDOWN | WM_MBUTTONDOWN\n"));
1406
if (m_SaverMode != sm_test) {
1414
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_CLOSE or WM_DESTROY\n"));
1415
if (m_SaverMode == sm_preview || m_SaverMode == sm_test) {
1422
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_SYSCOMMAND\n"));
1423
if (m_SaverMode == sm_full) {
1435
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_SETCURSOR\n"));
1436
if (m_SaverMode == sm_full && !m_bCheckingSaverPassword) {
1443
case WM_POWERBROADCAST:
1444
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_POWERBROADCAST\n"));
1445
if (wParam == PBT_APMQUERYSUSPEND && gspfnMyVerifyPwdProc == NULL)
1450
if (WM_SETTIMER == uMsg) {
1452
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_SETTIMER\n"));
1453
// All initialization messages have gone through. Allow
1454
// 500ms of idle time, then proceed with initialization.
1455
SetTimer(hWnd, 1, 500, NULL);
1457
} else if (WM_INTERRUPTSAVER == uMsg) {
1459
BOINCTRACE(_T("CScreensaver::SaverProc Received WM_INTERRUPTSAVER\n"));
1460
if (hWnd == m_Monitors[0].hWnd) {
1466
return DefWindowProc(hWnd, uMsg, wParam, lParam);
1472
INT_PTR CScreensaver::ConfigureDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM UNUSED(lParam)) {
1473
DWORD screen_blank=0, blank_time=0;
1479
// make sure you check return value of registry queries
1480
// in case the item in question doesn't happen to exist.
1481
retval = UtilGetRegKey(REG_BLANK_NAME, screen_blank);
1485
CheckDlgButton(hwnd, IDC_BLANK, screen_blank);
1487
retval = UtilGetRegKey(REG_BLANK_TIME, blank_time);
1488
if (retval < 0) { blank_time=0; }
1489
_ltot(blank_time, buf, 10);
1490
SetDlgItemText(hwnd, IDC_BLANK_TIME, buf);
1494
int id=LOWORD(wParam);
1497
screen_blank = (IsDlgButtonChecked(hwnd, IDC_BLANK) == BST_CHECKED);
1498
UtilSetRegKey(REG_BLANK_NAME, screen_blank);
1500
GetDlgItemText(hwnd, IDC_BLANK_TIME, buf, 256);
1501
blank_time = atoi(buf);
1502
UtilSetRegKey(REG_BLANK_TIME, blank_time);
1505
if (id == IDOK || id == IDCANCEL) {
1506
EndDialog(hwnd, id);
1516
// This function forwards all window messages to SaverProc, which has
1517
// access to the "this" pointer.
1519
LRESULT CALLBACK CScreensaver::SaverProcStub(
1520
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
1522
return gspScreensaver->SaverProc(hWnd, uMsg, wParam, lParam);
1528
INT_PTR CALLBACK CScreensaver::ConfigureDialogProcStub(
1529
HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
1531
return gspScreensaver->ConfigureDialogProc(hwndDlg, uMsg, wParam, lParam);
1537
VOID CScreensaver::ShutdownSaver() {
1538
// Unflag screensaver running if in full on mode
1539
if (m_SaverMode == sm_full) {
1541
SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0);
1544
// Kill the currently executing graphics application
1545
terminate_screensaver(m_hGraphicsApplication, &m_running_result);
1547
// Post message to drop out of message loop
1548
// This can be called from the data management thread, so specifically
1549
// lookup and post to the primary window instead of calling PostQuitMessage
1550
// since PostQuitMessage posts to the current threads message pump if it
1552
if (m_Monitors[0].hWnd) {
1553
PostMessage(m_Monitors[0].hWnd, WM_QUIT, 0, 0);
1560
// A message was received (mouse move, keydown, etc.) that may mean
1561
// the screen saver should show the password dialog and/or shut down.
1563
VOID CScreensaver::InterruptSaver() {
1564
BOOL bPasswordOkay = FALSE;
1566
BOINCTRACE(_T("CScreensaver::InterruptSaver Function Begin\n"));
1567
if (m_SaverMode == sm_test || m_SaverMode == sm_full && !m_bCheckingSaverPassword) {
1568
if (m_bIs9x && m_SaverMode == sm_full) {
1569
// If no VerifyPassword function, then no password is set
1570
// or we're not on 9x.
1571
if (gspfnMyVerifyPwdProc) {
1572
BOINCTRACE(_T("CScreensaver::InterruptSaver Win9x Detected and Password Configured\n"));
1573
m_bCheckingSaverPassword = TRUE;
1575
BOINCTRACE(_T("CScreensaver::InterruptSaver Calling VerifyScreenSavePwd\n"));
1576
bPasswordOkay = gspfnMyVerifyPwdProc(m_hWnd);
1577
BOINCTRACE(_T("CScreensaver::InterruptSaver Finished\n"));
1579
m_bCheckingSaverPassword = FALSE;
1581
if (!bPasswordOkay) {
1582
// Back to screen saving...
1583
BOINCTRACE(_T("CScreensaver::InterruptSaver Incorrect Password Given, Resetting m_dwSaverMouseMoveCount\n"));
1585
m_dwSaverMouseMoveCount = 0;
1592
if (m_bIs9x && m_SaverMode == sm_full && m_bCheckingSaverPassword) {
1593
// Win9x sucks so bad the darn password dialog can get stuck behind the
1594
// screensaver window. Which leaves the screensaver in a state where
1595
// you have to reboot the machine.
1596
HWND hwndPassword = FindWindow(_T("#32770"), _T("Windows Screen Saver"));
1597
HWND hwndForeWindow = GetForegroundWindow();
1599
BOINCTRACE(_T("CScreensaver::InterruptSaver Password Dialog Detected\n"));
1600
if (hwndPassword != hwndForeWindow) {
1601
BOINCTRACE(_T("CScreensaver::InterruptSaver Password Dialog is NOT the foreground window, bringing to foreground\n"));
1602
SetForegroundWindow(hwndPassword);
1607
BOINCTRACE(_T("CScreensaver::InterruptSaver Function End\n"));
1613
// Update the box that shows the error message
1615
VOID CScreensaver::UpdateErrorBox() {
1616
INTERNALMONITORINFO* pMonitorInfo;
1619
static DWORD dwTimeLast = 0;
1624
// Update timing to determine how much to move error box
1625
if (dwTimeLast == 0) {
1626
dwTimeLast = timeGetTime();
1629
dwTimeNow = timeGetTime();
1630
fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 10000.0f;
1631
dwTimeLast = dwTimeNow;
1633
for(DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) {
1634
pMonitorInfo = &m_Monitors[iMonitor];
1635
hwnd = pMonitorInfo->hWnd;
1638
if (m_SaverMode == sm_full) {
1639
rcBounds = pMonitorInfo->rcScreen;
1640
ScreenToClient(hwnd, (POINT*)&rcBounds.left);
1641
ScreenToClient(hwnd, (POINT*)&rcBounds.right);
1643
rcBounds = m_rcRenderTotal;
1646
if (pMonitorInfo->widthError == 0) {
1647
if (m_SaverMode == sm_preview) {
1648
pMonitorInfo->widthError = (float) (rcBounds.right - rcBounds.left);
1649
pMonitorInfo->heightError = (float) (rcBounds.bottom - rcBounds.top);
1650
pMonitorInfo->xError = 0.0f;
1651
pMonitorInfo->yError = 0.0f;
1652
pMonitorInfo->xVelError = 0.0f;
1653
pMonitorInfo->yVelError = 0.0f;
1654
InvalidateRect(hwnd, NULL, FALSE); // Invalidate the hwnd so it gets drawn
1657
pMonitorInfo->widthError = 454;
1658
pMonitorInfo->heightError = 320;
1659
pMonitorInfo->xError = (rcBounds.right + rcBounds.left - pMonitorInfo->widthError) / 2.0f;
1660
pMonitorInfo->yError = (rcBounds.bottom + rcBounds.top - pMonitorInfo->heightError) / 2.0f;
1661
pMonitorInfo->xVelError = (rcBounds.right - rcBounds.left) / 10.0f;
1662
pMonitorInfo->yVelError = (rcBounds.bottom - rcBounds.top) / 20.0f;
1665
if (m_SaverMode != sm_preview) {
1669
SetRect(&rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
1670
(INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
1671
(INT)(pMonitorInfo->yError + pMonitorInfo->heightError));
1673
// Update rect velocity
1674
if ((pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta +
1675
pMonitorInfo->widthError > rcBounds.right && pMonitorInfo->xVelError > 0.0f) ||
1676
(pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta <
1677
rcBounds.left && pMonitorInfo->xVelError < 0.0f)
1679
pMonitorInfo->xVelError = -pMonitorInfo->xVelError;
1681
if ((pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta +
1682
pMonitorInfo->heightError > rcBounds.bottom && pMonitorInfo->yVelError > 0.0f) ||
1683
(pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta <
1684
rcBounds.top && pMonitorInfo->yVelError < 0.0f)
1686
pMonitorInfo->yVelError = -pMonitorInfo->yVelError;
1688
// Update rect position
1689
pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta;
1690
pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta;
1692
SetRect(&rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
1693
(INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
1694
(INT)(pMonitorInfo->yError + pMonitorInfo->heightError));
1696
if ((dwTimeNow - pMonitorInfo->dwTimeLastUpdate) > 1000)
1698
pMonitorInfo->dwTimeLastUpdate = dwTimeNow;
1700
InvalidateRect(hwnd, NULL, TRUE);
1711
VOID CScreensaver::DoPaint(HWND hwnd, HDC hdc, LPPAINTSTRUCT lpps) {
1713
INTERNALMONITORINFO* pMonitorInfo = NULL;
1714
HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
1716
for(iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) {
1717
pMonitorInfo = &m_Monitors[iMonitor];
1718
if (pMonitorInfo->hMonitor == hMonitor)
1722
if (iMonitor == m_dwNumMonitors) {
1726
// Retrieve the latest piece of error information
1730
GetError(bErrorMode, hrError, szError, sizeof(szError)/sizeof(TCHAR));
1733
// Start drawing the goods
1739
static HBRUSH hbrushBlack = (HBRUSH)GetStockObject(BLACK_BRUSH);
1740
static HBRUSH hbrushRed = (HBRUSH)CreateSolidBrush(RGB(255,0,0));
1741
static HBITMAP hbmp = LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_BOINCSPLAT));
1744
// Start off with a black screen and then draw on top of it.
1745
FillRect(hdc, &lpps->rcPaint, hbrushBlack);
1748
// If the screensaver has switched to a blanked state or not in an error mode,
1749
// we should exit here so the screen has been erased to black.
1755
SetRect(&rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
1756
(INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
1757
(INT)(pMonitorInfo->yError + pMonitorInfo->heightError)
1759
// This fill rect is useful when testing
1760
// FillRect(hdc, &rc, hbrushRed);
1764
// Draw the bitmap rectangle and copy the bitmap into
1765
// it. the bitmap is centered in the rectangle by adding 2
1766
// to the left and top coordinates of the bitmap rectangle,
1767
// and subtracting 4 from the right and bottom coordinates.
1769
GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bm);
1771
long left = rc.left + (pMonitorInfo->widthError - 4 - bm.bmWidth)/2;
1772
long top = rc.top + 2;
1773
DrawTransparentBitmap(hdc, hbmp, left, top, RGB(255, 0, 255));
1775
// Draw text in the center of the frame
1776
SetBkColor(hdc, RGB(0,0,0)); // Black
1777
SetTextColor(hdc, RGB(255,255,255)); // Red
1781
hf = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial Narrow");
1785
SelectObject(hdc, hf);
1788
iTextHeight = DrawText(hdc, szError, -1, &rc, DT_CENTER | DT_CALCRECT);
1790
rc2.top+=bm.bmHeight+20;
1791
DrawText(hdc, szError, -1, &rc2, DT_CENTER);
1797
// Draws a bitmap on the screen with a transparent background.
1798
// Code orginally from Microsoft Knowledge Base Article - 79212
1800
void CScreensaver::DrawTransparentBitmap(
1801
HDC hdc, HBITMAP hBitmap, LONG xStart, LONG yStart,
1802
COLORREF cTransparentColor
1806
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
1807
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
1808
HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
1811
hdcTemp = CreateCompatibleDC(hdc);
1812
SelectObject(hdcTemp, hBitmap); // Select the bitmap
1814
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
1815
ptSize.x = bm.bmWidth; // Get width of bitmap
1816
ptSize.y = bm.bmHeight; // Get height of bitmap
1817
DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
1819
// to logical points
1821
// Create some DCs to hold temporary data.
1822
hdcBack = CreateCompatibleDC(hdc);
1823
hdcObject = CreateCompatibleDC(hdc);
1824
hdcMem = CreateCompatibleDC(hdc);
1825
hdcSave = CreateCompatibleDC(hdc);
1827
// Create a bitmap for each DC. DCs are required for a number of
1831
bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
1834
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
1836
bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
1837
bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
1839
// Each DC must select a bitmap object to store pixel data.
1840
bmBackOld = (HBITMAP)SelectObject(hdcBack, bmAndBack);
1841
bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject);
1842
bmMemOld = (HBITMAP)SelectObject(hdcMem, bmAndMem);
1843
bmSaveOld = (HBITMAP)SelectObject(hdcSave, bmSave);
1845
// Set proper mapping mode.
1846
SetMapMode(hdcTemp, GetMapMode(hdc));
1848
// Save the bitmap sent here, because it will be overwritten.
1849
BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
1851
// Set the background color of the source DC to the color.
1852
// contained in the parts of the bitmap that should be transparent
1853
cColor = SetBkColor(hdcTemp, cTransparentColor);
1855
// Create the object mask for the bitmap by performing a BitBlt
1856
// from the source bitmap to a monochrome bitmap.
1857
BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
1859
// Set the background color of the source DC back to the original
1861
SetBkColor(hdcTemp, cColor);
1863
// Create the inverse of the object mask.
1864
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
1866
// Copy the background of the main DC to the destination.
1867
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart, SRCCOPY);
1869
// Mask out the places where the bitmap will be placed.
1870
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
1872
// Mask out the transparent colored pixels on the bitmap.
1873
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
1875
// XOR the bitmap with the background on the destination DC.
1876
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
1878
// Copy the destination to the screen.
1879
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
1881
// Place the original bitmap back into the bitmap sent here.
1882
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
1884
// Delete the memory bitmaps.
1885
DeleteObject(SelectObject(hdcBack, bmBackOld));
1886
DeleteObject(SelectObject(hdcObject, bmObjectOld));
1887
DeleteObject(SelectObject(hdcMem, bmMemOld));
1888
DeleteObject(SelectObject(hdcSave, bmSaveOld));
1890
// Delete the memory DCs.
1893
DeleteDC(hdcObject);
1901
VOID CScreensaver::ChangePassword() {
1902
// Load the password change DLL
1903
HINSTANCE mpr = LoadLibrary(_T("MPR.DLL"));
1906
// Grab the password change function from it
1907
typedef DWORD (PASCAL *PWCHGPROC)(LPCSTR, HWND, DWORD, LPVOID);
1908
PWCHGPROC pwd = (PWCHGPROC)GetProcAddress(mpr, "PwdChangePasswordA");
1910
// Do the password change
1912
pwd("SCRSAVE", m_hWndParent, 0, NULL);
1923
const char *BOINC_RCSID_116268c72f = "$Id: screensaver_win.cpp 15235 2008-05-16 16:55:02Z romw $";