Source code of Windows XP (NT5)
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.

522 lines
14 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1996
  4. *
  5. * TITLE: BATSTATE.C
  6. *
  7. * VERSION: 2.0
  8. *
  9. * AUTHOR: ReedB
  10. *
  11. * DATE: 17 Oct, 1996
  12. *
  13. * DESCRIPTION:
  14. * BATSTATE.C contains helper function which maintain the global battery
  15. * state list.
  16. *
  17. *******************************************************************************/
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <commctrl.h>
  23. #include <dbt.h>
  24. #include <devioctl.h>
  25. #include <ntpoapi.h>
  26. #include <poclass.h>
  27. #include "powrprofp.h"
  28. #include "batmeter.h"
  29. // Simulated battery only for debug build.
  30. #ifndef DEBUG
  31. #undef SIM_BATTERY
  32. #endif
  33. /*******************************************************************************
  34. *
  35. * G L O B A L D A T A
  36. *
  37. *******************************************************************************/
  38. // Global battery state list. This list has the composite system battery state
  39. // as it's always present head. individual battery devices are linked to this
  40. // head. Use WalkBatteryState(ALL, ... to walk the entire list, including the
  41. // head. Use WalkBatteryState(DEVICES, ... to walk just the device list. If a
  42. // battery is in this list, it's displayable. g_ulBatCount is the count of
  43. // battery devices in this list. The composite battery is not counted.
  44. extern BATTERY_STATE g_bs;
  45. extern ULONG g_ulBatCount;
  46. extern HWND g_hwndBatMeter;
  47. #ifdef WINNT
  48. /*******************************************************************************
  49. *
  50. * RegisterForDeviceNotification
  51. *
  52. * DESCRIPTION:
  53. * Do registration for WM_DEVICECHANGED.
  54. *
  55. * PARAMETERS:
  56. *
  57. *******************************************************************************/
  58. BOOL RegisterForDeviceNotification(PBATTERY_STATE pbs)
  59. {
  60. DEV_BROADCAST_HANDLE dbh;
  61. memset(&dbh, 0, sizeof(DEV_BROADCAST_HANDLE));
  62. dbh.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  63. dbh.dbch_devicetype = DBT_DEVTYP_HANDLE;
  64. dbh.dbch_handle = pbs->hDevice;
  65. if (!g_hwndBatMeter) {
  66. DebugPrint( "RegisterForDeviceNotification, NULL g_hwndBatMeter");
  67. return FALSE;
  68. }
  69. pbs->hDevNotify = RegisterDeviceNotification(g_hwndBatMeter,
  70. &dbh,
  71. DEVICE_NOTIFY_WINDOW_HANDLE);
  72. if (!pbs->hDevNotify) {
  73. DebugPrint( "RegisterDeviceNotification failed");
  74. return FALSE;
  75. }
  76. return TRUE;
  77. }
  78. /*******************************************************************************
  79. *
  80. * UnregisterForDeviceNotification
  81. *
  82. * DESCRIPTION:
  83. *
  84. *
  85. * PARAMETERS:
  86. *
  87. *******************************************************************************/
  88. void UnregisterForDeviceNotification(PBATTERY_STATE pbs)
  89. {
  90. if (pbs->hDevNotify) {
  91. UnregisterDeviceNotification(pbs->hDevNotify);
  92. pbs->hDevNotify = NULL;
  93. }
  94. }
  95. #endif
  96. /*******************************************************************************
  97. *
  98. * SystemPowerStatusToBatteryState
  99. *
  100. * DESCRIPTION:
  101. * Fill in BATTERY_STATE fields based on passed SYSTEM_POWER_STATUS.
  102. *
  103. * PARAMETERS:
  104. *
  105. *******************************************************************************/
  106. void SystemPowerStatusToBatteryState(
  107. LPSYSTEM_POWER_STATUS lpsps,
  108. PBATTERY_STATE pbs
  109. )
  110. {
  111. pbs->ulPowerState = 0;
  112. if (lpsps->ACLineStatus == AC_LINE_ONLINE) {
  113. pbs->ulPowerState |= BATTERY_POWER_ON_LINE;
  114. }
  115. if (lpsps->BatteryFlag & BATTERY_FLAG_CHARGING) {
  116. pbs->ulPowerState |= BATTERY_CHARGING;
  117. }
  118. if (lpsps->BatteryFlag & BATTERY_FLAG_CRITICAL) {
  119. pbs->ulPowerState |= BATTERY_CRITICAL;
  120. }
  121. pbs->ulBatLifePercent = lpsps->BatteryLifePercent;
  122. pbs->ulBatLifeTime = lpsps->BatteryLifeTime;
  123. }
  124. /*******************************************************************************
  125. *
  126. * WalkBatteryState
  127. *
  128. * DESCRIPTION:
  129. *
  130. * PARAMETERS:
  131. *
  132. *******************************************************************************/
  133. BOOL WalkBatteryState(
  134. PBATTERY_STATE pbsStart,
  135. WALKENUMPROC pfnWalkEnumProc,
  136. HWND hWnd,
  137. LPARAM lParam1,
  138. LPARAM lParam2
  139. )
  140. {
  141. PBATTERY_STATE pbsTmp;
  142. while (pbsStart) {
  143. // Save the next entry in case the current one is deleted.
  144. pbsTmp = pbsStart->bsNext;
  145. if (!pfnWalkEnumProc(pbsStart, hWnd, lParam1, lParam2)) {
  146. return FALSE;
  147. }
  148. pbsStart = pbsTmp;
  149. }
  150. return TRUE;
  151. }
  152. /*******************************************************************************
  153. *
  154. * UpdateBatInfoProc
  155. *
  156. * DESCRIPTION:
  157. * Updates battery information for an individual battery device.
  158. *
  159. * PARAMETERS:
  160. *
  161. *******************************************************************************/
  162. BOOL UpdateBatInfoProc(
  163. PBATTERY_STATE pbs,
  164. HWND hWnd,
  165. LPARAM lParam1,
  166. LPARAM lParam2
  167. )
  168. {
  169. DWORD dwByteCount, dwIOCTL, dwWait;
  170. BATTERY_STATUS bs;
  171. BATTERY_WAIT_STATUS bws;
  172. BATTERY_INFORMATION bi;
  173. BATTERY_QUERY_INFORMATION bqi;
  174. if (pbs->hDevice == INVALID_HANDLE_VALUE) {
  175. DebugPrint( "UpdateBatInfoProc, Bad battery driver handle, LastError: 0x%X", GetLastError());
  176. return FALSE;
  177. }
  178. // If no tag, then don't update the battery info.
  179. dwIOCTL = IOCTL_BATTERY_QUERY_TAG;
  180. dwWait = 0;
  181. if (DeviceIoControl(pbs->hDevice, dwIOCTL,
  182. &dwWait, sizeof(dwWait),
  183. &(pbs->ulTag), sizeof(ULONG),
  184. &dwByteCount, NULL)) {
  185. bqi.BatteryTag = pbs->ulTag;
  186. bqi.InformationLevel = BatteryInformation;
  187. bqi.AtRate = 0;
  188. dwIOCTL = IOCTL_BATTERY_QUERY_INFORMATION;
  189. if (DeviceIoControl(pbs->hDevice, dwIOCTL,
  190. &bqi, sizeof(bqi),
  191. &bi, sizeof(bi),
  192. &dwByteCount, NULL)) {
  193. if (bi.FullChargedCapacity != UNKNOWN_CAPACITY) {
  194. pbs->ulFullChargedCapacity = bi.FullChargedCapacity;
  195. }
  196. else {
  197. pbs->ulFullChargedCapacity = bi.DesignedCapacity;
  198. }
  199. memset(&bws, 0, sizeof(BATTERY_WAIT_STATUS));
  200. bws.BatteryTag = pbs->ulTag;
  201. dwIOCTL = IOCTL_BATTERY_QUERY_STATUS;
  202. if (DeviceIoControl(pbs->hDevice, dwIOCTL,
  203. &bws, sizeof(BATTERY_WAIT_STATUS),
  204. &bs, sizeof(BATTERY_STATUS),
  205. &dwByteCount, NULL)) {
  206. pbs->ulPowerState = bs.PowerState;
  207. if (pbs->ulFullChargedCapacity < bs.Capacity) {
  208. pbs->ulFullChargedCapacity = bs.Capacity;
  209. DebugPrint( "UpdateBatInfoProc, unable to calculate ulFullChargedCapacity");
  210. }
  211. if (pbs->ulFullChargedCapacity == 0) {
  212. pbs->ulBatLifePercent = 0;
  213. }
  214. else {
  215. pbs->ulBatLifePercent =
  216. (100 * bs.Capacity) / pbs->ulFullChargedCapacity;
  217. }
  218. return TRUE;
  219. }
  220. }
  221. }
  222. else {
  223. pbs->ulTag = BATTERY_TAG_INVALID;
  224. // No battery tag, that's ok, the user may have removed the battery.
  225. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  226. return TRUE;
  227. }
  228. }
  229. DebugPrint( "UpdateBatInfoProc, IOCTL: %X Failure, BatNum: %d, LastError: %d\n", dwIOCTL, pbs->ulBatNum, GetLastError());
  230. return FALSE;
  231. }
  232. /*******************************************************************************
  233. *
  234. * SimUpdateBatInfoProc
  235. *
  236. * DESCRIPTION:
  237. * Simulate the update of battery information for an individual batter device.
  238. *
  239. * PARAMETERS:
  240. *
  241. *******************************************************************************/
  242. BOOL SimUpdateBatInfoProc(
  243. PBATTERY_STATE pbs,
  244. HWND hWnd,
  245. LPARAM lParam1,
  246. LPARAM lParam2
  247. )
  248. {
  249. pbs->ulTag = pbs->ulBatNum;
  250. if (pbs->ulBatNum == 1) {
  251. pbs->ulFullChargedCapacity = 2000;
  252. pbs->ulFullChargedCapacity = 1991;
  253. pbs->ulPowerState = BATTERY_CHARGING | BATTERY_POWER_ON_LINE;
  254. pbs->ulBatLifePercent = 75;
  255. }
  256. else {
  257. pbs->ulFullChargedCapacity = 3000;
  258. pbs->ulFullChargedCapacity = 2991;
  259. pbs->ulPowerState = BATTERY_DISCHARGING | BATTERY_CRITICAL;
  260. pbs->ulBatLifePercent = 3;
  261. }
  262. return TRUE;
  263. }
  264. /*******************************************************************************
  265. *
  266. * AddBatteryStateDevice
  267. *
  268. * DESCRIPTION:
  269. * Add only displayable batteries to the battery list. New entry is appended
  270. * to battery state list.
  271. *
  272. * PARAMETERS:
  273. *
  274. *******************************************************************************/
  275. PBATTERY_STATE AddBatteryStateDevice(LPTSTR lpszName, ULONG ulBatNum)
  276. {
  277. PBATTERY_STATE pbs, pbsTemp = &g_bs;
  278. LPTSTR lpsz = NULL;
  279. if (!lpszName) {
  280. return NULL;
  281. }
  282. // Append to end of list
  283. while (pbsTemp->bsNext) {
  284. pbsTemp = pbsTemp->bsNext;
  285. }
  286. // Allocate storage for new battery device state.
  287. if (pbs = LocalAlloc(LPTR, sizeof(BATTERY_STATE))) {
  288. if (lpsz = LocalAlloc(0, STRSIZE(lpszName))) {
  289. lstrcpy(lpsz, lpszName);
  290. pbs->lpszDeviceName = lpsz;
  291. pbs->ulSize = sizeof(BATTERY_STATE);
  292. pbs->ulBatNum = ulBatNum;
  293. // Open a handle to the battery driver.
  294. pbs->hDevice = CreateFile(lpszName,
  295. GENERIC_READ | GENERIC_WRITE,
  296. FILE_SHARE_READ | FILE_SHARE_WRITE,
  297. NULL, OPEN_EXISTING,
  298. FILE_ATTRIBUTE_NORMAL, NULL);
  299. #ifdef WINNT
  300. // Setup for notification by PNP when battery goes away.
  301. RegisterForDeviceNotification(pbs);
  302. #endif
  303. // Get the current battery info from the battery driver.
  304. if (UpdateBatInfoProc(pbs, NULL, 0, 0)) {
  305. // Link the new battery device state into the list.
  306. pbsTemp->bsNext = pbs;
  307. pbs->bsPrev = pbsTemp;
  308. return pbs;
  309. }
  310. LocalFree(lpsz);
  311. }
  312. LocalFree(pbs);
  313. }
  314. return NULL;
  315. }
  316. /*******************************************************************************
  317. *
  318. * SimAddBatteryStateDevice
  319. *
  320. * DESCRIPTION:
  321. * Simulate the addition of displayable batteries to the battery list.
  322. * New entry is appended to battery state list.
  323. *
  324. * PARAMETERS:
  325. *
  326. *******************************************************************************/
  327. PBATTERY_STATE SimAddBatteryStateDevice(LPTSTR lpszName, ULONG ulBatNum)
  328. {
  329. PBATTERY_STATE pbs, pbsTemp = &g_bs;
  330. LPTSTR lpsz = NULL;
  331. if (!lpszName) {
  332. return NULL;
  333. }
  334. // Append to end of list
  335. while (pbsTemp->bsNext) {
  336. pbsTemp = pbsTemp->bsNext;
  337. }
  338. // Allocate storage for new battery device state.
  339. if (pbs = LocalAlloc(LPTR, sizeof(BATTERY_STATE))) {
  340. if (lpsz = LocalAlloc(0, STRSIZE(lpszName))) {
  341. lstrcpy(lpsz, lpszName);
  342. pbs->lpszDeviceName = lpsz;
  343. pbs->ulSize = sizeof(BATTERY_STATE);
  344. pbs->ulBatNum = ulBatNum;
  345. // Open a handle to the battery driver.
  346. pbs->hDevice = (HANDLE) -1;
  347. // Get the current battery info from the battery driver.
  348. if (SimUpdateBatInfoProc(pbs, NULL, 0, 0)) {
  349. // Link the new battery device state into the list.
  350. pbsTemp->bsNext = pbs;
  351. pbs->bsPrev = pbsTemp;
  352. return pbs;
  353. }
  354. LocalFree(lpsz);
  355. }
  356. LocalFree(pbs);
  357. }
  358. return NULL;
  359. }
  360. /*******************************************************************************
  361. *
  362. * RemoveBatteryStateDevice
  363. *
  364. * DESCRIPTION:
  365. *
  366. * PARAMETERS:
  367. *
  368. *******************************************************************************/
  369. BOOL RemoveBatteryStateDevice(PBATTERY_STATE pbs)
  370. {
  371. // Unlink
  372. if (pbs->bsNext) {
  373. pbs->bsNext->bsPrev = pbs->bsPrev;
  374. }
  375. if (pbs->bsPrev) {
  376. pbs->bsPrev->bsNext = pbs->bsNext;
  377. }
  378. #ifdef winnt
  379. UnregisterForDeviceNotification(pbs);
  380. #endif
  381. // Free the battery driver handle if one was opened.
  382. if (pbs->hDevice != INVALID_HANDLE_VALUE) {
  383. CloseHandle(pbs->hDevice);
  384. }
  385. // Free the device name.
  386. LocalFree(pbs->lpszDeviceName);
  387. // Destroy any icons.
  388. if (pbs->hIconCache) {
  389. DestroyIcon(pbs->hIconCache);
  390. }
  391. if (pbs->hIconCache16) {
  392. DestroyIcon(pbs->hIconCache16);
  393. }
  394. // Free the associated storage.
  395. LocalFree(pbs);
  396. return TRUE;
  397. }
  398. /*******************************************************************************
  399. *
  400. * RemoveMissingProc
  401. *
  402. * DESCRIPTION:
  403. * Remove a battery from the global battery state list.
  404. *
  405. * PARAMETERS:
  406. * lParam2 - REMOVE_MISSING or REMOVE_ALL
  407. *
  408. *******************************************************************************/
  409. BOOL RemoveMissingProc(
  410. PBATTERY_STATE pbs,
  411. HWND hWnd,
  412. LPARAM lParam1,
  413. LPARAM lParam2)
  414. {
  415. UINT i;
  416. LPTSTR *pszDeviceNames;
  417. if (lParam2 == REMOVE_MISSING) {
  418. if ((pszDeviceNames = (LPTSTR *)lParam1) != NULL) {
  419. for (i = 0; i < NUM_BAT; i++) {
  420. if (pszDeviceNames[i]) {
  421. if (!lstrcmp(pbs->lpszDeviceName, pszDeviceNames[i])) {
  422. // Device found in device list, leave it alone.
  423. return TRUE;
  424. }
  425. }
  426. else {
  427. continue;
  428. }
  429. }
  430. }
  431. }
  432. // Device not in the device names list, remove it.
  433. RemoveBatteryStateDevice(pbs);
  434. return TRUE;
  435. }
  436. /*******************************************************************************
  437. *
  438. * FindNameProc
  439. *
  440. * DESCRIPTION:
  441. * Returns FALSE (stop searching) if we find the name, else TRUE.
  442. *
  443. * PARAMETERS:
  444. *
  445. *******************************************************************************/
  446. BOOL FindNameProc(PBATTERY_STATE pbs, HWND hWnd, LPARAM lParam1, LPARAM lParam2)
  447. {
  448. if (lParam1) {
  449. if (!lstrcmp(pbs->lpszDeviceName, (LPTSTR)lParam1)) {
  450. // Device found in device list.
  451. return FALSE;
  452. }
  453. }
  454. return TRUE;
  455. }