~ubuntu-branches/ubuntu/lucid/boinc/lucid

« back to all changes in this revision

Viewing changes to clientscr/screensaver_win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Frank S. Thomas, Frank S. Thomas
  • Date: 2008-05-31 08:02:47 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20080531080247-4ce890lp2rc768cr
Tags: 6.2.7-1
[ Frank S. Thomas ]
* New upstream release.
  - BOINC Manager: Redraw disk usage charts immediately after connecting to
    a (different) client. (closes: 463823)
* debian/copyright:
  - Added the instructions from debian/README.Debian-source about how
    repackaged BOINC tarballs can be reproduced because DevRef now
    recommends to put this here instead of in the afore-mentioned file.
  - Updated for the new release.
* Removed the obsolete debian/README.Debian-source.
* For consistency upstream renamed the core client and the command tool
  ("boinc_client" to "boinc" and "boinc_cmd" to "boinccmd"). Done the same
  in all packages and created symlinks with the old names for the binaries
  and man pages. Also added an entry in debian/boinc-client.NEWS explaining
  this change.
* debian/rules: Do not list Makefile.ins in the clean target individually,
  just remove all that can be found.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Berkeley Open Infrastructure for Network Computing
 
2
// http://boinc.berkeley.edu
 
3
// Copyright (C) 2005 University of California
 
4
//
 
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.
 
9
//
 
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.
 
14
//
 
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
 
19
// 
 
20
// Contributor(s):
 
21
//     DirectX 8.1 Screen Saver Framework from Microsoft.
 
22
//     Microsoft Knowledge Base Article - 79212
 
23
//
 
24
 
 
25
#include "boinc_win.h"
 
26
 
 
27
#include <windowsx.h>
 
28
#include <mmsystem.h>
 
29
#include <regstr.h>
 
30
#include <strsafe.h>
 
31
#include <mmsystem.h>
 
32
#define COMPILE_MULTIMON_STUBS
 
33
 
 
34
#include "boinc_ss.h"
 
35
#include "diagnostics.h"
 
36
#include "common_defs.h"
 
37
#include "util.h"
 
38
#include "gui_rpc_client.h"
 
39
#include "screensaver.h"
 
40
#include "screensaver_win.h"
 
41
 
 
42
#ifdef _DEBUG
 
43
#define UNUSED(x)
 
44
#else
 
45
#define UNUSED(x) x
 
46
#endif
 
47
 
 
48
 
 
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;
 
56
 
 
57
const UINT                      WM_SETTIMER = RegisterWindowMessage(TEXT("BOINCSetTimer"));
 
58
const UINT                      WM_INTERRUPTSAVER = RegisterWindowMessage(TEXT("BOINCInterruptScreensaver"));
 
59
const UINT                      WM_BOINCSFW = RegisterWindowMessage(TEXT("BOINCSetForegroundWindow"));
 
60
 
 
61
 
 
62
INT WINAPI WinMain(
 
63
    HINSTANCE hInstance, HINSTANCE UNUSED(hPrevInstance), LPSTR UNUSED(lpCmdLine), int UNUSED(nCmdShow)
 
64
) {
 
65
    HRESULT      hr;
 
66
    CScreensaver BOINCSS;
 
67
    int          retval;
 
68
    WSADATA      wsdata;
 
69
    BOOL         bIs95 = FALSE;
 
70
    BOOL         bIs9x = FALSE;
 
71
    DWORD        dwVal;
 
72
    DWORD        dwSize = sizeof(dwVal); 
 
73
    HKEY         hKey;
 
74
 
 
75
#ifdef _DEBUG
 
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,
 
85
        "stdoutscr",
 
86
        "stderrscr"
 
87
    );
 
88
    if (retval) {
 
89
        BOINCTRACE("WinMain - BOINC Screensaver Diagnostic Error '%d'\n", retval);
 
90
        MessageBox(NULL, NULL, "BOINC Screensaver Diagnostic Error", MB_OK);
 
91
    }
 
92
#endif
 
93
 
 
94
    // Figure out if we're on Win9x
 
95
    OSVERSIONINFO osvi; 
 
96
    osvi.dwOSVersionInfoSize = sizeof(osvi);
 
97
    GetVersionEx(&osvi);
 
98
    bIs9x =   osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;
 
99
    bIs95 =   (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
 
100
              ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0));
 
101
 
 
102
    // Load dynamically linked modules
 
103
    gshUser32 = LoadLibrary(_T("USER32.DLL"));
 
104
    if (bIs9x) {
 
105
        gshPasswordCPL = LoadLibrary(_T("PASSWORD.CPL"));
 
106
    }
 
107
 
 
108
    // Map function pointers
 
109
    if (gshUser32) {
 
110
        gspfnMyGetLastInputInfo = (MYGETLASTINPUTINFO) GetProcAddress(gshUser32, _T("GetLastInputInfo"));
 
111
        gspfnMyIsHungAppWindow = (MYISHUNGAPPWINDOW) GetProcAddress(gshUser32, _T("IsHungAppWindow"));
 
112
        if (bIs95) {
 
113
            gspfnMyBroadcastSystemMessage = (MYBROADCASTSYSTEMMESSAGE) GetProcAddress(gshUser32, _T("BroadcastSystemMessage"));
 
114
        } else {
 
115
            gspfnMyBroadcastSystemMessage = (MYBROADCASTSYSTEMMESSAGE) GetProcAddress(gshUser32, _T("BroadcastSystemMessageA"));
 
116
        }
 
117
    }
 
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"));
 
122
                RegCloseKey(hKey);
 
123
            }
 
124
        }
 
125
    }
 
126
 
 
127
    // Initialize the CRT random number generator.
 
128
    srand((unsigned int)time(0));
 
129
 
 
130
    // Initialize the Windows sockets interface.
 
131
    retval = WSAStartup(MAKEWORD(1, 1), &wsdata);
 
132
    if (retval) {
 
133
        BOINCTRACE("WinMain - Winsock Initialization Failure '%d'\n", retval);
 
134
        return retval;
 
135
    }
 
136
 
 
137
    if (FAILED(hr = BOINCSS.Create(hInstance))) {
 
138
        BOINCSS.DisplayErrorMsg(hr);
 
139
        WSACleanup();
 
140
        return 0;
 
141
    }
 
142
 
 
143
    retval = BOINCSS.Run();
 
144
 
 
145
    // Cleanup the Windows sockets interface.
 
146
    WSACleanup();
 
147
 
 
148
    // Clean up function pointers.
 
149
    gspfnMyGetLastInputInfo = NULL;
 
150
    gspfnMyIsHungAppWindow = NULL;
 
151
    gspfnMyBroadcastSystemMessage = NULL;
 
152
    gspfnMyVerifyPwdProc = NULL;
 
153
 
 
154
    // Free modules
 
155
    FreeLibrary(gshUser32);
 
156
    if (gshPasswordCPL) {
 
157
        FreeLibrary(gshPasswordCPL);
 
158
        gshPasswordCPL = NULL;
 
159
    }
 
160
    
 
161
    return retval;
 
162
}
 
163
 
 
164
 
 
165
CScreensaver::CScreensaver() {
 
166
    gspScreensaver = this;
 
167
 
 
168
    m_bCheckingSaverPassword = FALSE;
 
169
    m_bIs9x = FALSE;
 
170
    m_dwSaverMouseMoveCount = 0;
 
171
    m_hWnd = NULL;
 
172
    m_hWndParent = NULL;
 
173
    
 
174
    m_bAllScreensSame = FALSE;
 
175
    m_bWindowed = FALSE;
 
176
    m_bWaitForInputIdle = FALSE;
 
177
 
 
178
    m_bErrorMode = FALSE;
 
179
    m_hrError = S_OK;
 
180
    m_szError[0] = _T('\0');
 
181
 
 
182
    LoadString(NULL, IDS_DESCRIPTION, m_strWindowTitle, 200);
 
183
 
 
184
    m_bPaintingInitialized = FALSE;
 
185
    m_dwBlankScreen = 0;
 
186
    m_dwBlankTime = 0;
 
187
 
 
188
    rpc = NULL;
 
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));
 
196
 
 
197
    ZeroMemory(m_Monitors, sizeof(m_Monitors));
 
198
    m_dwNumMonitors = 0;
 
199
 
 
200
    m_dwLastInputTimeAtStartup = 0;
 
201
    m_tThreadCreateTime = 0;
 
202
}
 
203
 
 
204
 
 
205
// Have the client program call this function before calling Run().
 
206
//
 
207
HRESULT CScreensaver::Create(HINSTANCE hInstance) {
 
208
    HRESULT hr;
 
209
    BOOL    bReturnValue;
 
210
 
 
211
    m_hInstance = hInstance;
 
212
 
 
213
    // Parse the command line and do the appropriate thing
 
214
    m_SaverMode = ParseCommandLine(GetCommandLine());
 
215
 
 
216
    // Figure out if we're on Win9x
 
217
    OSVERSIONINFO osvi; 
 
218
    osvi.dwOSVersionInfoSize = sizeof(osvi);
 
219
    GetVersionEx(&osvi);
 
220
    m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
 
221
 
 
222
    // Store last input value if it exists
 
223
    if (gspfnMyGetLastInputInfo) {
 
224
        LASTINPUTINFO lii;
 
225
        lii.cbSize = sizeof(LASTINPUTINFO);
 
226
 
 
227
        gspfnMyGetLastInputInfo(&lii);
 
228
 
 
229
        m_dwLastInputTimeAtStartup = lii.dwTime;
 
230
    }
 
231
 
 
232
    // Enumerate Monitors
 
233
    EnumMonitors();
 
234
 
 
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;
 
240
 
 
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;
 
247
 
 
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);
 
252
 
 
253
        bReturnValue = UtilSetRegKey(REG_BLANK_TIME, m_dwBlankTime);
 
254
    BOINCTRACE("CScreensaver::Create - Set Reg Key REG_BLANK_TIME return value '%d'\n", bReturnValue);
 
255
 
 
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);
 
259
 
 
260
    // Create the infrastructure mutexes so we can properly aquire them to report
 
261
    //   errors
 
262
    if (!CreateInfrastructureMutexes()) {
 
263
        return E_FAIL;
 
264
    }
 
265
 
 
266
        if (rpc == NULL) rpc = new RPC_CLIENT;
 
267
 
 
268
                        // Create the screen saver window(s)
 
269
    if (m_SaverMode == sm_preview || 
 
270
        m_SaverMode == sm_full
 
271
    ) {
 
272
        if (FAILED(hr = CreateSaverWindow())) {
 
273
            SetError(TRUE, hr);
 
274
        }
 
275
    }
 
276
 
 
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;
 
281
 
 
282
        // Post a message to mark the end of the initial group of window messages
 
283
        PostMessage(m_hWnd, WM_SETTIMER, 0, 0);
 
284
 
 
285
        MSG msg;
 
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
 
290
                PostQuitMessage(0);
 
291
                break;
 
292
            }
 
293
 
 
294
            TranslateMessage(&msg);
 
295
            DispatchMessage(&msg);
 
296
        }
 
297
    }
 
298
 
 
299
    return S_OK;
 
300
}
 
301
 
 
302
 
 
303
 
 
304
 
 
305
// Starts main execution of the screen saver.
 
306
//
 
307
INT CScreensaver::Run() {
 
308
    HOST_INFO hostinfo;
 
309
    HRESULT hr;
 
310
 
 
311
    // Parse the command line and do the appropriate thing
 
312
    switch (m_SaverMode) {
 
313
    case sm_config:
 
314
        if (m_bErrorMode) {
 
315
            DisplayErrorMsg(m_hrError);
 
316
        } else {
 
317
            DoConfig();
 
318
        }
 
319
        break;
 
320
    case sm_test:
 
321
        rpc->init(NULL);
 
322
        rpc->get_host_info(hostinfo);
 
323
        rpc->close();
 
324
        break;
 
325
    case sm_preview:
 
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())) {
 
331
            DisplayErrorMsg(hr);
 
332
        }
 
333
        break;
 
334
    case sm_full:
 
335
        // Create the data management thread to talk with the daemon
 
336
        if (!CreateDataManagementThread()) {
 
337
            return E_FAIL;
 
338
        }
 
339
 
 
340
        if (FAILED(hr = DoSaver())) {
 
341
            DisplayErrorMsg(hr);
 
342
        }
 
343
 
 
344
        // Create the data management thread to talk with the daemon
 
345
        //
 
346
        if (!DestroyDataManagementThread()) {
 
347
            return E_FAIL;
 
348
        }
 
349
        
 
350
        if (rpc) {
 
351
            delete rpc;
 
352
            rpc = NULL;
 
353
        }
 
354
        break;
 
355
    case sm_passwordchange:
 
356
        ChangePassword();
 
357
        break;
 
358
    }
 
359
 
 
360
    return 0;
 
361
}
 
362
 
 
363
 
 
364
 
 
365
 
 
366
// Displays error messages in a message box
 
367
//
 
368
HRESULT CScreensaver::DisplayErrorMsg(HRESULT hr) {
 
369
    TCHAR strMsg[512];
 
370
 
 
371
    GetTextForError(hr, strMsg, 512);
 
372
 
 
373
    MessageBox(m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK);
 
374
 
 
375
    return hr;
 
376
}
 
377
 
 
378
 
 
379
 
 
380
 
 
381
// Interpret command-line parameters passed to this app.
 
382
//
 
383
SaverMode CScreensaver::ParseCommandLine(TCHAR* pstrCommandLine) {
 
384
    m_hWndParent = NULL;
 
385
 
 
386
        BOINCTRACE("ParseCommandLine: '%s'\n", pstrCommandLine);
 
387
 
 
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('\"')) {
 
391
        pstrCommandLine++;
 
392
        while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T('\"')) {
 
393
            pstrCommandLine++;
 
394
        }
 
395
        if (*pstrCommandLine == _T('\"')) {
 
396
            pstrCommandLine++;
 
397
        }
 
398
    } else {
 
399
        while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T(' ')) {
 
400
            pstrCommandLine++;
 
401
        }
 
402
        if (*pstrCommandLine == _T(' ')) {
 
403
            pstrCommandLine++;
 
404
        }
 
405
    }
 
406
 
 
407
    // Skip along to the first option delimiter "/" or "-"
 
408
    while (*pstrCommandLine != _T('\0') && *pstrCommandLine != _T('/') && *pstrCommandLine != _T('-')) {
 
409
        pstrCommandLine++;
 
410
    }
 
411
 
 
412
    // If there wasn't one, then must be config mode
 
413
    if (*pstrCommandLine == _T('\0')) {
 
414
        return sm_config;
 
415
    }
 
416
 
 
417
    // Otherwise see what the option was
 
418
    switch (*(++pstrCommandLine)) {
 
419
        case 'c':
 
420
        case 'C':
 
421
            pstrCommandLine++;
 
422
            while (*pstrCommandLine && !isdigit(*pstrCommandLine)) {
 
423
                pstrCommandLine++;
 
424
            }
 
425
            if (isdigit(*pstrCommandLine)) {
 
426
#ifdef _WIN64
 
427
                m_hWndParent = (HWND)_atoi64(pstrCommandLine);
 
428
#else
 
429
                m_hWndParent = (HWND)_ttol(pstrCommandLine);
 
430
#endif
 
431
            } else {
 
432
                m_hWndParent = NULL;
 
433
            }
 
434
            return sm_config;
 
435
 
 
436
        case 't':
 
437
        case 'T':
 
438
            return sm_test;
 
439
 
 
440
        case 'p':
 
441
        case 'P':
 
442
            // Preview-mode, so option is followed by the parent HWND in decimal
 
443
            pstrCommandLine++;
 
444
            while (*pstrCommandLine && !isdigit(*pstrCommandLine)) {
 
445
                pstrCommandLine++;
 
446
            }
 
447
            if (isdigit(*pstrCommandLine)) {
 
448
#ifdef _WIN64
 
449
                m_hWndParent = (HWND)_atoi64(pstrCommandLine);
 
450
#else
 
451
                m_hWndParent = (HWND)_ttol(pstrCommandLine);
 
452
#endif
 
453
            }
 
454
            return sm_preview;
 
455
 
 
456
        case 'a':
 
457
        case 'A':
 
458
            // Password change mode, so option is followed by parent HWND in decimal
 
459
            pstrCommandLine++;
 
460
            while (*pstrCommandLine && !isdigit(*pstrCommandLine)) {
 
461
                pstrCommandLine++;
 
462
            }
 
463
            if (isdigit(*pstrCommandLine)) {
 
464
#ifdef _WIN64
 
465
                m_hWndParent = (HWND)_atoi64(pstrCommandLine);
 
466
#else
 
467
                m_hWndParent = (HWND)_ttol(pstrCommandLine);
 
468
#endif
 
469
            }
 
470
            return sm_passwordchange;
 
471
 
 
472
        default:
 
473
            // All other options => run the screensaver (typically this is "/s")
 
474
            return sm_full;
 
475
    }
 
476
}
 
477
 
 
478
 
 
479
 
 
480
 
 
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.
 
486
//
 
487
VOID CScreensaver::EnumMonitors(VOID) {
 
488
    DWORD iDevice = 0;
 
489
    DISPLAY_DEVICE_FULL dispdev;
 
490
    DISPLAY_DEVICE_FULL dispdev2;
 
491
    DEVMODE devmode;
 
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);
 
504
 
 
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);
 
509
            
 
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;
 
517
                } else {
 
518
                    pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x;
 
519
                    pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y;
 
520
                }
 
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);
 
524
            }
 
525
            m_dwNumMonitors++;
 
526
            if (m_dwNumMonitors == MAX_DISPLAYS) {
 
527
                break;
 
528
            }
 
529
        }
 
530
        iDevice++;
 
531
    }
 
532
}
 
533
 
 
534
 
 
535
 
 
536
 
 
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
 
540
//
 
541
int CScreensaver::UtilSetRegKey(LPCTSTR name, DWORD value) {
 
542
        LONG error;
 
543
        HKEY boinc_key;
 
544
 
 
545
        if (m_bIs9x) {
 
546
                error = RegCreateKeyEx(
 
547
            HKEY_LOCAL_MACHINE, 
 
548
            _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),  
 
549
                        0,
 
550
            NULL,
 
551
            REG_OPTION_NON_VOLATILE,
 
552
            KEY_READ | KEY_WRITE,
 
553
            NULL,
 
554
            &boinc_key,
 
555
            NULL
 
556
        );
 
557
                if (error != ERROR_SUCCESS) return -1;
 
558
        } else {
 
559
                error = RegCreateKeyEx(
 
560
            HKEY_CURRENT_USER,
 
561
            _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),  
 
562
                        0,
 
563
            NULL,
 
564
            REG_OPTION_NON_VOLATILE,
 
565
            KEY_READ | KEY_WRITE,
 
566
            NULL,
 
567
            &boinc_key,
 
568
            NULL
 
569
        );
 
570
                if (error != ERROR_SUCCESS) return -1;
 
571
        }
 
572
 
 
573
        error = RegSetValueEx(boinc_key, name, 0, REG_DWORD, (CONST BYTE *)&value, 4);
 
574
 
 
575
        RegCloseKey(boinc_key);
 
576
 
 
577
        return 0;
 
578
}
 
579
 
 
580
 
 
581
 
 
582
 
 
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
 
586
//
 
587
int CScreensaver::UtilGetRegKey(LPCTSTR name, DWORD &keyval) {
 
588
        LONG  error;
 
589
        DWORD type = REG_DWORD;
 
590
        DWORD size = sizeof(DWORD);
 
591
        DWORD value;
 
592
        HKEY  boinc_key;
 
593
 
 
594
        if (m_bIs9x) {
 
595
                error = RegOpenKeyEx(
 
596
            HKEY_LOCAL_MACHINE, 
 
597
            _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),  
 
598
                        0, 
 
599
            KEY_ALL_ACCESS,
 
600
            &boinc_key
 
601
        );
 
602
                if (error != ERROR_SUCCESS) return -1;
 
603
        } else {
 
604
                error = RegOpenKeyEx(
 
605
            HKEY_CURRENT_USER,
 
606
            _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Screensaver"),  
 
607
                        0,
 
608
            KEY_ALL_ACCESS,
 
609
            &boinc_key
 
610
        );
 
611
                if (error != ERROR_SUCCESS) return -1;
 
612
        }
 
613
 
 
614
        error = RegQueryValueEx(boinc_key, name, NULL, &type, (BYTE *)&value, &size);
 
615
 
 
616
        keyval = value;
 
617
 
 
618
        RegCloseKey(boinc_key);
 
619
 
 
620
        if (error != ERROR_SUCCESS) return -1;
 
621
 
 
622
        return 0;
 
623
}
 
624
 
 
625
 
 
626
 
 
627
 
 
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
 
632
//
 
633
int CScreensaver::UtilGetRegStartupStr(LPCTSTR name, LPTSTR str) {
 
634
        LONG error;
 
635
        DWORD type = REG_SZ;
 
636
        DWORD size = 128;
 
637
        HKEY boinc_key;
 
638
 
 
639
        *str = 0;
 
640
 
 
641
        if (m_bIs9x) {
 
642
                error = RegOpenKeyEx(
 
643
            HKEY_LOCAL_MACHINE, 
 
644
            _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
 
645
                        0, 
 
646
            KEY_ALL_ACCESS,
 
647
            &boinc_key
 
648
        );
 
649
                if (error != ERROR_SUCCESS) return -1;
 
650
        } else {
 
651
                error = RegOpenKeyEx(
 
652
            HKEY_CURRENT_USER, 
 
653
            _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
 
654
                        0, 
 
655
            KEY_ALL_ACCESS, 
 
656
            &boinc_key
 
657
        );
 
658
                if (error != ERROR_SUCCESS) return -1;
 
659
        }
 
660
 
 
661
        error = RegQueryValueEx(boinc_key, name, NULL, &type, (BYTE*)str, &size);
 
662
 
 
663
        RegCloseKey(boinc_key);
 
664
 
 
665
        if (error != ERROR_SUCCESS) return -1;
 
666
 
 
667
        return ERROR_SUCCESS;
 
668
}
 
669
 
 
670
 
 
671
 
 
672
 
 
673
// Determine if BOINC is configured to automatically start at logon/startup.
 
674
//
 
675
BOOL CScreensaver::IsConfigStartupBOINC() {
 
676
        BOOL                            bRetVal;
 
677
        BOOL                            bCheckFileExists;
 
678
        TCHAR                           szBuffer[MAX_PATH];
 
679
        TCHAR                           szShortcutBuffer[MAX_PATH];
 
680
        HANDLE                          hFileHandle;
 
681
    HMODULE                             hShell32;
 
682
        MYSHGETFOLDERPATH       pfnMySHGetFolderPath = NULL;
 
683
 
 
684
 
 
685
        // Lets set the default value to FALSE
 
686
        bRetVal = FALSE;
 
687
 
 
688
    // Load the shortcut filename into the shortcut buffer.
 
689
    LoadString(NULL, IDS_SHORTCUTNAME, szShortcutBuffer, sizeof(szShortcutBuffer)/sizeof(TCHAR));
 
690
 
 
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"));
 
695
 
 
696
 
 
697
        // Now lets begin looking in the registry
 
698
        if (ERROR_SUCCESS == UtilGetRegStartupStr(REG_STARTUP_NAME, szBuffer)) {
 
699
                bRetVal = TRUE;
 
700
        } else {
 
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;
 
711
                                } else {
 
712
                                        BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_STARTUP Append Operation\n"));
 
713
                                }
 
714
                        } else {
 
715
                                BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_STARTUP\n"));
 
716
                        }
 
717
                }
 
718
 
 
719
 
 
720
                if (bCheckFileExists) {
 
721
                        hFileHandle = CreateFile(
 
722
                                szBuffer,
 
723
                                GENERIC_READ,
 
724
                                FILE_SHARE_READ,
 
725
                                NULL,
 
726
                                OPEN_EXISTING,
 
727
                                FILE_ATTRIBUTE_NORMAL,
 
728
                                NULL);
 
729
 
 
730
                        if (INVALID_HANDLE_VALUE != hFileHandle) {
 
731
                                BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned a valid handle '%d'\n"), hFileHandle);
 
732
                                CloseHandle(hFileHandle);
 
733
                                bRetVal = TRUE;
 
734
                        } else {
 
735
                                BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned INVALID_HANDLE_VALUE - GetLastError() '%d'\n"), GetLastError());
 
736
 
 
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;
 
747
                                                } else {
 
748
                                                        BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP Append Operation\n"));
 
749
                                                }
 
750
                                        } else {
 
751
                                                BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: FAILED pfnMySHGetFolderPath - CSIDL_COMMON_STARTUP\n"));
 
752
                                        }
 
753
                                }
 
754
 
 
755
 
 
756
                                if (bCheckFileExists) {
 
757
                                        hFileHandle = CreateFile(
 
758
                                                szBuffer,
 
759
                                                GENERIC_READ,
 
760
                                                FILE_SHARE_READ,
 
761
                                                NULL,
 
762
                                                OPEN_EXISTING,
 
763
                                                FILE_ATTRIBUTE_NORMAL,
 
764
                                                NULL);
 
765
 
 
766
                                        if (INVALID_HANDLE_VALUE != hFileHandle) {
 
767
                                                BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned a valid handle '%d'\n"), hFileHandle);
 
768
                                                CloseHandle(hFileHandle);
 
769
                                                bRetVal = TRUE;
 
770
                                        } else {
 
771
                                                BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: CreateFile returned INVALID_HANDLE_VALUE - GetLastError() '%d'\n"), GetLastError());
 
772
                                        }
 
773
                                }
 
774
                        }
 
775
                }
 
776
        }
 
777
 
 
778
        // Free the dynamically linked to library
 
779
        FreeLibrary(hShell32);
 
780
 
 
781
        BOINCTRACE(_T("CScreensaver::IsConfigStartupBOINC: Returning '%d'\n"), bRetVal);
 
782
        return bRetVal;
 
783
}
 
784
 
 
785
 
 
786
 
 
787
 
 
788
// Desc: Create the infrastructure for thread safe acccess to the infrastructure
 
789
//       layer of the screen saver.
 
790
//
 
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());
 
795
        return FALSE;
 
796
    }
 
797
    return TRUE;
 
798
}
 
799
 
 
800
 
 
801
 
 
802
 
 
803
// Provide a thread-safe implementation for retrieving the current
 
804
//       error condition.
 
805
//
 
806
BOOL CScreensaver::GetError(
 
807
    BOOL& bErrorMode, HRESULT& hrError, TCHAR* pszError, size_t iErrorSize
 
808
) {
 
809
    DWORD dwWaitResult;
 
810
    BOOL  bRetVal = FALSE;
 
811
 
 
812
    // Request ownership of mutex.
 
813
    dwWaitResult = WaitForSingleObject(
 
814
        m_hErrorManagementMutex,   // handle to mutex
 
815
        5000L);                    // five-second time-out interval
 
816
 
 
817
    switch (dwWaitResult) {
 
818
        // WAIT_OBJECT_0 - The thread got mutex ownership.
 
819
        case WAIT_OBJECT_0:
 
820
            bErrorMode = m_bErrorMode;
 
821
            hrError = m_hrError;
 
822
 
 
823
            if (NULL != pszError) {
 
824
                StringCbCopyN(pszError, iErrorSize, m_szError, sizeof(m_szError) * sizeof(TCHAR));
 
825
            }
 
826
 
 
827
            bRetVal = TRUE;
 
828
            break; 
 
829
 
 
830
        // WAIT_TIMEOUT - Cannot get mutex ownership due to time-out.
 
831
        // WAIT_ABANDONED - Got ownership of the abandoned mutex object.
 
832
        case WAIT_TIMEOUT: 
 
833
        case WAIT_ABANDONED: 
 
834
            break; 
 
835
    }
 
836
 
 
837
    ReleaseMutex(m_hErrorManagementMutex);
 
838
 
 
839
    return bRetVal; 
 
840
}
 
841
 
 
842
 
 
843
 
 
844
 
 
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.
 
848
//
 
849
BOOL CScreensaver::SetError(BOOL bErrorMode, HRESULT hrError) {
 
850
    DWORD dwWaitResult;
 
851
    BOOL  bRetVal = FALSE;
 
852
 
 
853
    // Request ownership of mutex.
 
854
    dwWaitResult = WaitForSingleObject(
 
855
        m_hErrorManagementMutex,   // handle to mutex
 
856
        5000L                // five-second time-out interval
 
857
    );
 
858
 
 
859
    switch (dwWaitResult) {
 
860
        // WAIT_OBJECT_0 - The thread got mutex ownership.
 
861
        case WAIT_OBJECT_0:
 
862
            m_bErrorMode = bErrorMode;
 
863
            m_hrError = hrError;
 
864
 
 
865
            // Update the error text, including a possible RPC call
 
866
            //   to the daemon.
 
867
            UpdateErrorBoxText();
 
868
 
 
869
            bRetVal = TRUE;
 
870
            break; 
 
871
 
 
872
        // WAIT_TIMEOUT - Cannot get mutex ownership due to time-out.
 
873
        // WAIT_ABANDONED - Got ownership of the abandoned mutex object.
 
874
        case WAIT_TIMEOUT: 
 
875
        case WAIT_ABANDONED: 
 
876
            break; 
 
877
    }
 
878
    ReleaseMutex(m_hErrorManagementMutex);
 
879
    return bRetVal; 
 
880
}
 
881
 
 
882
 
 
883
 
 
884
// Update the error message
 
885
//
 
886
VOID CScreensaver::UpdateErrorBoxText() {
 
887
    PROJECT* pProject;
 
888
    bool     bIsActive       = false;
 
889
    bool     bIsExecuting    = false;
 
890
    bool     bIsDownloaded   = false;
 
891
    size_t   iResultCount    = 0;
 
892
    size_t   iIndex          = 0;
 
893
 
 
894
 
 
895
    if ((SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING == m_hrError)
 
896
        || (SCRAPPERR_DAEMONALLOWSNOGRAPHICS == m_hrError) 
 
897
    ) {
 
898
        if (m_updating_results) return;     // results vector is currently being updated by rpc
 
899
        
 
900
        iResultCount = results.results.size();
 
901
                int iModIndex;
 
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 
 
920
                                        );
 
921
                                        if ( m_tLastResultChangeTime+10 < time(0) ) {
 
922
                                                m_iLastResultShown = iModIndex;
 
923
                                                m_tLastResultChangeTime = time(0);
 
924
                                        }
 
925
                                        break;
 
926
                    } else {
 
927
                        m_bResetCoreState = TRUE;
 
928
                                        GetTextForError(IDS_ERR_GENERIC, m_szError, sizeof(m_szError) / sizeof(TCHAR));
 
929
                    }
 
930
            } else {
 
931
                m_bResetCoreState = TRUE;
 
932
                                GetTextForError(IDS_ERR_GENERIC, m_szError, sizeof(m_szError) / sizeof(TCHAR));
 
933
            }
 
934
        }
 
935
        m_szError[ sizeof(m_szError) -1 ] = '\0';
 
936
    } else {
 
937
        // Load error string
 
938
        GetTextForError(m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR));
 
939
    }
 
940
    BOINCTRACE(_T("CScreensaver::UpdateErrorBoxText - Updated Text '%s'\n"), m_szError);
 
941
}
 
942
 
 
943
 
 
944
 
 
945
 
 
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).
 
953
//
 
954
BOOL CScreensaver::GetTextForError(
 
955
    HRESULT hr, TCHAR* pszError, DWORD dwNumChars
 
956
) {
 
957
    const DWORD dwErrorMap[][2] = {
 
958
    //  HRESULT, stringID
 
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
 
972
    };
 
973
    const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]);
 
974
 
 
975
    DWORD iError;
 
976
    DWORD resid = 0;
 
977
 
 
978
    for(iError = 0; iError < dwErrorMapSize; iError++) {
 
979
        if (hr == (HRESULT)dwErrorMap[iError][0]) {
 
980
            resid = dwErrorMap[iError][1];
 
981
        }
 
982
    }
 
983
    if (resid == 0) {
 
984
        resid = IDS_ERR_GENERIC;
 
985
    }
 
986
 
 
987
    LoadString(NULL, resid, pszError, dwNumChars);
 
988
 
 
989
    if (resid == IDS_ERR_GENERIC) {
 
990
        return FALSE;
 
991
    } else {
 
992
        return TRUE;
 
993
    }
 
994
}
 
995
 
 
996
 
 
997
 
 
998
// Create the thread that is used to talk to the daemon.
 
999
//
 
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 
 
1011
 
 
1012
   if (m_hDataManagementThread == NULL) {
 
1013
        BOINCTRACE(_T("CScreensaver::CreateDataManagementThread: Failed to create data management thread '%d'\n"), GetLastError());
 
1014
        return FALSE;
 
1015
   }
 
1016
   return TRUE;
 
1017
}
 
1018
 
 
1019
 
 
1020
 
 
1021
 
 
1022
// Terminate the thread that is used to talk to the daemon.
 
1023
//
 
1024
BOOL CScreensaver::DestroyDataManagementThread() {
 
1025
    m_QuitDataManagementProc = TRUE;  // Tell RPC Thread to exit
 
1026
    
 
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;
 
1031
 
 
1032
        boinc_sleep(0.1);
 
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)) {
 
1036
            break;
 
1037
        }
 
1038
    }
 
1039
    return TRUE;
 
1040
}
 
1041
 
 
1042
 
 
1043
 
 
1044
 
 
1045
// This function forwards to DataManagementProc, which has access to the
 
1046
//       "this" pointer.
 
1047
//
 
1048
DWORD WINAPI CScreensaver::DataManagementProcStub(LPVOID UNUSED(lpParam)) {
 
1049
    return gspScreensaver->DataManagementProc();
 
1050
}
 
1051
 
 
1052
 
 
1053
 
 
1054
 
 
1055
void CScreensaver::HandleRPCError()
 
1056
{
 
1057
    // Attempt to reinitialize the RPC client and state
 
1058
    rpc->close();
 
1059
    rpc->init(NULL);
 
1060
    m_bResetCoreState = TRUE;
 
1061
 
 
1062
    if (!m_bBOINCConfigChecked) {
 
1063
        m_bBOINCConfigChecked = TRUE;
 
1064
        m_bBOINCStartupConfigured = IsConfigStartupBOINC();
 
1065
    }
 
1066
 
 
1067
    if ((time(0) - m_tThreadCreateTime) > 3) {
 
1068
                if (m_bBOINCStartupConfigured) {
 
1069
            SetError(TRUE, SCRAPPERR_BOINCNOTDETECTED);
 
1070
        } else {
 
1071
            SetError(TRUE, SCRAPPERR_BOINCNOTDETECTEDSTARTUP);
 
1072
        }
 
1073
    }
 
1074
 
 
1075
}
 
1076
 
 
1077
 
 
1078
 
 
1079
 
 
1080
void CScreensaver::CheckForegroundWindow()
 
1081
{
 
1082
    BOOL    bForegroundWindowIsScreensaver;
 
1083
    HWND    hwndBOINCGraphicsWindow = NULL;
 
1084
    HWND    hwndForeWindow = NULL;
 
1085
    HWND    hwndForeParent = NULL;
 
1086
    DWORD   iMonitor = 0;
 
1087
    INTERNALMONITORINFO* pMonitorInfo = NULL;
 
1088
 
 
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
 
1097
        //   to the top.
 
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"));
 
1104
 
 
1105
                // This may be needed on Windows 2000 or better machines
 
1106
                if (gspfnMyBroadcastSystemMessage) {
 
1107
                    DWORD dwComponents = BSM_APPLICATIONS;
 
1108
                    gspfnMyBroadcastSystemMessage(
 
1109
                        BSF_ALLOWSFW, 
 
1110
                        &dwComponents,
 
1111
                        WM_BOINCSFW,
 
1112
                        NULL,
 
1113
                        NULL
 
1114
                    );
 
1115
                }
 
1116
            }
 
1117
        } else {
 
1118
            // Science application has focus, and is visible.
 
1119
            //
 
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.
 
1127
            //
 
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"));
 
1134
                LASTINPUTINFO lii;
 
1135
                lii.cbSize = sizeof(LASTINPUTINFO);
 
1136
 
 
1137
                gspfnMyGetLastInputInfo(&lii);
 
1138
 
 
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);
 
1145
                }
 
1146
            }
 
1147
        }
 
1148
    } else {
 
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))
 
1158
            {
 
1159
                bForegroundWindowIsScreensaver = TRUE;
 
1160
            }
 
1161
        }
 
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);
 
1169
        }
 
1170
    }
 
1171
}
 
1172
 
 
1173
 
 
1174
 
 
1175
// Register and create the appropriate window(s)
 
1176
//
 
1177
HRESULT CScreensaver::CreateSaverWindow() {
 
1178
    // Register an appropriate window class for the primary display
 
1179
    WNDCLASS    cls;
 
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;
 
1188
    cls.cbWndExtra     = 0; 
 
1189
    cls.cbClsExtra     = 0; 
 
1190
    RegisterClass(&cls);
 
1191
 
 
1192
    // Register an appropriate window class for the secondary display(s)
 
1193
    WNDCLASS    cls2;
 
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);
 
1205
 
 
1206
    // Create the window
 
1207
    RECT rc;
 
1208
    DWORD dwStyle;
 
1209
    switch (m_SaverMode) {
 
1210
        case sm_preview:
 
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
 
1217
            );
 
1218
            m_Monitors[0].hWnd = m_hWnd;
 
1219
            GetClientRect(m_hWnd, &m_rcRenderTotal);
 
1220
            GetClientRect(m_hWnd, &m_rcRenderCurDevice);
 
1221
            break;
 
1222
 
 
1223
        case sm_test:
 
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
 
1232
            );
 
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);
 
1237
            break;
 
1238
 
 
1239
        case sm_full:
 
1240
            dwStyle = WS_VISIBLE | WS_POPUP;
 
1241
            m_hWnd = NULL;
 
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)
 
1247
                                                continue;
 
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);
 
1253
                                        } else {
 
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);
 
1257
                                        }
 
1258
                                        if (pMonitorInfo->hWnd == NULL) {
 
1259
                                                return E_FAIL;
 
1260
                    }
 
1261
                                        
 
1262
                    if (m_hWnd == NULL) {
 
1263
                                                m_hWnd = pMonitorInfo->hWnd;
 
1264
                    }
 
1265
 
 
1266
                                        SetTimer(pMonitorInfo->hWnd, 2, 250, NULL);
 
1267
                                }
 
1268
            }
 
1269
    }
 
1270
    if (m_hWnd == NULL) {
 
1271
        return E_FAIL;
 
1272
    }
 
1273
 
 
1274
    return S_OK;
 
1275
}
 
1276
 
 
1277
 
 
1278
 
 
1279
// Run the screensaver graphics - may be preview, test or full-on mode
 
1280
//
 
1281
HRESULT CScreensaver::DoSaver() {
 
1282
    // Flag as screensaver running if in full on mode
 
1283
    if (m_SaverMode == sm_full) {
 
1284
        BOOL bUnused;
 
1285
        SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0);
 
1286
    }
 
1287
 
 
1288
 
 
1289
    // Message pump
 
1290
    BOOL bGotMsg;
 
1291
    MSG msg;
 
1292
    msg.message = WM_NULL;
 
1293
    while (msg.message != WM_QUIT) {
 
1294
        bGotMsg = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
 
1295
        if (bGotMsg) {
 
1296
            TranslateMessage(&msg);
 
1297
            DispatchMessage(&msg);
 
1298
        } else {
 
1299
            Sleep(10);
 
1300
        }
 
1301
    }
 
1302
 
 
1303
    return S_OK;
 
1304
}
 
1305
 
 
1306
 
 
1307
 
 
1308
 
 
1309
VOID CScreensaver::DoConfig() {
 
1310
    DialogBox(NULL, MAKEINTRESOURCE(DLG_CONFIG), m_hWndParent, ConfigureDialogProcStub);
 
1311
}
 
1312
 
 
1313
 
 
1314
 
 
1315
// Handle window messages for main screensaver windows.
 
1316
//
 
1317
LRESULT CScreensaver::SaverProc(
 
1318
    HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
 
1319
) {
 
1320
    DWORD dwMonitor = 0;
 
1321
#ifdef _DEBUG
 
1322
    for(DWORD iIndex = 0; iIndex < m_dwNumMonitors; iIndex++) {
 
1323
                if (hWnd == m_Monitors[iIndex].hWnd ) {
 
1324
            dwMonitor = iIndex;
 
1325
        }
 
1326
    }
 
1327
#endif
 
1328
 
 
1329
    BOINCTRACE(_T("CScreensaver::SaverProc [%d] hWnd '%d' uMsg '%X' wParam '%d' lParam '%d'\n"), dwMonitor, hWnd, uMsg, wParam, lParam);
 
1330
 
 
1331
    switch (uMsg) {
 
1332
        case WM_TIMER:
 
1333
            BOINCTRACE(_T("CScreensaver::SaverProc Received WM_TIMER\n"));
 
1334
                        switch (wParam) { 
 
1335
                                case 1: 
 
1336
                                        // Initial idle time is done, proceed with initialization.
 
1337
                                        m_bWaitForInputIdle = FALSE;
 
1338
                                        KillTimer(hWnd, 1);
 
1339
                    return 0;
 
1340
                    break;
 
1341
                                case 2:
 
1342
                    // Create a screen saver window on the primary display if 
 
1343
                    //   the boinc client crashes
 
1344
                        CreateSaverWindow();
 
1345
 
 
1346
                    // Update the position of the box every second so that it
 
1347
                    //   does not end up off the visible area of the screen.
 
1348
                                    UpdateErrorBox();
 
1349
                    return 0;
 
1350
                    break;
 
1351
            }
 
1352
            break;
 
1353
        case WM_PAINT:
 
1354
            {
 
1355
                                BOOL    bErrorMode;
 
1356
                                HRESULT hrError;
 
1357
                                TCHAR   szError[400];
 
1358
                                GetError(bErrorMode, hrError, szError, sizeof(szError)/sizeof(TCHAR));
 
1359
 
 
1360
                                // Show error message, if there is one
 
1361
                PAINTSTRUCT ps;
 
1362
                BeginPaint(hWnd, &ps);
 
1363
 
 
1364
                // In preview mode, just fill 
 
1365
                // the preview window with black, and the BOINC icon. 
 
1366
                if (!bErrorMode && m_SaverMode == sm_preview) {
 
1367
                    RECT rc;
 
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)));
 
1372
                } else {
 
1373
                    DoPaint(hWnd, ps.hdc, &ps);
 
1374
                }
 
1375
 
 
1376
                EndPaint(hWnd, &ps);
 
1377
            }
 
1378
 
 
1379
            return 0;
 
1380
            break;
 
1381
 
 
1382
        case WM_MOUSEMOVE:
 
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) {
 
1389
                    xPrev = xCur;
 
1390
                    yPrev = yCur;
 
1391
                    m_dwSaverMouseMoveCount++;
 
1392
                    if (m_dwSaverMouseMoveCount > 5) {
 
1393
                        BOINCTRACE(_T("CScreensaver::SaverProc Received WM_MOUSEMOVE and time to InterruptSaver()\n"));
 
1394
                        InterruptSaver();
 
1395
                    }
 
1396
                }
 
1397
            }
 
1398
            return 0;
 
1399
            break;
 
1400
 
 
1401
        case WM_KEYDOWN:
 
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) {
 
1407
                InterruptSaver();
 
1408
            }
 
1409
            return 0;
 
1410
            break;
 
1411
 
 
1412
        case WM_CLOSE:
 
1413
        case WM_DESTROY:
 
1414
            BOINCTRACE(_T("CScreensaver::SaverProc Received WM_CLOSE or WM_DESTROY\n"));
 
1415
            if (m_SaverMode == sm_preview || m_SaverMode == sm_test) {
 
1416
                ShutdownSaver();
 
1417
            }
 
1418
            return 0;
 
1419
            break;
 
1420
 
 
1421
        case WM_SYSCOMMAND: 
 
1422
            BOINCTRACE(_T("CScreensaver::SaverProc Received WM_SYSCOMMAND\n"));
 
1423
            if (m_SaverMode == sm_full) {
 
1424
                switch (wParam) {
 
1425
                    case SC_NEXTWINDOW:
 
1426
                    case SC_PREVWINDOW:
 
1427
                    case SC_SCREENSAVE:
 
1428
                    case SC_CLOSE:
 
1429
                        return 0;
 
1430
                }
 
1431
            }
 
1432
            break;
 
1433
 
 
1434
        case WM_SETCURSOR:
 
1435
            BOINCTRACE(_T("CScreensaver::SaverProc Received WM_SETCURSOR\n"));
 
1436
            if (m_SaverMode == sm_full && !m_bCheckingSaverPassword) {
 
1437
                // Hide cursor
 
1438
                SetCursor(NULL);
 
1439
                return TRUE;
 
1440
            }
 
1441
            break;
 
1442
 
 
1443
        case WM_POWERBROADCAST:
 
1444
            BOINCTRACE(_T("CScreensaver::SaverProc Received WM_POWERBROADCAST\n"));
 
1445
            if (wParam == PBT_APMQUERYSUSPEND && gspfnMyVerifyPwdProc == NULL)
 
1446
                InterruptSaver();
 
1447
            break;
 
1448
    }
 
1449
 
 
1450
    if (WM_SETTIMER == uMsg) {
 
1451
 
 
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);
 
1456
 
 
1457
    } else if (WM_INTERRUPTSAVER == uMsg) {
 
1458
 
 
1459
        BOINCTRACE(_T("CScreensaver::SaverProc Received WM_INTERRUPTSAVER\n"));
 
1460
        if (hWnd == m_Monitors[0].hWnd) {
 
1461
            InterruptSaver();
 
1462
        }
 
1463
 
 
1464
    }
 
1465
 
 
1466
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
 
1467
}
 
1468
 
 
1469
 
 
1470
 
 
1471
 
 
1472
INT_PTR CScreensaver::ConfigureDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM UNUSED(lParam)) {
 
1473
        DWORD screen_blank=0, blank_time=0;
 
1474
        char buf[256];
 
1475
        int retval;
 
1476
 
 
1477
        switch (msg) {
 
1478
                case WM_INITDIALOG:
 
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);
 
1482
                        if (retval < 0) {
 
1483
                screen_blank=0;
 
1484
            }
 
1485
                        CheckDlgButton(hwnd, IDC_BLANK, screen_blank);
 
1486
 
 
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);
 
1491
 
 
1492
                        return TRUE;
 
1493
                case WM_COMMAND:
 
1494
                        int id=LOWORD(wParam);
 
1495
                        if (id==IDOK) {
 
1496
 
 
1497
                                screen_blank = (IsDlgButtonChecked(hwnd, IDC_BLANK) == BST_CHECKED);
 
1498
                                UtilSetRegKey(REG_BLANK_NAME, screen_blank);
 
1499
 
 
1500
                                GetDlgItemText(hwnd, IDC_BLANK_TIME, buf, 256);
 
1501
                                blank_time = atoi(buf);
 
1502
                                UtilSetRegKey(REG_BLANK_TIME, blank_time);
 
1503
 
 
1504
                        }
 
1505
                        if (id == IDOK || id == IDCANCEL) {
 
1506
                                EndDialog(hwnd, id);
 
1507
            }
 
1508
                        break;
 
1509
        }
 
1510
        return FALSE;
 
1511
}
 
1512
 
 
1513
 
 
1514
 
 
1515
 
 
1516
// This function forwards all window messages to SaverProc, which has
 
1517
//       access to the "this" pointer.
 
1518
//
 
1519
LRESULT CALLBACK CScreensaver::SaverProcStub(
 
1520
    HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
 
1521
) {
 
1522
    return gspScreensaver->SaverProc(hWnd, uMsg, wParam, lParam);
 
1523
}
 
1524
 
 
1525
 
 
1526
 
 
1527
 
 
1528
INT_PTR CALLBACK CScreensaver::ConfigureDialogProcStub(
 
1529
    HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
 
1530
) {
 
1531
    return gspScreensaver->ConfigureDialogProc(hwndDlg, uMsg, wParam, lParam);
 
1532
}
 
1533
 
 
1534
 
 
1535
 
 
1536
 
 
1537
VOID CScreensaver::ShutdownSaver() {
 
1538
    // Unflag screensaver running if in full on mode
 
1539
    if (m_SaverMode == sm_full) {
 
1540
        BOOL bUnused;
 
1541
        SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0);
 
1542
    }
 
1543
 
 
1544
    // Kill the currently executing graphics application
 
1545
    terminate_screensaver(m_hGraphicsApplication, &m_running_result);
 
1546
 
 
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
 
1551
    // exists.
 
1552
    if (m_Monitors[0].hWnd) {
 
1553
        PostMessage(m_Monitors[0].hWnd, WM_QUIT, 0, 0);
 
1554
    }
 
1555
}
 
1556
 
 
1557
 
 
1558
 
 
1559
 
 
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.
 
1562
//
 
1563
VOID CScreensaver::InterruptSaver() {
 
1564
    BOOL bPasswordOkay = FALSE;
 
1565
 
 
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;
 
1574
 
 
1575
                BOINCTRACE(_T("CScreensaver::InterruptSaver Calling VerifyScreenSavePwd\n"));
 
1576
                bPasswordOkay = gspfnMyVerifyPwdProc(m_hWnd);
 
1577
                BOINCTRACE(_T("CScreensaver::InterruptSaver Finished\n"));
 
1578
 
 
1579
                m_bCheckingSaverPassword = FALSE;
 
1580
 
 
1581
                if (!bPasswordOkay) {
 
1582
                    // Back to screen saving...
 
1583
                    BOINCTRACE(_T("CScreensaver::InterruptSaver Incorrect Password Given, Resetting m_dwSaverMouseMoveCount\n"));
 
1584
                    SetCursor(NULL);
 
1585
                    m_dwSaverMouseMoveCount = 0;
 
1586
                    return;
 
1587
                }
 
1588
            }
 
1589
        }
 
1590
        ShutdownSaver();
 
1591
    } else {
 
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();
 
1598
            if (hwndPassword) {
 
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);
 
1603
                }
 
1604
            }
 
1605
        }
 
1606
    }
 
1607
    BOINCTRACE(_T("CScreensaver::InterruptSaver Function End\n"));
 
1608
}
 
1609
 
 
1610
 
 
1611
 
 
1612
 
 
1613
// Update the box that shows the error message
 
1614
//
 
1615
VOID CScreensaver::UpdateErrorBox() {
 
1616
    INTERNALMONITORINFO* pMonitorInfo;
 
1617
    HWND hwnd;
 
1618
    RECT rcBounds;
 
1619
    static DWORD dwTimeLast = 0;
 
1620
    DWORD dwTimeNow;
 
1621
    FLOAT fTimeDelta;
 
1622
 
 
1623
 
 
1624
    // Update timing to determine how much to move error box
 
1625
    if (dwTimeLast == 0) {
 
1626
        dwTimeLast = timeGetTime();
 
1627
    }
 
1628
 
 
1629
    dwTimeNow = timeGetTime();
 
1630
    fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 10000.0f;
 
1631
    dwTimeLast = dwTimeNow;
 
1632
 
 
1633
    for(DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) {
 
1634
        pMonitorInfo = &m_Monitors[iMonitor];
 
1635
        hwnd = pMonitorInfo->hWnd;
 
1636
        if (hwnd == NULL)
 
1637
            continue;
 
1638
        if (m_SaverMode == sm_full) {
 
1639
            rcBounds = pMonitorInfo->rcScreen;
 
1640
            ScreenToClient(hwnd, (POINT*)&rcBounds.left);
 
1641
            ScreenToClient(hwnd, (POINT*)&rcBounds.right);
 
1642
        } else {
 
1643
            rcBounds = m_rcRenderTotal;
 
1644
        }
 
1645
 
 
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
 
1655
                UpdateWindow(hwnd);
 
1656
            } else {
 
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;
 
1663
            }
 
1664
        } else {
 
1665
            if (m_SaverMode != sm_preview) {
 
1666
                RECT rcOld;
 
1667
                RECT rcNew;
 
1668
 
 
1669
                SetRect(&rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
 
1670
                    (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
 
1671
                    (INT)(pMonitorInfo->yError + pMonitorInfo->heightError));
 
1672
 
 
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)
 
1678
                ) {
 
1679
                    pMonitorInfo->xVelError = -pMonitorInfo->xVelError;
 
1680
                }
 
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)
 
1685
                ) {
 
1686
                    pMonitorInfo->yVelError = -pMonitorInfo->yVelError;
 
1687
                }
 
1688
                // Update rect position
 
1689
                pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta;
 
1690
                pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta;
 
1691
            
 
1692
                SetRect(&rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
 
1693
                    (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
 
1694
                    (INT)(pMonitorInfo->yError + pMonitorInfo->heightError));
 
1695
 
 
1696
                                if ((dwTimeNow - pMonitorInfo->dwTimeLastUpdate) > 1000)
 
1697
                                {
 
1698
                                        pMonitorInfo->dwTimeLastUpdate = dwTimeNow;
 
1699
 
 
1700
                    InvalidateRect(hwnd, NULL, TRUE);
 
1701
                    UpdateWindow(hwnd);
 
1702
                                }
 
1703
            }
 
1704
        }
 
1705
    }
 
1706
}
 
1707
 
 
1708
 
 
1709
 
 
1710
 
 
1711
VOID CScreensaver::DoPaint(HWND hwnd, HDC hdc, LPPAINTSTRUCT lpps) {
 
1712
    DWORD iMonitor = 0;
 
1713
    INTERNALMONITORINFO* pMonitorInfo = NULL;
 
1714
    HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
 
1715
 
 
1716
    for(iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++) {
 
1717
        pMonitorInfo = &m_Monitors[iMonitor];
 
1718
        if (pMonitorInfo->hMonitor == hMonitor)
 
1719
            break;
 
1720
    }
 
1721
 
 
1722
    if (iMonitor == m_dwNumMonitors) {
 
1723
        return;
 
1724
    }
 
1725
 
 
1726
    // Retrieve the latest piece of error information 
 
1727
    BOOL    bErrorMode;
 
1728
    HRESULT hrError;
 
1729
    TCHAR       szError[400];
 
1730
    GetError(bErrorMode, hrError, szError, sizeof(szError)/sizeof(TCHAR));
 
1731
 
 
1732
 
 
1733
    // Start drawing the goods
 
1734
    RECT    rc;
 
1735
    RECT    rc2;
 
1736
    RECT    rcOrginal;
 
1737
        int             iTextHeight;
 
1738
 
 
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));
 
1742
 
 
1743
 
 
1744
        // Start off with a black screen and then draw on top of it.
 
1745
        FillRect(hdc, &lpps->rcPaint, hbrushBlack);
 
1746
 
 
1747
 
 
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.
 
1750
    if (!bErrorMode) {
 
1751
        return;
 
1752
    }
 
1753
 
 
1754
    
 
1755
    SetRect(&rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
 
1756
        (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
 
1757
        (INT)(pMonitorInfo->yError + pMonitorInfo->heightError)
 
1758
    );
 
1759
//  This fill rect is useful when testing
 
1760
//      FillRect(hdc, &rc, hbrushRed);
 
1761
        rcOrginal = rc;
 
1762
 
 
1763
 
 
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.
 
1768
    BITMAP     bm;
 
1769
    GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bm);
 
1770
 
 
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));
 
1774
 
 
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
 
1778
   
 
1779
        // Set font
 
1780
        HFONT hf;
 
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");
 
1782
        
 
1783
    if(hf)
 
1784
    {
 
1785
        SelectObject(hdc, hf);
 
1786
    }
 
1787
        rc2 = rc;
 
1788
    iTextHeight = DrawText(hdc, szError, -1, &rc, DT_CENTER | DT_CALCRECT);
 
1789
        rc = rc2;
 
1790
        rc2.top+=bm.bmHeight+20;
 
1791
    DrawText(hdc, szError, -1, &rc2, DT_CENTER);
 
1792
}
 
1793
 
 
1794
 
 
1795
 
 
1796
 
 
1797
// Draws a bitmap on the screen with a transparent background.
 
1798
//         Code orginally from Microsoft Knowledge Base Article - 79212
 
1799
//
 
1800
void CScreensaver::DrawTransparentBitmap(
 
1801
    HDC hdc, HBITMAP hBitmap, LONG xStart, LONG yStart,
 
1802
    COLORREF cTransparentColor
 
1803
){
 
1804
    BITMAP     bm;
 
1805
    COLORREF   cColor;
 
1806
    HBITMAP    bmAndBack, bmAndObject, bmAndMem, bmSave;
 
1807
    HBITMAP    bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
 
1808
    HDC        hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
 
1809
    POINT      ptSize;
 
1810
 
 
1811
    hdcTemp = CreateCompatibleDC(hdc);
 
1812
    SelectObject(hdcTemp, hBitmap);   // Select the bitmap
 
1813
 
 
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
 
1818
 
 
1819
                                     // to logical points
 
1820
 
 
1821
    // Create some DCs to hold temporary data.
 
1822
    hdcBack   = CreateCompatibleDC(hdc);
 
1823
    hdcObject = CreateCompatibleDC(hdc);
 
1824
    hdcMem    = CreateCompatibleDC(hdc);
 
1825
    hdcSave   = CreateCompatibleDC(hdc);
 
1826
 
 
1827
    // Create a bitmap for each DC. DCs are required for a number of
 
1828
    // GDI functions.
 
1829
 
 
1830
    // Monochrome DC
 
1831
    bmAndBack   = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
 
1832
 
 
1833
    // Monochrome DC
 
1834
    bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
 
1835
 
 
1836
    bmAndMem    = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
 
1837
    bmSave      = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
 
1838
 
 
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);
 
1844
 
 
1845
    // Set proper mapping mode.
 
1846
    SetMapMode(hdcTemp, GetMapMode(hdc));
 
1847
 
 
1848
    // Save the bitmap sent here, because it will be overwritten.
 
1849
    BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
 
1850
 
 
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);
 
1854
 
 
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);
 
1858
 
 
1859
    // Set the background color of the source DC back to the original
 
1860
    // color.
 
1861
    SetBkColor(hdcTemp, cColor);
 
1862
 
 
1863
    // Create the inverse of the object mask.
 
1864
    BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
 
1865
 
 
1866
    // Copy the background of the main DC to the destination.
 
1867
    BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart, SRCCOPY);
 
1868
 
 
1869
    // Mask out the places where the bitmap will be placed.
 
1870
    BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
 
1871
 
 
1872
    // Mask out the transparent colored pixels on the bitmap.
 
1873
    BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
 
1874
 
 
1875
    // XOR the bitmap with the background on the destination DC.
 
1876
    BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
 
1877
 
 
1878
    // Copy the destination to the screen.
 
1879
    BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
 
1880
 
 
1881
    // Place the original bitmap back into the bitmap sent here.
 
1882
    BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
 
1883
 
 
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));
 
1889
 
 
1890
    // Delete the memory DCs.
 
1891
    DeleteDC(hdcMem);
 
1892
    DeleteDC(hdcBack);
 
1893
    DeleteDC(hdcObject);
 
1894
    DeleteDC(hdcSave);
 
1895
    DeleteDC(hdcTemp);
 
1896
}
 
1897
 
 
1898
 
 
1899
 
 
1900
 
 
1901
VOID CScreensaver::ChangePassword() {
 
1902
    // Load the password change DLL
 
1903
    HINSTANCE mpr = LoadLibrary(_T("MPR.DLL"));
 
1904
 
 
1905
    if (mpr != NULL) {
 
1906
        // Grab the password change function from it
 
1907
        typedef DWORD (PASCAL *PWCHGPROC)(LPCSTR, HWND, DWORD, LPVOID);
 
1908
        PWCHGPROC pwd = (PWCHGPROC)GetProcAddress(mpr, "PwdChangePasswordA");
 
1909
 
 
1910
        // Do the password change
 
1911
        if (pwd != NULL) {
 
1912
            pwd("SCRSAVE", m_hWndParent, 0, NULL);
 
1913
        }
 
1914
 
 
1915
        // Free the library
 
1916
        FreeLibrary(mpr);
 
1917
    }
 
1918
}
 
1919
 
 
1920
 
 
1921
 
 
1922
 
 
1923
const char *BOINC_RCSID_116268c72f = "$Id: screensaver_win.cpp 15235 2008-05-16 16:55:02Z romw $";