00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "CMSWindowsScreenSaver.h"
00016 #include "CMSWindowsScreen.h"
00017 #include "CThread.h"
00018 #include "CLog.h"
00019 #include "TMethodJob.h"
00020 #include "CArch.h"
00021 #include "CArchMiscWindows.h"
00022 #include <malloc.h>
00023 #include <tchar.h>
00024
00025 #if !defined(SPI_GETSCREENSAVERRUNNING)
00026 #define SPI_GETSCREENSAVERRUNNING 114
00027 #endif
00028
00029 static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure";
00030 static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword";
00031 static const TCHAR* const g_pathScreenSaverIsSecure[] = {
00032 "Control Panel",
00033 "Desktop",
00034 NULL
00035 };
00036
00037
00038
00039
00040
00041 CMSWindowsScreenSaver::CMSWindowsScreenSaver() :
00042 m_wasSecure(false),
00043 m_wasSecureAnInt(false),
00044 m_process(NULL),
00045 m_watch(NULL),
00046 m_threadID(0),
00047 m_active(false)
00048 {
00049
00050 m_is95Family = false;
00051 m_is95 = false;
00052 m_isNT = false;
00053 OSVERSIONINFO info;
00054 info.dwOSVersionInfoSize = sizeof(info);
00055 if (GetVersionEx(&info)) {
00056 m_is95Family = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
00057 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
00058 info.dwMajorVersion <= 4) {
00059 m_isNT = true;
00060 }
00061 else if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
00062 info.dwMajorVersion == 4 &&
00063 info.dwMinorVersion == 0) {
00064 m_is95 = true;
00065 }
00066 }
00067
00068
00069 SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
00070 }
00071
00072 CMSWindowsScreenSaver::~CMSWindowsScreenSaver()
00073 {
00074 unwatchProcess();
00075 }
00076
00077 bool
00078 CMSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
00079 {
00080
00081 if (m_active) {
00082 return false;
00083 }
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 Sleep(250);
00094
00095
00096 m_threadID = GetCurrentThreadId();
00097 m_msg = msg;
00098 m_wParam = wParam;
00099 m_lParam = lParam;
00100
00101
00102
00103 if (m_is95Family) {
00104
00105
00106 DWORD processID = findScreenSaver();
00107 HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID);
00108 if (process == NULL) {
00109
00110 LOG((CLOG_DEBUG2 "can't open screen saver process"));
00111 return false;
00112 }
00113
00114
00115 watchProcess(process);
00116 }
00117 else {
00118
00119
00120
00121
00122
00123
00124
00125 if (!isActive()) {
00126 LOG((CLOG_DEBUG2 "can't open screen saver desktop"));
00127 return false;
00128 }
00129
00130 watchDesktop();
00131 }
00132
00133 return true;
00134 }
00135
00136 void
00137 CMSWindowsScreenSaver::enable()
00138 {
00139 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0);
00140
00141
00142 if (m_wasSecure) {
00143 setSecure(true, m_wasSecureAnInt);
00144 }
00145
00146
00147 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
00148 }
00149
00150 void
00151 CMSWindowsScreenSaver::disable()
00152 {
00153 SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
00154 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0);
00155
00156
00157 m_wasSecure = isSecure(&m_wasSecureAnInt);
00158 if (m_wasSecure) {
00159 setSecure(false, m_wasSecureAnInt);
00160 }
00161
00162
00163 CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);
00164 }
00165
00166 void
00167 CMSWindowsScreenSaver::activate()
00168 {
00169
00170 if (!isActive()) {
00171
00172 HWND hwnd = GetForegroundWindow();
00173 if (hwnd != NULL) {
00174 PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
00175 }
00176 else {
00177
00178 DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
00179 }
00180
00181
00182 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
00183 }
00184 }
00185
00186 void
00187 CMSWindowsScreenSaver::deactivate()
00188 {
00189 bool killed = false;
00190 if (!m_is95Family) {
00191
00192 HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE,
00193 DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
00194 if (desktop != NULL) {
00195 EnumDesktopWindows(desktop,
00196 &CMSWindowsScreenSaver::killScreenSaverFunc,
00197 reinterpret_cast<LPARAM>(&killed));
00198 CloseDesktop(desktop);
00199 }
00200 }
00201
00202
00203 if (!killed) {
00204
00205 HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
00206 if (hwnd == NULL) {
00207
00208 hwnd = FindWindow("Default Screen Saver", NULL);
00209 }
00210 if (hwnd != NULL) {
00211 PostMessage(hwnd, WM_CLOSE, 0, 0);
00212 }
00213 }
00214
00215
00216 SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
00217 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
00218 !m_wasEnabled, 0, SPIF_SENDWININICHANGE);
00219 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
00220 m_wasEnabled, 0, SPIF_SENDWININICHANGE);
00221
00222
00223 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
00224 }
00225
00226 bool
00227 CMSWindowsScreenSaver::isActive() const
00228 {
00229 if (m_is95) {
00230 return (FindWindow("WindowsScreenSaverClass", NULL) != NULL);
00231 }
00232 else if (m_isNT) {
00233
00234 HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, MAXIMUM_ALLOWED);
00235 if (desktop == NULL && GetLastError() != ERROR_ACCESS_DENIED) {
00236
00237 return false;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 CFindScreenSaverInfo info;
00253 info.m_desktop = desktop;
00254 info.m_window = NULL;
00255 EnumDesktopWindows(desktop,
00256 &CMSWindowsScreenSaver::findScreenSaverFunc,
00257 reinterpret_cast<LPARAM>(&info));
00258
00259
00260 CloseDesktop(desktop);
00261
00262
00263 return (info.m_window != NULL);
00264 }
00265 else {
00266 BOOL running;
00267 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
00268 return (running != FALSE);
00269 }
00270 }
00271
00272 BOOL CALLBACK
00273 CMSWindowsScreenSaver::findScreenSaverFunc(HWND hwnd, LPARAM arg)
00274 {
00275 CFindScreenSaverInfo* info = reinterpret_cast<CFindScreenSaverInfo*>(arg);
00276
00277 if (info->m_desktop != NULL) {
00278 DWORD threadID = GetWindowThreadProcessId(hwnd, NULL);
00279 HDESK desktop = GetThreadDesktop(threadID);
00280 if (desktop != NULL && desktop != info->m_desktop) {
00281
00282 return FALSE;
00283 }
00284 }
00285
00286
00287 info->m_window = hwnd;
00288
00289
00290 return FALSE;
00291 }
00292
00293 BOOL CALLBACK
00294 CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)
00295 {
00296 if (IsWindowVisible(hwnd)) {
00297 HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
00298 if (instance != CMSWindowsScreen::getInstance()) {
00299 PostMessage(hwnd, WM_CLOSE, 0, 0);
00300 *reinterpret_cast<bool*>(arg) = true;
00301 }
00302 }
00303 return TRUE;
00304 }
00305
00306 DWORD
00307 CMSWindowsScreenSaver::findScreenSaver()
00308 {
00309
00310 HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
00311
00312
00313 if (hwnd != NULL) {
00314 DWORD processID;
00315 GetWindowThreadProcessId(hwnd, &processID);
00316 return processID;
00317 }
00318
00319
00320 return 0;
00321 }
00322
00323 void
00324 CMSWindowsScreenSaver::watchDesktop()
00325 {
00326
00327 unwatchProcess();
00328
00329
00330 LOG((CLOG_DEBUG "watching screen saver desktop"));
00331 m_active = true;
00332 m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
00333 &CMSWindowsScreenSaver::watchDesktopThread));
00334 }
00335
00336 void
00337 CMSWindowsScreenSaver::watchProcess(HANDLE process)
00338 {
00339
00340 unwatchProcess();
00341
00342
00343 if (process != NULL) {
00344 LOG((CLOG_DEBUG "watching screen saver process"));
00345 m_process = process;
00346 m_active = true;
00347 m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
00348 &CMSWindowsScreenSaver::watchProcessThread));
00349 }
00350 }
00351
00352 void
00353 CMSWindowsScreenSaver::unwatchProcess()
00354 {
00355 if (m_watch != NULL) {
00356 LOG((CLOG_DEBUG "stopped watching screen saver process/desktop"));
00357 m_watch->cancel();
00358 m_watch->wait();
00359 delete m_watch;
00360 m_watch = NULL;
00361 m_active = false;
00362 }
00363 if (m_process != NULL) {
00364 CloseHandle(m_process);
00365 m_process = NULL;
00366 }
00367 }
00368
00369 void
00370 CMSWindowsScreenSaver::watchDesktopThread(void*)
00371 {
00372 DWORD reserved = 0;
00373 TCHAR* name = NULL;
00374
00375 for (;;) {
00376
00377 ARCH->sleep(0.2);
00378
00379 if (m_isNT) {
00380
00381 HDESK desk = OpenInputDesktop(0, FALSE, GENERIC_READ);
00382 if (desk == NULL) {
00383
00384 continue;
00385 }
00386
00387
00388 DWORD size;
00389 GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
00390
00391
00392 if (size > reserved) {
00393 reserved = size;
00394 name = (TCHAR*)alloca(reserved + sizeof(TCHAR));
00395 }
00396
00397
00398 GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
00399 CloseDesktop(desk);
00400
00401
00402 if (_tcsicmp(name, TEXT("Screen-saver")) == 0) {
00403
00404 continue;
00405 }
00406 }
00407 else {
00408
00409 BOOL running;
00410 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
00411 if (running) {
00412 continue;
00413 }
00414 }
00415
00416
00417 m_active = false;
00418 PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
00419 return;
00420 }
00421 }
00422
00423 void
00424 CMSWindowsScreenSaver::watchProcessThread(void*)
00425 {
00426 for (;;) {
00427 CThread::testCancel();
00428 if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) {
00429
00430 LOG((CLOG_DEBUG "screen saver died"));
00431
00432
00433 m_active = false;
00434 PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
00435 return;
00436 }
00437 }
00438 }
00439
00440 void
00441 CMSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt)
00442 {
00443 HKEY hkey =
00444 CArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
00445 if (hkey == NULL) {
00446 return;
00447 }
00448
00449 const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;
00450 if (saveSecureAsInt) {
00451 CArchMiscWindows::setValue(hkey, isSecure, secure ? 1 : 0);
00452 }
00453 else {
00454 CArchMiscWindows::setValue(hkey, isSecure, secure ? "1" : "0");
00455 }
00456
00457 CArchMiscWindows::closeKey(hkey);
00458 }
00459
00460 bool
00461 CMSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const
00462 {
00463
00464 HKEY hkey =
00465 CArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
00466 if (hkey == NULL) {
00467 return false;
00468 }
00469
00470
00471
00472 bool result;
00473 const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;
00474 switch (CArchMiscWindows::typeOfValue(hkey, isSecure)) {
00475 default:
00476 result = false;
00477 break;
00478
00479 case CArchMiscWindows::kUINT: {
00480 DWORD value =
00481 CArchMiscWindows::readValueInt(hkey, isSecure);
00482 *wasSecureFlagAnInt = true;
00483 result = (value != 0);
00484 break;
00485 }
00486
00487 case CArchMiscWindows::kSTRING: {
00488 std::string value =
00489 CArchMiscWindows::readValueString(hkey, isSecure);
00490 *wasSecureFlagAnInt = false;
00491 result = (value != "0");
00492 break;
00493 }
00494 }
00495
00496 CArchMiscWindows::closeKey(hkey);
00497 return result;
00498 }