Fixed detection of screen saver shutdown on windows nt.

This commit is contained in:
crs 2003-03-16 17:40:57 +00:00
parent 74e50877e9
commit 9f984ad1a0
2 changed files with 99 additions and 45 deletions

View File

@ -16,6 +16,9 @@
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CArch.h"
#include <malloc.h>
#include <tchar.h>
#if !defined(SPI_GETSCREENSAVERRUNNING) #if !defined(SPI_GETSCREENSAVERRUNNING)
#define SPI_GETSCREENSAVERRUNNING 114 #define SPI_GETSCREENSAVERRUNNING 114
@ -70,29 +73,35 @@ CMSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
// the system is idle or the user deliberately started // the system is idle or the user deliberately started
// the screen saver. // the screen saver.
Sleep(250); Sleep(250);
HWND hwnd = findScreenSaver();
if (hwnd == NULL) {
// didn't start
LOG((CLOG_DEBUG "can't find screen saver window"));
return false;
}
// get the process // set parameters common to all screen saver handling
DWORD processID;
GetWindowThreadProcessId(hwnd, &processID);
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID);
if (process == NULL) {
// didn't start
LOG((CLOG_DEBUG "can't open screen saver process"));
return false;
}
// watch for the process to exit
m_threadID = GetCurrentThreadId(); m_threadID = GetCurrentThreadId();
m_msg = msg; m_msg = msg;
m_wParam = wParam; m_wParam = wParam;
m_lParam = lParam; m_lParam = lParam;
watchProcess(process);
// we handle the screen saver differently for the windows
// 95 and nt families.
if (m_is95Family) {
// on windows 95 we wait for the screen saver process
// to terminate. get the process.
DWORD processID = findScreenSaver();
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID);
if (process == NULL) {
// didn't start
LOG((CLOG_DEBUG "can't open screen saver process"));
return false;
}
// watch for the process to exit
watchProcess(process);
}
else {
// on the windows nt family we wait for the desktop to
// change until it's neither the Screen-Saver desktop
// nor a desktop we can't open (the login desktop).
watchDesktop();
}
return true; return true;
} }
@ -240,39 +249,39 @@ CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)
return TRUE; return TRUE;
} }
HWND DWORD
CMSWindowsScreenSaver::findScreenSaver() CMSWindowsScreenSaver::findScreenSaver()
{ {
if (!m_is95Family) { // try windows 95 way
// screen saver runs on a separate desktop HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, MAXIMUM_ALLOWED);
if (desktop != NULL) {
// search
CFindScreenSaverInfo info;
info.m_desktop = desktop;
info.m_window = NULL;
EnumDesktopWindows(desktop,
&CMSWindowsScreenSaver::findScreenSaverFunc,
reinterpret_cast<LPARAM>(&info));
// done with desktop // get process ID of process that owns the window, if found
CloseDesktop(desktop); if (hwnd != NULL) {
DWORD processID;
// return window if found GetWindowThreadProcessId(hwnd, &processID);
if (info.m_window != NULL) { return processID;
return info.m_window;
}
}
} }
// try windows 95 way // not found
return FindWindow("WindowsScreenSaverClass", NULL); return 0;
}
void
CMSWindowsScreenSaver::watchDesktop()
{
// stop watching previous process/desktop
unwatchProcess();
// watch desktop in another thread
LOG((CLOG_DEBUG "watching screen saver desktop"));
m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
&CMSWindowsScreenSaver::watchDesktopThread));
} }
void void
CMSWindowsScreenSaver::watchProcess(HANDLE process) CMSWindowsScreenSaver::watchProcess(HANDLE process)
{ {
// stop watching previous process // stop watching previous process/desktop
unwatchProcess(); unwatchProcess();
// watch new process in another thread // watch new process in another thread
@ -288,7 +297,7 @@ void
CMSWindowsScreenSaver::unwatchProcess() CMSWindowsScreenSaver::unwatchProcess()
{ {
if (m_watch != NULL) { if (m_watch != NULL) {
LOG((CLOG_DEBUG "stopped watching screen saver process")); LOG((CLOG_DEBUG "stopped watching screen saver process/desktop"));
m_watch->cancel(); m_watch->cancel();
m_watch->wait(); m_watch->wait();
delete m_watch; delete m_watch;
@ -300,15 +309,58 @@ CMSWindowsScreenSaver::unwatchProcess()
} }
} }
void
CMSWindowsScreenSaver::watchDesktopThread(void*)
{
DWORD reserved = 0;
TCHAR* name = NULL;
for (;;) {
// wait a bit
ARCH->sleep(0.2);
// get current desktop
HDESK desk = OpenInputDesktop(0, FALSE, GENERIC_READ);
if (desk == NULL) {
// can't open desktop so keep waiting
continue;
}
// get current desktop name length
DWORD size;
GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
// allocate more space for the name, if necessary
if (size > reserved) {
reserved = size;
name = (TCHAR*)alloca(reserved + sizeof(TCHAR));
}
// get current desktop name
GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
// compare name to screen saver desktop name
if (_tcsicmp(name, TEXT("Screen-saver")) == 0) {
// still the screen saver desktop so keep waiting
continue;
}
// send screen saver deactivation message
PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
return;
}
}
void void
CMSWindowsScreenSaver::watchProcessThread(void*) CMSWindowsScreenSaver::watchProcessThread(void*)
{ {
for (;;) { for (;;) {
CThread::testCancel(); CThread::testCancel();
if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) { if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) {
// process terminated. send screen saver deactivation // process terminated
// message.
LOG((CLOG_DEBUG "screen saver died")); LOG((CLOG_DEBUG "screen saver died"));
// send screen saver deactivation message
PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
return; return;
} }

View File

@ -58,9 +58,11 @@ private:
static BOOL CALLBACK findScreenSaverFunc(HWND hwnd, LPARAM lParam); static BOOL CALLBACK findScreenSaverFunc(HWND hwnd, LPARAM lParam);
static BOOL CALLBACK killScreenSaverFunc(HWND hwnd, LPARAM lParam); static BOOL CALLBACK killScreenSaverFunc(HWND hwnd, LPARAM lParam);
HWND findScreenSaver(); DWORD findScreenSaver();
void watchDesktop();
void watchProcess(HANDLE process); void watchProcess(HANDLE process);
void unwatchProcess(); void unwatchProcess();
void watchDesktopThread(void*);
void watchProcessThread(void*); void watchProcessThread(void*);
private: private: