Ignore:
Timestamp:
Jul 29, 2006, 6:43:07 AM (19 years ago)
Author:
bird
Message:

Two classes (CPMScreen and CPMKeyState) + the hook dll left (and debugging of course).

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/synergy/lib/platform/CPMScreenSaver.cpp

    r2751 r2752  
    22 * synergy -- mouse and keyboard sharing utility
    33 * Copyright (C) 2002 Chris Schoeneman
     4 * Copyright (C) 2006 Knut St. Osmundsen
    45 *
    56 * This package is free software; you can redistribute it and/or
     
    1314 */
    1415
    15 #include "CMSWindowsScreenSaver.h"
    16 #include "CMSWindowsScreen.h"
    17 #include "CThread.h"
    18 #include "CLog.h"
    19 #include "TMethodJob.h"
    20 #include "CArch.h"
    21 #include "CArchMiscWindows.h"
    22 #include <malloc.h>
    23 #include <tchar.h>
    24 
    25 #if !defined(SPI_GETSCREENSAVERRUNNING)
    26 #define SPI_GETSCREENSAVERRUNNING 114
    27 #endif
    28 
    29 static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure";
    30 static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword";
    31 static const TCHAR* const g_pathScreenSaverIsSecure[] = {
    32         "Control Panel",
    33         "Desktop",
    34         NULL
    35 };
     16#include "CPMScreenSaver.h"
    3617
    3718//
    38 // CMSWindowsScreenSaver
     19// CPMScreenSaver
    3920//
    4021
    41 CMSWindowsScreenSaver::CMSWindowsScreenSaver() :
    42         m_wasSecure(false),
    43         m_wasSecureAnInt(false),
    44         m_process(NULL),
    45         m_watch(NULL),
    46         m_threadID(0),
    47         m_active(false)
     22CPMScreenSaver::CPMScreenSaver()
    4823{
    49         // detect OS
    50         m_is95Family = false;
    51         m_is95       = false;
    52         m_isNT       = false;
    53         OSVERSIONINFO info;
    54         info.dwOSVersionInfoSize = sizeof(info);
    55         if (GetVersionEx(&info)) {
    56                 m_is95Family = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
    57                 if (info.dwPlatformId   == VER_PLATFORM_WIN32_NT &&
    58                         info.dwMajorVersion <= 4) {
    59                         m_isNT = true;
    60                 }
    61                 else if (info.dwPlatformId  == VER_PLATFORM_WIN32_WINDOWS &&
    62                                 info.dwMajorVersion == 4 &&
    63                                 info.dwMinorVersion == 0) {
    64                         m_is95 = true;
    65                 }
    66         }
    67 
    68         // check if screen saver is enabled
    69         SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
    7024}
    7125
    72 CMSWindowsScreenSaver::~CMSWindowsScreenSaver()
     26CPMScreenSaver::~CPMScreenSaver()
    7327{
    74         unwatchProcess();
     28}
     29
     30void
     31CPMScreenSaver::enable()
     32{
     33}
     34
     35void
     36CPMScreenSaver::disable()
     37{
     38}
     39
     40void
     41CPMScreenSaver::activate()
     42{
     43}
     44
     45void
     46CPMScreenSaver::deactivate()
     47{
    7548}
    7649
    7750bool
    78 CMSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
     51CPMScreenSaver::isActive() const
    7952{
    80         // if already started then say it didn't just start
    81         if (m_active) {
    82                 return false;
    83         }
    84 
    85         // screen saver may have started.  look for it and get
    86         // the process.  if we can't find it then assume it
    87         // didn't really start.  we wait a moment before
    88         // looking to give the screen saver a chance to start.
    89         // this shouldn't be a problem since we only get here
    90         // if the screen saver wants to kick in, meaning that
    91         // the system is idle or the user deliberately started
    92         // the screen saver.
    93         Sleep(250);
    94 
    95         // set parameters common to all screen saver handling
    96         m_threadID = GetCurrentThreadId();
    97         m_msg      = msg;
    98         m_wParam   = wParam;
    99         m_lParam   = lParam;
    100 
    101         // we handle the screen saver differently for the windows
    102         // 95 and nt families.
    103         if (m_is95Family) {
    104                 // on windows 95 we wait for the screen saver process
    105                 // to terminate.  get the process.
    106                 DWORD processID = findScreenSaver();
    107                 HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID);
    108                 if (process == NULL) {
    109                         // didn't start
    110                         LOG((CLOG_DEBUG2 "can't open screen saver process"));
    111                         return false;
    112                 }
    113 
    114                 // watch for the process to exit
    115                 watchProcess(process);
    116         }
    117         else {
    118                 // on the windows nt family we wait for the desktop to
    119                 // change until it's neither the Screen-Saver desktop
    120                 // nor a desktop we can't open (the login desktop).
    121                 // since windows will send the request-to-start-screen-
    122                 // saver message even when the screen saver is disabled
    123                 // we first check that the screen saver is indeed active
    124                 // before watching for it to stop.
    125                 if (!isActive()) {
    126                         LOG((CLOG_DEBUG2 "can't open screen saver desktop"));
    127                         return false;
    128                 }
    129 
    130                 watchDesktop();
    131         }
    132 
    133         return true;
     53    return false;
    13454}
    13555
    136 void
    137 CMSWindowsScreenSaver::enable()
    138 {
    139         SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0);
    140 
    141         // restore password protection
    142         if (m_wasSecure) {
    143                 setSecure(true, m_wasSecureAnInt);
    144         }
    145 
    146         // restore display power down
    147         CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
    148 }
    149 
    150 void
    151 CMSWindowsScreenSaver::disable()
    152 {
    153         SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
    154         SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0);
    155 
    156         // disable password protected screensaver
    157         m_wasSecure = isSecure(&m_wasSecureAnInt);
    158         if (m_wasSecure) {
    159                 setSecure(false, m_wasSecureAnInt);
    160         }
    161 
    162         // disable display power down
    163         CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);
    164 }
    165 
    166 void
    167 CMSWindowsScreenSaver::activate()
    168 {
    169         // don't activate if already active
    170         if (!isActive()) {
    171                 // activate
    172                 HWND hwnd = GetForegroundWindow();
    173                 if (hwnd != NULL) {
    174                         PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
    175                 }
    176                 else {
    177                         // no foreground window.  pretend we got the event instead.
    178                         DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
    179                 }
    180 
    181                 // restore power save when screen saver activates
    182                 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
    183         }
    184 }
    185 
    186 void
    187 CMSWindowsScreenSaver::deactivate()
    188 {
    189         bool killed = false;
    190         if (!m_is95Family) {
    191                 // NT runs screen saver in another desktop
    192                 HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE,
    193                                                                 DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
    194                 if (desktop != NULL) {
    195                         EnumDesktopWindows(desktop,
    196                                                                 &CMSWindowsScreenSaver::killScreenSaverFunc,
    197                                                                 reinterpret_cast<LPARAM>(&killed));
    198                         CloseDesktop(desktop);
    199                 }
    200         }
    201 
    202         // if above failed or wasn't tried, try the windows 95 way
    203         if (!killed) {
    204                 // find screen saver window and close it
    205                 HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
    206                 if (hwnd == NULL) {
    207                         // win2k may use a different class
    208                         hwnd = FindWindow("Default Screen Saver", NULL);
    209                 }
    210                 if (hwnd != NULL) {
    211                         PostMessage(hwnd, WM_CLOSE, 0, 0);
    212                 }
    213         }
    214 
    215         // force timer to restart
    216         SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
    217         SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
    218                                                                 !m_wasEnabled, 0, SPIF_SENDWININICHANGE);
    219         SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
    220                                                                  m_wasEnabled, 0, SPIF_SENDWININICHANGE);
    221 
    222         // disable display power down
    223         CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
    224 }
    225 
    226 bool
    227 CMSWindowsScreenSaver::isActive() const
    228 {
    229         if (m_is95) {
    230                 return (FindWindow("WindowsScreenSaverClass", NULL) != NULL);
    231         }
    232         else if (m_isNT) {
    233                 // screen saver runs on a separate desktop
    234                 HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, MAXIMUM_ALLOWED);
    235                 if (desktop == NULL && GetLastError() != ERROR_ACCESS_DENIED) {
    236                         // desktop doesn't exist so screen saver is not running
    237                         return false;
    238                 }
    239 
    240                 // desktop exists.  this should indicate that the screen saver
    241                 // is running but an OS bug can cause a valid handle to be
    242                 // returned even if the screen saver isn't running (Q230117).
    243                 // we'll try to enumerate the windows on the desktop and, if
    244                 // there are any, we assume the screen saver is running.  (note
    245                 // that if we don't have permission to enumerate then we'll
    246                 // assume that the screen saver is not running.)  that'd be
    247                 // easy enough except there's another OS bug (Q198590) that can
    248                 // cause EnumDesktopWindows() to enumerate the windows of
    249                 // another desktop if the requested desktop has no windows.  to
    250                 // work around that we have to verify that the enumerated
    251                 // windows are, in fact, on the expected desktop.
    252                 CFindScreenSaverInfo info;
    253                 info.m_desktop = desktop;
    254                 info.m_window  = NULL;
    255                 EnumDesktopWindows(desktop,
    256                                                                 &CMSWindowsScreenSaver::findScreenSaverFunc,
    257                                                                 reinterpret_cast<LPARAM>(&info));
    258 
    259                 // done with desktop
    260                 CloseDesktop(desktop);
    261 
    262                 // screen saver is running if a window was found
    263                 return (info.m_window != NULL);
    264         }
    265         else {
    266                 BOOL running;
    267                 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
    268                 return (running != FALSE);
    269         }
    270 }
    271 
    272 BOOL CALLBACK
    273 CMSWindowsScreenSaver::findScreenSaverFunc(HWND hwnd, LPARAM arg)
    274 {
    275         CFindScreenSaverInfo* info = reinterpret_cast<CFindScreenSaverInfo*>(arg);
    276 
    277         if (info->m_desktop != NULL) {
    278                 DWORD threadID = GetWindowThreadProcessId(hwnd, NULL);
    279                 HDESK desktop  = GetThreadDesktop(threadID);
    280                 if (desktop != NULL && desktop != info->m_desktop) {
    281                         // stop enumerating -- wrong desktop
    282                         return FALSE;
    283                 }
    284         }
    285 
    286         // found a window
    287         info->m_window = hwnd;
    288 
    289         // don't need to enumerate further
    290         return FALSE;
    291 }
    292 
    293 BOOL CALLBACK
    294 CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)
    295 {
    296         if (IsWindowVisible(hwnd)) {
    297                 HINSTANCE instance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
    298                 if (instance != CMSWindowsScreen::getInstance()) {
    299                         PostMessage(hwnd, WM_CLOSE, 0, 0);
    300                         *reinterpret_cast<bool*>(arg) = true;
    301                 }
    302         }
    303         return TRUE;
    304 }
    305 
    306 DWORD
    307 CMSWindowsScreenSaver::findScreenSaver()
    308 {
    309         // try windows 95 way
    310         HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
    311 
    312         // get process ID of process that owns the window, if found
    313         if (hwnd != NULL) {
    314                 DWORD processID;
    315                 GetWindowThreadProcessId(hwnd, &processID);
    316                 return processID;
    317         }
    318 
    319         // not found
    320         return 0;
    321 }
    322 
    323 void
    324 CMSWindowsScreenSaver::watchDesktop()
    325 {
    326         // stop watching previous process/desktop
    327         unwatchProcess();
    328 
    329         // watch desktop in another thread
    330         LOG((CLOG_DEBUG "watching screen saver desktop"));
    331         m_active = true;
    332         m_watch  = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
    333                                                                 &CMSWindowsScreenSaver::watchDesktopThread));
    334 }
    335 
    336 void
    337 CMSWindowsScreenSaver::watchProcess(HANDLE process)
    338 {
    339         // stop watching previous process/desktop
    340         unwatchProcess();
    341 
    342         // watch new process in another thread
    343         if (process != NULL) {
    344                 LOG((CLOG_DEBUG "watching screen saver process"));
    345                 m_process = process;
    346                 m_active  = true;
    347                 m_watch   = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
    348                                                                 &CMSWindowsScreenSaver::watchProcessThread));
    349         }
    350 }
    351 
    352 void
    353 CMSWindowsScreenSaver::unwatchProcess()
    354 {
    355         if (m_watch != NULL) {
    356                 LOG((CLOG_DEBUG "stopped watching screen saver process/desktop"));
    357                 m_watch->cancel();
    358                 m_watch->wait();
    359                 delete m_watch;
    360                 m_watch  = NULL;
    361                 m_active = false;
    362         }
    363         if (m_process != NULL) {
    364                 CloseHandle(m_process);
    365                 m_process = NULL;
    366         }
    367 }
    368 
    369 void
    370 CMSWindowsScreenSaver::watchDesktopThread(void*)
    371 {
    372         DWORD reserved = 0;
    373         TCHAR* name    = NULL;
    374 
    375         for (;;) {
    376                 // wait a bit
    377                 ARCH->sleep(0.2);
    378 
    379                 if (m_isNT) {
    380                         // get current desktop
    381                         HDESK desk = OpenInputDesktop(0, FALSE, GENERIC_READ);
    382                         if (desk == NULL) {
    383                                 // can't open desktop so keep waiting
    384                                 continue;
    385                         }
    386 
    387                         // get current desktop name length
    388                         DWORD size;
    389                         GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
    390 
    391                         // allocate more space for the name, if necessary
    392                         if (size > reserved) {
    393                                 reserved = size;
    394                                 name     = (TCHAR*)alloca(reserved + sizeof(TCHAR));
    395                         }
    396 
    397                         // get current desktop name
    398                         GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
    399                         CloseDesktop(desk);
    400 
    401                         // compare name to screen saver desktop name
    402                         if (_tcsicmp(name, TEXT("Screen-saver")) == 0) {
    403                                 // still the screen saver desktop so keep waiting
    404                                 continue;
    405                         }
    406                 }
    407                 else {
    408                         // 2000/XP have a sane way to detect a runnin screensaver.
    409                         BOOL running;
    410                         SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
    411                         if (running) {
    412                                 continue;
    413                         }
    414                 }
    415 
    416                 // send screen saver deactivation message
    417                 m_active = false;
    418                 PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
    419                 return;
    420         }
    421 }
    422 
    423 void
    424 CMSWindowsScreenSaver::watchProcessThread(void*)
    425 {
    426         for (;;) {
    427                 CThread::testCancel();
    428                 if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) {
    429                         // process terminated
    430                         LOG((CLOG_DEBUG "screen saver died"));
    431 
    432                         // send screen saver deactivation message
    433                         m_active = false;
    434                         PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
    435                         return;
    436                 }
    437         }
    438 }
    439 
    440 void
    441 CMSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt)
    442 {
    443         HKEY hkey =
    444                 CArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
    445         if (hkey == NULL) {
    446                 return;
    447         }
    448 
    449         const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;
    450         if (saveSecureAsInt) {
    451                 CArchMiscWindows::setValue(hkey, isSecure, secure ? 1 : 0);
    452         }
    453         else {
    454                 CArchMiscWindows::setValue(hkey, isSecure, secure ? "1" : "0");
    455         }
    456 
    457         CArchMiscWindows::closeKey(hkey);
    458 }
    459 
    460 bool
    461 CMSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const
    462 {
    463         // get the password protection setting key
    464         HKEY hkey =
    465                 CArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
    466         if (hkey == NULL) {
    467                 return false;
    468         }
    469 
    470         // get the value.  the value may be an int or a string, depending
    471         // on the version of windows.
    472         bool result;
    473         const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;
    474         switch (CArchMiscWindows::typeOfValue(hkey, isSecure)) {
    475         default:
    476                 result = false;
    477                 break;
    478 
    479         case CArchMiscWindows::kUINT: {
    480                 DWORD value =
    481                         CArchMiscWindows::readValueInt(hkey, isSecure);
    482                 *wasSecureFlagAnInt = true;
    483                 result = (value != 0);
    484                 break;
    485         }
    486 
    487         case CArchMiscWindows::kSTRING: {
    488                 std::string value =
    489                         CArchMiscWindows::readValueString(hkey, isSecure);
    490                 *wasSecureFlagAnInt = false;
    491                 result = (value != "0");
    492                 break;
    493         }
    494         }
    495 
    496         CArchMiscWindows::closeKey(hkey);
    497         return result;
    498 }
Note: See TracChangeset for help on using the changeset viewer.