Leaked source code of windows server 2003
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

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Scheduling Agent Service
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  7. //
  8. // File: events.cxx
  9. //
  10. // Contents: Idle and battery event code.
  11. //
  12. // History: 22-Mar-96 EricB created
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include "..\pch\headers.hxx"
  16. #pragma hdrstop
  17. #include "globals.hxx"
  18. #include "svc_core.hxx"
  19. extern "C"
  20. {
  21. #include "msidle.h"
  22. }
  23. #define SCH_NOIDLE_VALUE TEXT("NoIdle")
  24. BOOL g_fOnBattery;
  25. BOOL g_fIdleInitialized;
  26. HINSTANCE g_hMsidleDll = NULL;
  27. //
  28. // msidle.dll function pointers.
  29. //
  30. _BEGINIDLEDETECTION gpfnBeginIdleDetection;
  31. _ENDIDLEDETECTION gpfnEndIdleDetection;
  32. _SETIDLETIMEOUT gpfnSetIdleTimeout;
  33. _SETIDLENOTIFY gpfnSetIdleNotify;
  34. _SETBUSYNOTIFY gpfnSetBusyNotify;
  35. _GETIDLEMINUTES gpfnGetIdleMinutes;
  36. //+----------------------------------------------------------------------------
  37. //
  38. // Function: OnIdleNotification
  39. //
  40. // Synopsis: Called when the winproc receives idle notifications.
  41. //
  42. // Arguments: [wParam] - indicates whether it is for idle start or end.
  43. //
  44. // Returns: hresults
  45. //
  46. //-----------------------------------------------------------------------------
  47. void WINAPI
  48. OnIdleNotify(DWORD dwState)
  49. {
  50. switch (dwState)
  51. {
  52. case STATE_USER_IDLE_BEGIN:
  53. //
  54. // Received idle notification.
  55. //
  56. if (g_pSched != NULL)
  57. {
  58. schDebugOut((DEB_ITRACE,
  59. "*** OnIdleNotification: entering idle state. ***\n"));
  60. g_pSched->OnIdleEvent(TRUE);
  61. }
  62. break;
  63. case STATE_USER_IDLE_END:
  64. //
  65. // Idle has ended.
  66. //
  67. if (g_pSched != NULL)
  68. {
  69. schDebugOut((DEB_ITRACE,
  70. "*** OnIdleNotification: idle lost. ***\n"));
  71. g_pSched->OnIdleEvent(FALSE);
  72. }
  73. break;
  74. default:
  75. schAssert(0);
  76. break;
  77. }
  78. }
  79. //+----------------------------------------------------------------------------
  80. //
  81. // Function: SetNextIdleNotificationFn
  82. //
  83. // Synopsis: Set the length of time to wait for the next idle notification.
  84. //
  85. // Returns: TRUE for success, and FALSE if unable to make the call.
  86. //
  87. //-----------------------------------------------------------------------------
  88. BOOL
  89. SetNextIdleNotificationFn(WORD wIdleWait)
  90. {
  91. schDebugOut((DEB_ITRACE, "SetNextIdleNotification(%u)\n", wIdleWait));
  92. if (!g_fIdleInitialized)
  93. {
  94. DBG_OUT("Calling SetNextIdleNotification before idle init!");
  95. return FALSE;
  96. }
  97. //
  98. // 0xffff is a flag value meaning that no idle notification is needed.
  99. //
  100. if (wIdleWait == 0xffff)
  101. {
  102. schDebugOut((DEB_IDLE, "Next idle wait is 0xffff, not requesting"
  103. " idle notification\n"));
  104. //
  105. // msidle.dll makes it impossible to turn off idle notification
  106. // completely. SetIdleNotify(FALSE, 0) will do it temporarily,
  107. // but if we have also registered for a loss-of-idle notification,
  108. // then as soon as we get that notification, msidle.dll turns idle
  109. // notification back on automatically.
  110. // So we also set a long idle wait period.
  111. // (It doesn't have to be 0xffff, but it might as well be)
  112. //
  113. gpfnSetIdleTimeout(0xffff, 0);
  114. gpfnSetIdleNotify(FALSE, 0);
  115. return FALSE;
  116. }
  117. schAssert(wIdleWait != 0);
  118. schDebugOut((DEB_IDLE, "Requesting %u-minute idle notification\n",
  119. wIdleWait));
  120. gpfnSetIdleTimeout(wIdleWait, 0);
  121. gpfnSetIdleNotify(TRUE, 0);
  122. return TRUE;
  123. }
  124. //+----------------------------------------------------------------------------
  125. //
  126. // Function: SetIdleLossNotificationFn
  127. //
  128. // Synopsis: Registers for idle loss notification.
  129. //
  130. // Returns: TRUE for success, and FALSE if unable to make the call.
  131. //
  132. //-----------------------------------------------------------------------------
  133. BOOL
  134. SetIdleLossNotificationFn()
  135. {
  136. schDebugOut((DEB_ITRACE, "SetIdleLossNotification()\n"));
  137. if (!g_fIdleInitialized)
  138. {
  139. DBG_OUT("Calling SetIdleLossNotification before idle init!");
  140. return FALSE;
  141. }
  142. schDebugOut((DEB_IDLE, "Requesting idle LOSS notification\n"));
  143. gpfnSetBusyNotify(TRUE, 0);
  144. return TRUE;
  145. }
  146. //+----------------------------------------------------------------------------
  147. //
  148. // Function: GetTimeIdle
  149. //
  150. // Synopsis: Obtains the length of time the machine has been idle.
  151. //
  152. //-----------------------------------------------------------------------------
  153. DWORD
  154. GetTimeIdle(void)
  155. {
  156. DWORD dwMinutes;
  157. if (!g_fIdleInitialized)
  158. {
  159. DBG_OUT("Calling GetTimeIdle before idle init!");
  160. dwMinutes = 0;
  161. }
  162. else
  163. {
  164. dwMinutes = gpfnGetIdleMinutes(0);
  165. }
  166. schDebugOut((DEB_IDLE, "User has been idle for %u minutes\n", dwMinutes));
  167. return dwMinutes;
  168. }
  169. //+----------------------------------------------------------------------------
  170. //
  171. // Function: OnPowerChange
  172. //
  173. // Synopsis: Called when the machine's battery state changes.
  174. //
  175. // Arguments: [fGoingOnBattery] - set to true if going on battery power,
  176. // false if going back on line power.
  177. //
  178. // Returns: hresults
  179. //
  180. //-----------------------------------------------------------------------------
  181. HRESULT
  182. OnPowerChange(BOOL fGoingOnBattery)
  183. {
  184. schDebugOut((DEB_ITRACE, "OnPowerChange: fGoingOnBattery = %s\n",
  185. (fGoingOnBattery) ? "TRUE" : "FALSE"));
  186. //
  187. // Check to see if our battery state has changed, or if this is just
  188. // a battery update
  189. //
  190. if (g_fOnBattery != fGoingOnBattery)
  191. {
  192. g_fOnBattery = fGoingOnBattery;
  193. //
  194. // Signal the main thread to recalculate the next wakeup time, since
  195. // the calculation depends on whether the machine is on batteries.
  196. // Do this by simply signaling the wakeup timer. This will cause a
  197. // recalc.
  198. //
  199. g_pSched->SignalWakeupTimer();
  200. if (fGoingOnBattery)
  201. {
  202. //
  203. // Notify the job processor to kill any jobs with the
  204. // TASK_FLAG_KILL_IF_GOING_ON_BATTERIES flag set.
  205. //
  206. CJobProcessor * pjp;
  207. for (pjp = gpJobProcessorMgr->GetFirstProcessor(); pjp != NULL; )
  208. {
  209. pjp->KillIfFlagSet(TASK_FLAG_KILL_IF_GOING_ON_BATTERIES);
  210. CJobProcessor * pjpNext = pjp->Next();
  211. pjp->Release();
  212. pjp = pjpNext;
  213. }
  214. }
  215. }
  216. return S_OK;
  217. }
  218. //+----------------------------------------------------------------------------
  219. //
  220. // Function: InitBatteryNotification
  221. //
  222. // Synopsis: Initialize the battery event boolean.
  223. //
  224. // Returns: hresults
  225. //
  226. // Notes: Currently only Win95 supports power management.
  227. //
  228. //-----------------------------------------------------------------------------
  229. HRESULT
  230. InitBatteryNotification(void)
  231. {
  232. DWORD dwErr;
  233. //
  234. // Check current battery state and set bool accordingly.
  235. //
  236. SYSTEM_POWER_STATUS PwrStatus;
  237. if (!GetSystemPowerStatus(&PwrStatus))
  238. {
  239. dwErr = GetLastError();
  240. if (dwErr == ERROR_FILE_NOT_FOUND ||
  241. dwErr == ERROR_CALL_NOT_IMPLEMENTED)
  242. {
  243. g_fOnBattery = FALSE;
  244. schDebugOut((DEB_ITRACE,
  245. "InitBatteryNotification: GetSystemPowerStatus"
  246. " returned %u, g_fOnBattery set to FALSE\n",
  247. dwErr));
  248. return S_OK;
  249. }
  250. ERR_OUT("GetSystemPowerStatus", HRESULT_FROM_WIN32(dwErr));
  251. return HRESULT_FROM_WIN32(dwErr);
  252. }
  253. g_fOnBattery = (PwrStatus.ACLineStatus == 0) ? TRUE : FALSE;
  254. schDebugOut((DEB_ITRACE, "InitBatteryNotification: g_fOnBattery = %s\n",
  255. (g_fOnBattery) ? "TRUE" : "FALSE"));
  256. return S_OK;
  257. }
  258. //+----------------------------------------------------------------------------
  259. //
  260. // Function: InitIdleDetection
  261. //
  262. // Synopsis: Called after the message window is created to initialize idle
  263. // detection and hot corners.
  264. //
  265. // Arguments:
  266. //
  267. // Returns: hresults
  268. //
  269. //-----------------------------------------------------------------------------
  270. HRESULT
  271. InitIdleDetection()
  272. {
  273. TRACE_FUNCTION(InitIdleDetection);
  274. DWORD dwErr;
  275. //
  276. // Look in the registry to see if idle detection is disabled.
  277. //
  278. long lErr;
  279. HKEY hSchedKey = NULL;
  280. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ,
  281. &hSchedKey);
  282. if (lErr == ERROR_SUCCESS)
  283. {
  284. TCHAR tszInit[SCH_MED0BUF_LEN + 1];
  285. DWORD cb = SCH_MED0BUF_LEN * sizeof(TCHAR);
  286. lErr = RegQueryValueEx(hSchedKey, SCH_NOIDLE_VALUE, NULL, NULL,
  287. (LPBYTE)tszInit, &cb);
  288. RegCloseKey(hSchedKey);
  289. if (lErr == ERROR_SUCCESS)
  290. {
  291. //
  292. // The presence of the value is sufficient to disable idle
  293. // detection. g_fIdleInitialized will remain FALSE, resulting
  294. // in all idle operations being skipped.
  295. //
  296. schDebugOut((DEB_ITRACE, "Idle detection is disabled!!!!!!!!\n"));
  297. return S_OK;
  298. }
  299. }
  300. // load msidle.dll
  301. if (g_hMsidleDll == NULL) {
  302. g_hMsidleDll = LoadLibrary(TEXT("MSIDLE.DLL"));
  303. if (g_hMsidleDll == NULL)
  304. {
  305. dwErr = GetLastError();
  306. ERR_OUT("Load of msidle.dll", dwErr);
  307. return HRESULT_FROM_WIN32(dwErr);
  308. }
  309. }
  310. // get entry points
  311. gpfnBeginIdleDetection = (_BEGINIDLEDETECTION)
  312. GetProcAddress(g_hMsidleDll, (LPSTR)3);
  313. gpfnEndIdleDetection = (_ENDIDLEDETECTION)
  314. GetProcAddress(g_hMsidleDll, (LPSTR)4);
  315. gpfnSetIdleTimeout = (_SETIDLETIMEOUT)
  316. GetProcAddress(g_hMsidleDll, (LPSTR)5);
  317. gpfnSetIdleNotify = (_SETIDLENOTIFY)
  318. GetProcAddress(g_hMsidleDll, (LPSTR)6);
  319. gpfnSetBusyNotify = (_SETBUSYNOTIFY)
  320. GetProcAddress(g_hMsidleDll, (LPSTR)7);
  321. gpfnGetIdleMinutes = (_GETIDLEMINUTES)
  322. GetProcAddress(g_hMsidleDll, (LPSTR)8);
  323. if (gpfnBeginIdleDetection == NULL ||
  324. gpfnEndIdleDetection == NULL ||
  325. gpfnSetIdleTimeout == NULL ||
  326. gpfnSetIdleNotify == NULL ||
  327. gpfnSetBusyNotify == NULL ||
  328. gpfnGetIdleMinutes == NULL)
  329. {
  330. dwErr = GetLastError();
  331. ERR_OUT("Getting msidle.dll entry point addresses", dwErr);
  332. goto ErrExit;
  333. }
  334. // call start monitoring
  335. dwErr = gpfnBeginIdleDetection(OnIdleNotify, SCH_DEFAULT_IDLE_TIME, 0);
  336. if (dwErr)
  337. {
  338. ERR_OUT("Making initial idle call", dwErr);
  339. goto ErrExit;
  340. }
  341. g_fIdleInitialized = TRUE;
  342. return S_OK;
  343. ErrExit:
  344. FreeLibrary(g_hMsidleDll);
  345. g_hMsidleDll = NULL;
  346. gpfnBeginIdleDetection = NULL;
  347. gpfnEndIdleDetection = NULL;
  348. gpfnSetIdleTimeout = NULL;
  349. gpfnSetIdleNotify = NULL;
  350. gpfnSetBusyNotify = NULL;
  351. gpfnGetIdleMinutes = NULL;
  352. return HRESULT_FROM_WIN32(dwErr);
  353. }
  354. //+----------------------------------------------------------------------------
  355. //
  356. // Function: EndIdleDetection
  357. //
  358. // Synopsis: Stop idle detection.
  359. //
  360. // Arguments: None.
  361. //
  362. //-----------------------------------------------------------------------------
  363. void
  364. EndIdleDetection()
  365. {
  366. if (gpfnEndIdleDetection != NULL)
  367. {
  368. gpfnEndIdleDetection(0);
  369. }
  370. }