You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
423 lines
12 KiB
423 lines
12 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Scheduling Agent Service
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: events.cxx
|
|
//
|
|
// Contents: Idle and battery event code.
|
|
//
|
|
// History: 22-Mar-96 EricB created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "..\pch\headers.hxx"
|
|
#pragma hdrstop
|
|
#include "globals.hxx"
|
|
#include "svc_core.hxx"
|
|
extern "C"
|
|
{
|
|
#include "msidle.h"
|
|
}
|
|
|
|
#define SCH_NOIDLE_VALUE TEXT("NoIdle")
|
|
|
|
BOOL g_fOnBattery;
|
|
BOOL g_fIdleInitialized;
|
|
HINSTANCE g_hMsidleDll = NULL;
|
|
|
|
//
|
|
// msidle.dll function pointers.
|
|
//
|
|
_BEGINIDLEDETECTION gpfnBeginIdleDetection;
|
|
_ENDIDLEDETECTION gpfnEndIdleDetection;
|
|
_SETIDLETIMEOUT gpfnSetIdleTimeout;
|
|
_SETIDLENOTIFY gpfnSetIdleNotify;
|
|
_SETBUSYNOTIFY gpfnSetBusyNotify;
|
|
_GETIDLEMINUTES gpfnGetIdleMinutes;
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: OnIdleNotification
|
|
//
|
|
// Synopsis: Called when the winproc receives idle notifications.
|
|
//
|
|
// Arguments: [wParam] - indicates whether it is for idle start or end.
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void WINAPI
|
|
OnIdleNotify(DWORD dwState)
|
|
{
|
|
switch (dwState)
|
|
{
|
|
case STATE_USER_IDLE_BEGIN:
|
|
//
|
|
// Received idle notification.
|
|
//
|
|
if (g_pSched != NULL)
|
|
{
|
|
schDebugOut((DEB_ITRACE,
|
|
"*** OnIdleNotification: entering idle state. ***\n"));
|
|
g_pSched->OnIdleEvent(TRUE);
|
|
}
|
|
break;
|
|
|
|
case STATE_USER_IDLE_END:
|
|
//
|
|
// Idle has ended.
|
|
//
|
|
if (g_pSched != NULL)
|
|
{
|
|
schDebugOut((DEB_ITRACE,
|
|
"*** OnIdleNotification: idle lost. ***\n"));
|
|
g_pSched->OnIdleEvent(FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
schAssert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetNextIdleNotificationFn
|
|
//
|
|
// Synopsis: Set the length of time to wait for the next idle notification.
|
|
//
|
|
// Returns: TRUE for success, and FALSE if unable to make the call.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
SetNextIdleNotificationFn(WORD wIdleWait)
|
|
{
|
|
schDebugOut((DEB_ITRACE, "SetNextIdleNotification(%u)\n", wIdleWait));
|
|
|
|
if (!g_fIdleInitialized)
|
|
{
|
|
DBG_OUT("Calling SetNextIdleNotification before idle init!");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 0xffff is a flag value meaning that no idle notification is needed.
|
|
//
|
|
if (wIdleWait == 0xffff)
|
|
{
|
|
schDebugOut((DEB_IDLE, "Next idle wait is 0xffff, not requesting"
|
|
" idle notification\n"));
|
|
//
|
|
// msidle.dll makes it impossible to turn off idle notification
|
|
// completely. SetIdleNotify(FALSE, 0) will do it temporarily,
|
|
// but if we have also registered for a loss-of-idle notification,
|
|
// then as soon as we get that notification, msidle.dll turns idle
|
|
// notification back on automatically.
|
|
// So we also set a long idle wait period.
|
|
// (It doesn't have to be 0xffff, but it might as well be)
|
|
//
|
|
gpfnSetIdleTimeout(0xffff, 0);
|
|
gpfnSetIdleNotify(FALSE, 0);
|
|
return FALSE;
|
|
}
|
|
|
|
schAssert(wIdleWait != 0);
|
|
schDebugOut((DEB_IDLE, "Requesting %u-minute idle notification\n",
|
|
wIdleWait));
|
|
|
|
gpfnSetIdleTimeout(wIdleWait, 0);
|
|
gpfnSetIdleNotify(TRUE, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetIdleLossNotificationFn
|
|
//
|
|
// Synopsis: Registers for idle loss notification.
|
|
//
|
|
// Returns: TRUE for success, and FALSE if unable to make the call.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
SetIdleLossNotificationFn()
|
|
{
|
|
schDebugOut((DEB_ITRACE, "SetIdleLossNotification()\n"));
|
|
|
|
if (!g_fIdleInitialized)
|
|
{
|
|
DBG_OUT("Calling SetIdleLossNotification before idle init!");
|
|
return FALSE;
|
|
}
|
|
|
|
schDebugOut((DEB_IDLE, "Requesting idle LOSS notification\n"));
|
|
gpfnSetBusyNotify(TRUE, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetTimeIdle
|
|
//
|
|
// Synopsis: Obtains the length of time the machine has been idle.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
GetTimeIdle(void)
|
|
{
|
|
DWORD dwMinutes;
|
|
|
|
if (!g_fIdleInitialized)
|
|
{
|
|
DBG_OUT("Calling GetTimeIdle before idle init!");
|
|
dwMinutes = 0;
|
|
}
|
|
else
|
|
{
|
|
dwMinutes = gpfnGetIdleMinutes(0);
|
|
}
|
|
|
|
schDebugOut((DEB_IDLE, "User has been idle for %u minutes\n", dwMinutes));
|
|
|
|
return dwMinutes;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: OnPowerChange
|
|
//
|
|
// Synopsis: Called when the machine's battery state changes.
|
|
//
|
|
// Arguments: [fGoingOnBattery] - set to true if going on battery power,
|
|
// false if going back on line power.
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
OnPowerChange(BOOL fGoingOnBattery)
|
|
{
|
|
schDebugOut((DEB_ITRACE, "OnPowerChange: fGoingOnBattery = %s\n",
|
|
(fGoingOnBattery) ? "TRUE" : "FALSE"));
|
|
|
|
//
|
|
// Check to see if our battery state has changed, or if this is just
|
|
// a battery update
|
|
//
|
|
if (g_fOnBattery != fGoingOnBattery)
|
|
{
|
|
g_fOnBattery = fGoingOnBattery;
|
|
|
|
//
|
|
// Signal the main thread to recalculate the next wakeup time, since
|
|
// the calculation depends on whether the machine is on batteries.
|
|
// Do this by simply signaling the wakeup timer. This will cause a
|
|
// recalc.
|
|
//
|
|
g_pSched->SignalWakeupTimer();
|
|
|
|
if (fGoingOnBattery)
|
|
{
|
|
//
|
|
// Notify the job processor to kill any jobs with the
|
|
// TASK_FLAG_KILL_IF_GOING_ON_BATTERIES flag set.
|
|
//
|
|
CJobProcessor * pjp;
|
|
for (pjp = gpJobProcessorMgr->GetFirstProcessor(); pjp != NULL; )
|
|
{
|
|
pjp->KillIfFlagSet(TASK_FLAG_KILL_IF_GOING_ON_BATTERIES);
|
|
CJobProcessor * pjpNext = pjp->Next();
|
|
pjp->Release();
|
|
pjp = pjpNext;
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: InitBatteryNotification
|
|
//
|
|
// Synopsis: Initialize the battery event boolean.
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
// Notes: Currently only Win95 supports power management.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
InitBatteryNotification(void)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
//
|
|
// Check current battery state and set bool accordingly.
|
|
//
|
|
SYSTEM_POWER_STATUS PwrStatus;
|
|
|
|
if (!GetSystemPowerStatus(&PwrStatus))
|
|
{
|
|
dwErr = GetLastError();
|
|
|
|
if (dwErr == ERROR_FILE_NOT_FOUND ||
|
|
dwErr == ERROR_CALL_NOT_IMPLEMENTED)
|
|
{
|
|
g_fOnBattery = FALSE;
|
|
schDebugOut((DEB_ITRACE,
|
|
"InitBatteryNotification: GetSystemPowerStatus"
|
|
" returned %u, g_fOnBattery set to FALSE\n",
|
|
dwErr));
|
|
return S_OK;
|
|
}
|
|
ERR_OUT("GetSystemPowerStatus", HRESULT_FROM_WIN32(dwErr));
|
|
return HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
g_fOnBattery = (PwrStatus.ACLineStatus == 0) ? TRUE : FALSE;
|
|
|
|
schDebugOut((DEB_ITRACE, "InitBatteryNotification: g_fOnBattery = %s\n",
|
|
(g_fOnBattery) ? "TRUE" : "FALSE"));
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: InitIdleDetection
|
|
//
|
|
// Synopsis: Called after the message window is created to initialize idle
|
|
// detection and hot corners.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
InitIdleDetection()
|
|
{
|
|
TRACE_FUNCTION(InitIdleDetection);
|
|
DWORD dwErr;
|
|
|
|
//
|
|
// Look in the registry to see if idle detection is disabled.
|
|
//
|
|
long lErr;
|
|
HKEY hSchedKey = NULL;
|
|
lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ,
|
|
&hSchedKey);
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
TCHAR tszInit[SCH_MED0BUF_LEN + 1];
|
|
DWORD cb = SCH_MED0BUF_LEN * sizeof(TCHAR);
|
|
|
|
lErr = RegQueryValueEx(hSchedKey, SCH_NOIDLE_VALUE, NULL, NULL,
|
|
(LPBYTE)tszInit, &cb);
|
|
|
|
RegCloseKey(hSchedKey);
|
|
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// The presence of the value is sufficient to disable idle
|
|
// detection. g_fIdleInitialized will remain FALSE, resulting
|
|
// in all idle operations being skipped.
|
|
//
|
|
schDebugOut((DEB_ITRACE, "Idle detection is disabled!!!!!!!!\n"));
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// load msidle.dll
|
|
if (g_hMsidleDll == NULL) {
|
|
|
|
g_hMsidleDll = LoadLibrary(TEXT("MSIDLE.DLL"));
|
|
|
|
if (g_hMsidleDll == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
ERR_OUT("Load of msidle.dll", dwErr);
|
|
return HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
}
|
|
|
|
// get entry points
|
|
gpfnBeginIdleDetection = (_BEGINIDLEDETECTION)
|
|
GetProcAddress(g_hMsidleDll, (LPSTR)3);
|
|
gpfnEndIdleDetection = (_ENDIDLEDETECTION)
|
|
GetProcAddress(g_hMsidleDll, (LPSTR)4);
|
|
gpfnSetIdleTimeout = (_SETIDLETIMEOUT)
|
|
GetProcAddress(g_hMsidleDll, (LPSTR)5);
|
|
gpfnSetIdleNotify = (_SETIDLENOTIFY)
|
|
GetProcAddress(g_hMsidleDll, (LPSTR)6);
|
|
gpfnSetBusyNotify = (_SETBUSYNOTIFY)
|
|
GetProcAddress(g_hMsidleDll, (LPSTR)7);
|
|
gpfnGetIdleMinutes = (_GETIDLEMINUTES)
|
|
GetProcAddress(g_hMsidleDll, (LPSTR)8);
|
|
|
|
if (gpfnBeginIdleDetection == NULL ||
|
|
gpfnEndIdleDetection == NULL ||
|
|
gpfnSetIdleTimeout == NULL ||
|
|
gpfnSetIdleNotify == NULL ||
|
|
gpfnSetBusyNotify == NULL ||
|
|
gpfnGetIdleMinutes == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
ERR_OUT("Getting msidle.dll entry point addresses", dwErr);
|
|
goto ErrExit;
|
|
}
|
|
|
|
// call start monitoring
|
|
dwErr = gpfnBeginIdleDetection(OnIdleNotify, SCH_DEFAULT_IDLE_TIME, 0);
|
|
if (dwErr)
|
|
{
|
|
ERR_OUT("Making initial idle call", dwErr);
|
|
goto ErrExit;
|
|
}
|
|
|
|
g_fIdleInitialized = TRUE;
|
|
|
|
return S_OK;
|
|
|
|
ErrExit:
|
|
|
|
FreeLibrary(g_hMsidleDll);
|
|
g_hMsidleDll = NULL;
|
|
gpfnBeginIdleDetection = NULL;
|
|
gpfnEndIdleDetection = NULL;
|
|
gpfnSetIdleTimeout = NULL;
|
|
gpfnSetIdleNotify = NULL;
|
|
gpfnSetBusyNotify = NULL;
|
|
gpfnGetIdleMinutes = NULL;
|
|
|
|
return HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: EndIdleDetection
|
|
//
|
|
// Synopsis: Stop idle detection.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
EndIdleDetection()
|
|
{
|
|
if (gpfnEndIdleDetection != NULL)
|
|
{
|
|
gpfnEndIdleDetection(0);
|
|
}
|
|
}
|