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.

1343 lines
42 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1997
  4. *
  5. * TITLE: BATMETER.C
  6. *
  7. * VERSION: 2.0
  8. *
  9. * AUTHOR: ReedB
  10. *
  11. * DATE: 17 Oct, 1996
  12. *
  13. * DESCRIPTION:
  14. *
  15. * Implements the battery meter of the PowerCfg or SysTray battery
  16. * meter windows. The battery meter has two display modes, single and
  17. * multi-battery. In single mode, a representation of the total of all battery
  18. * capacity in a system is displayed. In multi-battery mode, battery
  19. * information is displayed for each individual battery as well as the total.
  20. *
  21. * The battery meter parent window receives notification from USER when
  22. * any battery status has changed through the WM_POWERBROADCAST,
  23. * PBT_APMPOWERSTATUSCHANGE message.
  24. *
  25. * ??? We need to add perfmon support: Create and maintain keys/values
  26. * under HKEY_PERFORMANCE_DATA.
  27. *
  28. *******************************************************************************/
  29. #include <nt.h>
  30. #include <ntrtl.h>
  31. #include <nturtl.h>
  32. #include <windows.h>
  33. #include <commctrl.h>
  34. #include <dbt.h>
  35. #include <objbase.h>
  36. #include <initguid.h>
  37. #include <ntpoapi.h>
  38. #include <poclass.h>
  39. #include <setupapi.h>
  40. #include <syssetup.h>
  41. #include <setupbat.h>
  42. #include <ccstock.h>
  43. #include <help.h>
  44. #include "powrprofp.h"
  45. #include "batmeter.h"
  46. #include "bmresid.h"
  47. #include "..\powercfg\PwrMn_cs.h"
  48. #include "shfusion.h"
  49. // Simulated battery only for debug build.
  50. #ifndef DEBUG
  51. #undef SIM_BATTERY
  52. #endif
  53. // Define some things for debug.h. Required when you include ccstock.h in
  54. // one and only one file.
  55. #define SZ_DEBUGINI "ccshell.ini"
  56. #define SZ_DEBUGSECTION "BATMETER"
  57. #define SZ_MODULE "BATMETER"
  58. #define DECLARE_DEBUG
  59. #include <debug.h>
  60. /*******************************************************************************
  61. *
  62. * G L O B A L D A T A
  63. *
  64. *******************************************************************************/
  65. HINSTANCE g_hInstance; // Global instance handle of this DLL.
  66. HWND g_hwndParent; // Parent of the battery meter.
  67. HWND g_hwndBatMeter; // Battery meter.
  68. // The following constant global array is used to walk through the
  69. // control ID's in the battery metter dialog box. It makes getting
  70. // a control ID from a battery number easy.
  71. #define BAT_ICON 0
  72. #define BAT_STATUS 1
  73. #define BAT_REMAINING 2
  74. #define BAT_NUM 3
  75. #define BAT_LAST BAT_NUM+1
  76. UINT g_iMapBatNumToID [NUM_BAT+1][4]={
  77. {IDC_POWERSTATUSICON, IDC_POWERSTATUSBAR, IDC_REMAINING, IDC_BATNUM0},
  78. {IDC_POWERSTATUSICON1, IDC_STATUS1, IDC_REMAINING1, IDC_BATNUM1},
  79. {IDC_POWERSTATUSICON2, IDC_STATUS2, IDC_REMAINING2, IDC_BATNUM2},
  80. {IDC_POWERSTATUSICON3, IDC_STATUS3, IDC_REMAINING3, IDC_BATNUM3},
  81. {IDC_POWERSTATUSICON4, IDC_STATUS4, IDC_REMAINING4, IDC_BATNUM4},
  82. {IDC_POWERSTATUSICON5, IDC_STATUS5, IDC_REMAINING5, IDC_BATNUM5},
  83. {IDC_POWERSTATUSICON6, IDC_STATUS6, IDC_REMAINING6, IDC_BATNUM6},
  84. {IDC_POWERSTATUSICON7, IDC_STATUS7, IDC_REMAINING7, IDC_BATNUM7},
  85. {IDC_POWERSTATUSICON8, IDC_STATUS8, IDC_REMAINING8, IDC_BATNUM8}
  86. };
  87. // Global battery state list. This list has the composite system battery state
  88. // as it's always present head. individual battery devices are linked to this
  89. // head. Use WalkBatteryState(ALL, ... to walk the entire list, including the
  90. // head. Use WalkBatteryState(DEVICES, ... to walk just the device list. If a
  91. // battery is in this list, it's displayable. g_uiBatCount is the count of
  92. // battery devices in this list. The composite battery is not counted. The
  93. // g_pbs array provides a handy UI battery number to pbs conversion. The
  94. // following three variables are only changed during DeviceChanged.
  95. BATTERY_STATE g_bs;
  96. UINT g_uiBatCount;
  97. PBATTERY_STATE g_pbs[NUM_BAT+1];
  98. LPTSTR g_lpszDriverNames[NUM_BAT];
  99. UINT g_uiDriverCount;
  100. BOOL g_bShowingMulti;
  101. // The following array provides context sensitive help associations between
  102. // resource control identifiers and help resource string identifiers.
  103. const DWORD g_ContextMenuHelpIDs[] =
  104. {
  105. IDC_BATMETERGROUPBOX, IDH_COMM_GROUPBOX,
  106. IDC_BATMETERGROUPBOX1, IDH_COMM_GROUPBOX,
  107. IDC_POWERSTATUSICON, NO_HELP,
  108. IDC_POWERSTATUSICON1, IDH_BATMETER_CHARGING_ICON,
  109. IDC_POWERSTATUSICON2, IDH_BATMETER_CHARGING_ICON,
  110. IDC_POWERSTATUSICON3, IDH_BATMETER_CHARGING_ICON,
  111. IDC_POWERSTATUSICON4, IDH_BATMETER_CHARGING_ICON,
  112. IDC_POWERSTATUSICON5, IDH_BATMETER_CHARGING_ICON,
  113. IDC_POWERSTATUSICON6, IDH_BATMETER_CHARGING_ICON,
  114. IDC_POWERSTATUSICON7, IDH_BATMETER_CHARGING_ICON,
  115. IDC_POWERSTATUSICON8, IDH_BATMETER_CHARGING_ICON,
  116. IDC_BATNUM1, NO_HELP,
  117. IDC_BATNUM2, NO_HELP,
  118. IDC_BATNUM3, NO_HELP,
  119. IDC_BATNUM4, NO_HELP,
  120. IDC_BATNUM5, NO_HELP,
  121. IDC_BATNUM6, NO_HELP,
  122. IDC_BATNUM7, NO_HELP,
  123. IDC_BATNUM8, NO_HELP,
  124. IDC_STATUS1, NO_HELP,
  125. IDC_STATUS2, NO_HELP,
  126. IDC_STATUS3, NO_HELP,
  127. IDC_STATUS4, NO_HELP,
  128. IDC_STATUS5, NO_HELP,
  129. IDC_STATUS6, NO_HELP,
  130. IDC_STATUS7, NO_HELP,
  131. IDC_STATUS8, NO_HELP,
  132. IDC_MOREINFO, NO_HELP,
  133. IDC_CURRENTPOWERSOURCE, IDH_BATMETER_CURPOWERSOURCE,
  134. IDC_BATTERYLEVEL, IDH_BATMETER_CURPOWERSOURCE,
  135. IDC_TOTALBATPWRREMAINING, IDH_BATMETER_TOTALBATPOWER,
  136. IDC_REMAINING, IDH_BATMETER_TOTALBATPOWER,
  137. IDC_POWERSTATUSBAR, IDH_BATMETER_TOTALBATPOWER,
  138. IDC_BARPERCENT, IDH_BATMETER_TOTALBATPOWER,
  139. IDC_TOTALTIME, IDH_BATMETER_TOTALTIME,
  140. IDC_TIMEREMAINING, IDH_BATMETER_TOTALTIME,
  141. IDC_BATTERYNAME, IDH_DETAILED_BATINFO_LABELS,
  142. IDC_DEVNAME, IDH_DETAILED_BATINFO_LABELS,
  143. IDC_UNIQUEID, IDH_DETAILED_BATINFO_LABELS,
  144. IDC_BATID, IDH_DETAILED_BATINFO_LABELS,
  145. IDC_MANUFACTURE, IDH_DETAILED_BATINFO_LABELS,
  146. IDC_BATMANNAME, IDH_DETAILED_BATINFO_LABELS,
  147. IDC_DATEMANUFACTURED, IDH_DETAILED_BATINFO_LABELS,
  148. IDC_BATMANDATE, IDH_DETAILED_BATINFO_LABELS,
  149. IDC_CHEMISTRY, IDH_DETAILED_BATINFO_LABELS,
  150. IDC_CHEM, IDH_DETAILED_BATINFO_LABELS,
  151. IDC_POWERSTATE, IDH_DETAILED_BATINFO_LABELS,
  152. IDC_STATE, IDH_DETAILED_BATINFO_LABELS,
  153. IDC_REFRESH, IDH_DETAILED_BATINFO_REFRESH,
  154. 0, 0
  155. };
  156. /*******************************************************************************
  157. *
  158. * P U B L I C E N T R Y P O I N T S
  159. *
  160. *******************************************************************************/
  161. /*******************************************************************************
  162. *
  163. * DllInitialize
  164. *
  165. * DESCRIPTION:
  166. *
  167. * PARAMETERS:
  168. *
  169. *******************************************************************************/
  170. BOOL DllInitialize(IN PVOID hmod, IN ULONG ulReason, IN PCONTEXT pctx OPTIONAL)
  171. {
  172. UNREFERENCED_PARAMETER(pctx);
  173. switch (ulReason) {
  174. case DLL_PROCESS_ATTACH:
  175. g_hInstance = hmod;
  176. DisableThreadLibraryCalls(g_hInstance);
  177. SHFusionInitializeFromModuleID(hmod, 124);
  178. break;
  179. case DLL_PROCESS_DETACH:
  180. SHFusionUninitialize();
  181. break;
  182. }
  183. return TRUE;
  184. }
  185. /*******************************************************************************
  186. *
  187. * PowerCapabilities
  188. *
  189. * DESCRIPTION:
  190. * This public function is used to determine if the system has any power
  191. * management capabilities which require UI support. Return TRUE if power
  192. * management UI should be displayed.
  193. *
  194. * PARAMETERS:
  195. *
  196. *******************************************************************************/
  197. BOOL PowerCapabilities()
  198. {
  199. SYSTEM_POWER_CAPABILITIES spc;
  200. int dummy;
  201. #ifndef SIM_BATTERY
  202. if (GetPwrCapabilities(&spc)) {
  203. if ((spc.PowerButtonPresent) ||
  204. (spc.SleepButtonPresent) ||
  205. (spc.LidPresent) ||
  206. (spc.SystemS1) ||
  207. (spc.SystemS2) ||
  208. (spc.SystemS3) ||
  209. (spc.SystemS4) ||
  210. (spc.SystemS5) ||
  211. (spc.DiskSpinDown) ||
  212. (spc.SystemBatteriesPresent)) {
  213. return TRUE;
  214. }
  215. else {
  216. if (SystemParametersInfo(SPI_GETLOWPOWERACTIVE, 0, &dummy, 0)) {
  217. return TRUE;
  218. }
  219. }
  220. }
  221. return FALSE;
  222. #else
  223. return TRUE;
  224. #endif
  225. }
  226. /*******************************************************************************
  227. *
  228. * BatMeterCapabilities
  229. *
  230. * DESCRIPTION:
  231. * This public function is used to determine if the battery meter library
  232. * can run on the host machine. Return TRUE on success (battery meter can run).
  233. *
  234. * PARAMETERS:
  235. * ppuiBatCount - Points to a pointer which will be filled in with a pointer
  236. * to the global battery count.
  237. *
  238. *******************************************************************************/
  239. BOOL BatMeterCapabilities(
  240. PUINT *ppuiBatCount
  241. )
  242. {
  243. #ifndef SIM_BATTERY
  244. SYSTEM_POWER_CAPABILITIES spc;
  245. #endif // SIM_BATTERY
  246. if (ppuiBatCount) {
  247. *ppuiBatCount = &g_uiBatCount;
  248. }
  249. g_uiBatCount = 0;
  250. #ifndef SIM_BATTERY
  251. // Make sure we have batteries to query.
  252. if (GetPwrCapabilities(&spc)) {
  253. if (spc.SystemBatteriesPresent) {
  254. g_uiDriverCount = GetBatteryDriverNames(g_lpszDriverNames);
  255. if (g_uiDriverCount != 0) {
  256. g_uiBatCount = g_uiDriverCount;
  257. return TRUE;
  258. }
  259. else {
  260. BATTRACE(( "BatMeterCapabilities, no battery drivers found."));
  261. }
  262. }
  263. }
  264. return FALSE;
  265. #else // SIM_BATTERY
  266. g_uiBatCount = g_uiDriverCount = GetBatteryDriverNames(g_lpszDriverNames);
  267. return UpdateDriverList(g_lpszDriverNames, g_uiDriverCount);
  268. #endif // SIM_BATTERY
  269. }
  270. /*******************************************************************************
  271. *
  272. * CreateBatMeter
  273. *
  274. * DESCRIPTION:
  275. * Create, fetch data for and draw the battery meter window. Returns a handle
  276. * to the newly created battery meter window on success, NULL on failure.
  277. *
  278. * PARAMETERS:
  279. * hwndParent - Parent of the battery meter dialog.
  280. * wndFrame - Frame to locate the battery meter dialog.
  281. * bShowMulti - Specifies the display mode (TRUE -> multiple battery).
  282. * pbsComposite - Optional pointer to composite battery state.
  283. *
  284. *******************************************************************************/
  285. HWND CreateBatMeter(
  286. HWND hwndParent,
  287. HWND hwndFrame,
  288. BOOL bShowMulti,
  289. PBATTERY_STATE pbsComposite
  290. )
  291. {
  292. INT iWidth, iHeight;
  293. RECT rFrame = {0};
  294. // Build the battery devices name list if hasn't already been built.
  295. if (!g_uiBatCount)
  296. {
  297. BatMeterCapabilities(NULL);
  298. }
  299. // Remember if we are showing details for each battery
  300. g_bShowingMulti = bShowMulti;
  301. // Make sure we have at least one battery.
  302. if (g_uiBatCount)
  303. {
  304. // Create the battery meter control.
  305. g_hwndParent = hwndParent;
  306. g_hwndBatMeter = CreateDialog(g_hInstance,
  307. MAKEINTRESOURCE(IDD_BATMETER),
  308. hwndParent,
  309. BatMeterDlgProc);
  310. // Place the battery meter in the passed frame window.
  311. if ((g_hwndBatMeter) && (hwndFrame))
  312. {
  313. // Position the BatMeter dialog in the frame.
  314. if (!GetWindowRect(hwndFrame, &rFrame))
  315. {
  316. BATTRACE(( "CreateBatMeter, GetWindowRect failed, hwndFrame: %08X", hwndFrame));
  317. }
  318. iWidth = rFrame.right - rFrame.left;
  319. iHeight = rFrame.bottom - rFrame.top;
  320. if (IsBiDiLocalizedSystemEx(NULL))
  321. {
  322. // Whistler #209400: On BIDI systems, ScreenToClient() wants the right
  323. // coord in the left location because everything is flipped.
  324. rFrame.left = rFrame.right;
  325. }
  326. if (!ScreenToClient(hwndParent, (LPPOINT)&rFrame))
  327. {
  328. BATTRACE(( "CreateBatMeter, ScreenToClient failed"));
  329. }
  330. if (!MoveWindow(g_hwndBatMeter,
  331. rFrame.left,
  332. rFrame.top,
  333. iWidth,
  334. iHeight,
  335. FALSE))
  336. {
  337. BATTRACE(( "CreateBatMeter, MoveWindow failed, %d, %d", rFrame.left, rFrame.top));
  338. }
  339. // Build the battery driver data list.
  340. if (!UpdateDriverList(g_lpszDriverNames, g_uiDriverCount))
  341. {
  342. return DestroyBatMeter(g_hwndBatMeter);
  343. }
  344. // Do the first update.
  345. UpdateBatMeter(g_hwndBatMeter, bShowMulti, TRUE, pbsComposite);
  346. ShowWindow(g_hwndBatMeter, SW_SHOWNOACTIVATE);
  347. }
  348. }
  349. return g_hwndBatMeter;
  350. }
  351. /*******************************************************************************
  352. *
  353. * DestroyBatMeter
  354. *
  355. * DESCRIPTION:
  356. *
  357. *******************************************************************************/
  358. HWND DestroyBatMeter(HWND hWnd)
  359. {
  360. SendMessage(hWnd, WM_DESTROYBATMETER, 0, 0);
  361. g_hwndBatMeter = NULL;
  362. return g_hwndBatMeter;
  363. }
  364. /*******************************************************************************
  365. *
  366. * UpdateBatMeter
  367. *
  368. * DESCRIPTION:
  369. * This function should be called when the battery meter parent window
  370. * receives a WM_POWERBROADCAST, PBT_APMPOWERSTATUSCHANGE message, it will
  371. * update the data in the global battery state list. If needed the display
  372. * will also be updated.
  373. *
  374. * PARAMETERS:
  375. * HWND hwndBatMeter, hWnd of the battery meter dialog
  376. * BOOL bShowMulti, Specifies the display mode
  377. * BOOL bForceUpdate, Forces a UI update
  378. * PBATTERY_STATE pbsComposite Optional pointer to composite battery state.
  379. *
  380. *******************************************************************************/
  381. BOOL UpdateBatMeter(
  382. HWND hWnd,
  383. BOOL bShowMulti,
  384. BOOL bForceUpdate,
  385. PBATTERY_STATE pbsComposite
  386. )
  387. {
  388. BOOL bRet = FALSE;
  389. SYSTEM_POWER_STATUS sps;
  390. UINT uIconID;
  391. // Update the composite battery state.
  392. if (GetSystemPowerStatus(&sps) && hWnd) {
  393. if (sps.BatteryLifePercent > 100) {
  394. BATTRACE(( "GetSystemPowerStatuse, set BatteryLifePercent: %d", sps.BatteryLifePercent));
  395. }
  396. // Fill in the composite battery state.
  397. SystemPowerStatusToBatteryState(&sps, &g_bs);
  398. // Update the information in the battery state list if we have a battery.
  399. if (g_hwndBatMeter) {
  400. #ifndef SIM_BATTERY
  401. WalkBatteryState(DEVICES,
  402. (WALKENUMPROC)UpdateBatInfoProc,
  403. NULL,
  404. (LPARAM)NULL,
  405. (LPARAM)NULL);
  406. #else
  407. WalkBatteryState(DEVICES,
  408. (WALKENUMPROC)SimUpdateBatInfoProc,
  409. NULL,
  410. (LPARAM)NULL,
  411. (LPARAM)NULL);
  412. #endif
  413. // See if the current display mode matches the requested mode.
  414. if ((g_bShowingMulti != bShowMulti) || (bForceUpdate)) {
  415. g_bShowingMulti = SwitchDisplayMode(hWnd, bShowMulti);
  416. bForceUpdate = TRUE;
  417. }
  418. if (g_bShowingMulti) {
  419. // Walk the bs list, and update all battery displays.
  420. WalkBatteryState(ALL,
  421. (WALKENUMPROC)UpdateBatMeterProc,
  422. hWnd,
  423. (LPARAM)g_bShowingMulti,
  424. (LPARAM)bForceUpdate);
  425. }
  426. else {
  427. // Display only the comosite battery information.
  428. UpdateBatMeterProc(&g_bs,
  429. hWnd,
  430. (LPARAM)g_bShowingMulti,
  431. (LPARAM)bForceUpdate);
  432. }
  433. bRet = TRUE;
  434. }
  435. }
  436. else {
  437. // Fill in default composite info.
  438. g_bs.ulPowerState = BATTERY_POWER_ON_LINE;
  439. g_bs.ulBatLifePercent = (UINT) -1;
  440. g_bs.ulBatLifeTime = (UINT) -1;
  441. uIconID = MapBatInfoToIconID(&g_bs);
  442. g_bs.hIconCache = GetBattIcon(hWnd, uIconID, g_bs.hIconCache, FALSE, 32);
  443. g_bs.hIconCache16 = GetBattIcon(hWnd, uIconID, g_bs.hIconCache16, FALSE, 16);
  444. }
  445. // If a pointer is provided, copy the composite battery state data.
  446. if (pbsComposite) {
  447. if (pbsComposite->ulSize == sizeof(BATTERY_STATE)) {
  448. memcpy(pbsComposite, &g_bs, sizeof(BATTERY_STATE));
  449. }
  450. else {
  451. BATTRACE(( "UpdateBatMeter, passed BATTERY_STATE size is invalid"));
  452. }
  453. }
  454. return bRet;
  455. }
  456. /*******************************************************************************
  457. *
  458. * P R I V A T E F U N C T I O N S
  459. *
  460. *******************************************************************************/
  461. /*******************************************************************************
  462. *
  463. * LoadDynamicString
  464. *
  465. * DESCRIPTION:
  466. * Wrapper for the FormatMessage function that loads a string from our
  467. * resource table into a dynamically allocated buffer, optionally filling
  468. * it with the variable arguments passed.
  469. *
  470. * PARAMETERS:
  471. * uiStringID - resource identifier of the string to use.
  472. * ... - Optional parameters to use to format the string message.
  473. *
  474. *******************************************************************************/
  475. LPTSTR CDECL LoadDynamicString(UINT uiStringID, ... )
  476. {
  477. va_list Marker;
  478. TCHAR szBuf[256];
  479. LPTSTR lpsz;
  480. int iLen;
  481. // va_start is a macro...it breaks when you use it as an assign...on ALPHA.
  482. va_start(Marker, uiStringID);
  483. iLen = LoadString(g_hInstance, uiStringID, szBuf, ARRAYSIZE(szBuf));
  484. if (iLen == 0) {
  485. BATTRACE(( "LoadDynamicString: LoadString on: 0x%X failed", uiStringID));
  486. return NULL;
  487. }
  488. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  489. (LPVOID) szBuf, 0, 0, (LPTSTR)&lpsz, 0, &Marker);
  490. return lpsz;
  491. }
  492. /*******************************************************************************
  493. *
  494. * DisplayFreeStr
  495. *
  496. * DESCRIPTION:
  497. *
  498. * PARAMETERS:
  499. *
  500. *******************************************************************************/
  501. LPTSTR DisplayFreeStr(HWND hWnd, UINT uID, LPTSTR lpsz, BOOL bFree)
  502. {
  503. if (lpsz) {
  504. SetDlgItemText(hWnd, uID, lpsz);
  505. ShowWindow(GetDlgItem(hWnd, uID), SW_SHOWNOACTIVATE);
  506. if (bFree) {
  507. LocalFree(lpsz);
  508. return NULL;
  509. }
  510. }
  511. else {
  512. ShowWindow(GetDlgItem(hWnd, uID), SW_HIDE);
  513. }
  514. return lpsz;
  515. }
  516. /*******************************************************************************
  517. *
  518. * ShowHideItem
  519. * ShowItem
  520. * HideItem
  521. *
  522. * DESCRIPTION:
  523. * Handy helpers to show or hide dialog items in the battery meter dialog.
  524. *
  525. * PARAMETERS:
  526. * hWnd - Battery meter dialog handle.
  527. * uID - Control ID of control to be shown or hidden.
  528. *
  529. *******************************************************************************/
  530. BOOL ShowHideItem(HWND hWnd, UINT uID, BOOL bShow)
  531. {
  532. ShowWindow(GetDlgItem(hWnd, uID), (bShow) ? SW_SHOWNOACTIVATE : SW_HIDE);
  533. return bShow;
  534. }
  535. void ShowItem(HWND hWnd, UINT uID)
  536. {
  537. ShowWindow(GetDlgItem(hWnd, uID), SW_SHOWNOACTIVATE);
  538. }
  539. void HideItem(HWND hWnd, UINT uID)
  540. {
  541. ShowWindow(GetDlgItem(hWnd, uID), SW_HIDE);
  542. }
  543. /*******************************************************************************
  544. *
  545. * SwitchDisplayMode
  546. *
  547. * DESCRIPTION:
  548. * Return TRUE if display is switched to multi battery mode.
  549. *
  550. * PARAMETERS:
  551. *
  552. *******************************************************************************/
  553. BOOL SwitchDisplayMode(HWND hWnd, BOOL bShowMulti)
  554. {
  555. ULONG i, j;
  556. // Override request if multi-battery display is not possible.
  557. if ((bShowMulti) && (!g_uiBatCount)) {
  558. bShowMulti = FALSE;
  559. }
  560. if (!g_uiBatCount) {
  561. //
  562. // Hide all info if no batteries are installed
  563. //
  564. HideItem(hWnd, IDC_POWERSTATUSBAR);
  565. HideItem(hWnd, IDC_BARPERCENT);
  566. HideItem(hWnd, IDC_MOREINFO);
  567. } else if (bShowMulti) {
  568. HideItem(hWnd, IDC_POWERSTATUSBAR);
  569. HideItem(hWnd, IDC_BARPERCENT);
  570. ShowItem(hWnd, IDC_MOREINFO);
  571. for (i = 1; i <= g_uiBatCount; i++) {
  572. for (j = 0; j < BAT_LAST; j++) {
  573. ShowItem(hWnd, g_iMapBatNumToID[i][0]);
  574. }
  575. }
  576. }
  577. else {
  578. for (i = 1; i <= g_uiBatCount; i++) {
  579. for (j = 0; j < BAT_LAST; j++) {
  580. HideItem(hWnd, g_iMapBatNumToID[i][j]);
  581. }
  582. }
  583. ShowItem(hWnd, IDC_POWERSTATUSBAR);
  584. ShowItem(hWnd, IDC_BARPERCENT);
  585. HideItem(hWnd, IDC_MOREINFO);
  586. }
  587. return bShowMulti;
  588. }
  589. /*******************************************************************************
  590. *
  591. * CleanupBatteryData
  592. *
  593. * DESCRIPTION:
  594. *
  595. * PARAMETERS:
  596. *
  597. *******************************************************************************/
  598. void CleanupBatteryData(void)
  599. {
  600. g_hwndBatMeter = NULL;
  601. // Mark all batteries as missing.
  602. memset(&g_pbs, 0, sizeof(g_pbs));
  603. // Walk the bs list, remove all devices and cleanup.
  604. WalkBatteryState(DEVICES,
  605. (WALKENUMPROC)RemoveMissingProc,
  606. NULL,
  607. (LPARAM)NULL,
  608. (LPARAM)REMOVE_ALL);
  609. // Free any old driver names.
  610. FreeBatteryDriverNames(g_lpszDriverNames);
  611. g_uiBatCount = 0;
  612. }
  613. /*******************************************************************************
  614. *
  615. * BatMeterDlgProc
  616. *
  617. * DESCRIPTION:
  618. * DialogProc for the Battery Meter control. Provide support for more battery
  619. * info.
  620. *
  621. * PARAMETERS:
  622. *
  623. *******************************************************************************/
  624. LRESULT CALLBACK BatMeterDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  625. {
  626. #ifdef WINNT
  627. UINT i, j;
  628. PBATTERY_STATE pbsTemp;
  629. #endif // WINNT
  630. UINT uiBatNum;
  631. switch (uMsg) {
  632. case WM_COMMAND:
  633. if ((HIWORD(wParam) == STN_CLICKED) ||
  634. (HIWORD(wParam) == BN_CLICKED)) {
  635. switch (LOWORD(wParam)) {
  636. case IDC_POWERSTATUSICON1:
  637. case IDC_POWERSTATUSICON2:
  638. case IDC_POWERSTATUSICON3:
  639. case IDC_POWERSTATUSICON4:
  640. case IDC_POWERSTATUSICON5:
  641. case IDC_POWERSTATUSICON6:
  642. case IDC_POWERSTATUSICON7:
  643. case IDC_POWERSTATUSICON8:
  644. uiBatNum = LOWORD(wParam) - IDC_POWERSTATUSICON1 + 1;
  645. // Allow battery details only for present batteries.
  646. if ((g_pbs[uiBatNum]) &&
  647. (g_pbs[uiBatNum]->ulTag != BATTERY_TAG_INVALID)) {
  648. DialogBoxParam(g_hInstance,
  649. MAKEINTRESOURCE(IDD_BATDETAIL),
  650. hWnd,
  651. BatDetailDlgProc,
  652. (LPARAM)g_pbs[uiBatNum]);
  653. }
  654. break;
  655. }
  656. }
  657. break;
  658. case WM_DESTROYBATMETER:
  659. CleanupBatteryData();
  660. EndDialog(hWnd, wParam);
  661. break;
  662. case WM_DESTROY:
  663. CleanupBatteryData();
  664. break;
  665. case WM_DEVICECHANGE:
  666. #ifdef WINNT
  667. if ((wParam == DBT_DEVICEQUERYREMOVE) || (wParam == DBT_DEVICEREMOVECOMPLETE)) {
  668. if ( ((PDEV_BROADCAST_HANDLE)lParam)->dbch_devicetype == DBT_DEVTYP_HANDLE) {
  669. //
  670. // Find Device that got removed
  671. //
  672. pbsTemp = DEVICES;
  673. while (pbsTemp) {
  674. if (pbsTemp->hDevNotify == ((PDEV_BROADCAST_HANDLE)lParam)->dbch_hdevnotify) {
  675. break;
  676. }
  677. pbsTemp = pbsTemp->bsNext;
  678. }
  679. if (!pbsTemp) {
  680. break;
  681. }
  682. //
  683. // Close the handle to this device and release cached data.
  684. //
  685. RemoveBatteryStateDevice (pbsTemp);
  686. g_uiDriverCount--;
  687. g_uiBatCount = g_uiDriverCount;
  688. // Clear and rebuild g_pbs, the handy batttery number to pbs array.
  689. memset(&g_pbs, 0, sizeof(g_pbs));
  690. pbsTemp = &g_bs;
  691. for (i = 0; i <= g_uiBatCount; i++) {
  692. if (pbsTemp) {
  693. g_pbs[i] = pbsTemp;
  694. pbsTemp->ulBatNum = i;
  695. pbsTemp = pbsTemp->bsNext;
  696. }
  697. }
  698. // Refresh display
  699. for (i = 1; i <= NUM_BAT; i++) {
  700. for (j = 0; j < BAT_LAST; j++) {
  701. HideItem(g_hwndBatMeter, g_iMapBatNumToID[i][j]);
  702. }
  703. }
  704. g_bShowingMulti = SwitchDisplayMode (g_hwndBatMeter, g_bShowingMulti);
  705. if (g_bShowingMulti) {
  706. // Walk the bs list, and update all battery displays.
  707. WalkBatteryState(DEVICES,
  708. (WALKENUMPROC)UpdateBatMeterProc,
  709. g_hwndBatMeter,
  710. (LPARAM)g_bShowingMulti,
  711. (LPARAM)TRUE);
  712. }
  713. }
  714. }
  715. #else
  716. if (wParam == DBT_DEVICEQUERYREMOVE) {
  717. if (g_hwndBatMeter) {
  718. // Close all of the batteries.
  719. CleanupBatteryData();
  720. }
  721. }
  722. #endif
  723. return TRUE;
  724. case WM_HELP: // F1
  725. WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_ContextMenuHelpIDs);
  726. return TRUE;
  727. case WM_CONTEXTMENU: // right mouse click
  728. WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_ContextMenuHelpIDs);
  729. return TRUE;
  730. }
  731. return FALSE;
  732. }
  733. /*******************************************************************************
  734. *
  735. * GetBattIcon
  736. *
  737. * DESCRIPTION:
  738. *
  739. * PARAMETERS:
  740. *
  741. *******************************************************************************/
  742. HICON PASCAL GetBattIcon(
  743. HWND hWnd,
  744. UINT uIconID,
  745. HICON hIconCache,
  746. BOOL bWantBolt,
  747. UINT uiRes)
  748. {
  749. static HIMAGELIST hImgLst32, hImgLst16;
  750. HIMAGELIST hImgLst;
  751. int ImageIndex;
  752. // Destroy the old cached icon.
  753. if (hIconCache) {
  754. DestroyIcon(hIconCache);
  755. }
  756. // Don't put the charging bolt over the top of IDI_BATGONE.
  757. if (uIconID == IDI_BATGONE) {
  758. bWantBolt = FALSE;
  759. }
  760. // Use the transparency color must match that in the bit maps.
  761. if (!hImgLst32 || !hImgLst16) {
  762. hImgLst32 = ImageList_LoadImage(g_hInstance,
  763. MAKEINTRESOURCE(IDB_BATTS),
  764. 32, 0, RGB(255, 0, 255), IMAGE_BITMAP, 0);
  765. hImgLst16 = ImageList_LoadImage(g_hInstance,
  766. MAKEINTRESOURCE(IDB_BATTS16),
  767. 16, 0, RGB(255, 0, 255), IMAGE_BITMAP, 0);
  768. ImageList_SetOverlayImage(hImgLst32, IDI_CHARGE-FIRST_ICON_IMAGE, 1);
  769. ImageList_SetOverlayImage(hImgLst16, IDI_CHARGE-FIRST_ICON_IMAGE, 1);
  770. }
  771. if (uiRes == 32) {
  772. hImgLst = hImgLst32;
  773. }
  774. else {
  775. hImgLst = hImgLst16;
  776. }
  777. ImageIndex = uIconID - FIRST_ICON_IMAGE;
  778. if (bWantBolt) {
  779. return ImageList_GetIcon(hImgLst, ImageIndex, INDEXTOOVERLAYMASK(1));
  780. }
  781. else {
  782. return ImageList_GetIcon(hImgLst, ImageIndex, ILD_NORMAL);
  783. }
  784. }
  785. /*******************************************************************************
  786. *
  787. * CheckUpdateBatteryState
  788. *
  789. * DESCRIPTION:
  790. *
  791. * PARAMETERS:
  792. *
  793. *******************************************************************************/
  794. #define UPDATESTATUS_NOUPDATE 0
  795. #define UPDATESTATUS_UPDATE 1
  796. #define UPDATESTATUS_UPDATE_CHARGE 2
  797. UINT CheckUpdateBatteryState(
  798. PBATTERY_STATE pbs,
  799. BOOL bForceUpdate
  800. )
  801. {
  802. UINT uiRetVal = UPDATESTATUS_NOUPDATE;
  803. // Check to see if anything in the battery status has changed
  804. // since last time. If not then we have no work to do!
  805. if ((bForceUpdate) ||
  806. !((pbs->ulTag == pbs->ulLastTag) &&
  807. (pbs->ulBatLifePercent == pbs->ulLastBatLifePercent) &&
  808. (pbs->ulBatLifeTime == pbs->ulLastBatLifeTime) &&
  809. (pbs->ulPowerState == pbs->ulLastPowerState))) {
  810. uiRetVal = UPDATESTATUS_UPDATE;
  811. // Check for the special case where the charging state has changed.
  812. if ((pbs->ulPowerState & BATTERY_CHARGING) !=
  813. (pbs->ulLastPowerState & BATTERY_CHARGING)) {
  814. uiRetVal |= UPDATESTATUS_UPDATE_CHARGE;
  815. }
  816. // Copy current battery state to last.
  817. pbs->ulLastTag = pbs->ulTag;
  818. pbs->ulLastBatLifePercent = pbs->ulBatLifePercent;
  819. pbs->ulLastBatLifeTime = pbs->ulBatLifeTime;
  820. pbs->ulLastPowerState = pbs->ulPowerState;
  821. }
  822. return uiRetVal;
  823. }
  824. /*******************************************************************************
  825. *
  826. * MapBatInfoToIconID
  827. *
  828. * DESCRIPTION:
  829. * Map battery info to an Icon ID.
  830. *
  831. * PARAMETERS:
  832. * ulBatNum - Zero implies composite system state
  833. *
  834. *******************************************************************************/
  835. UINT MapBatInfoToIconID(PBATTERY_STATE pbs)
  836. {
  837. UINT uIconID = IDI_BATDEAD;
  838. if (!pbs->ulBatNum) {
  839. if (pbs->ulPowerState & BATTERY_POWER_ON_LINE) {
  840. return IDI_PLUG;
  841. }
  842. }
  843. else {
  844. if (pbs->ulTag == BATTERY_TAG_INVALID) {
  845. return IDI_BATGONE;
  846. }
  847. }
  848. if (pbs->ulPowerState & BATTERY_CRITICAL) {
  849. return IDI_BATDEAD;
  850. }
  851. if (pbs->ulBatLifePercent > 66) {
  852. uIconID = IDI_BATFULL;
  853. }
  854. else {
  855. if (pbs->ulBatLifePercent > 33) {
  856. uIconID = IDI_BATHALF;
  857. }
  858. else {
  859. if (pbs->ulBatLifePercent > 9) {
  860. uIconID = IDI_BATLOW;
  861. }
  862. }
  863. }
  864. return uIconID;
  865. }
  866. /*******************************************************************************
  867. *
  868. * DisplayIcon
  869. *
  870. * DESCRIPTION:
  871. *
  872. * PARAMETERS:
  873. *
  874. *******************************************************************************/
  875. void DisplayIcon(
  876. HWND hWnd,
  877. UINT uIconID,
  878. PBATTERY_STATE pbs,
  879. ULONG ulUpdateStatus
  880. )
  881. {
  882. BOOL bBolt;
  883. UINT uiMsg;
  884. // Only redraw the icon if it has changed OR
  885. // if it has gone from charging to not charging.
  886. if ((uIconID != pbs->uiIconIDcache) ||
  887. (ulUpdateStatus != UPDATESTATUS_NOUPDATE)) {
  888. pbs->uiIconIDcache = uIconID;
  889. bBolt = (pbs->ulPowerState & BATTERY_CHARGING);
  890. pbs->hIconCache = GetBattIcon(hWnd, uIconID, pbs->hIconCache, bBolt, 32);
  891. pbs->hIconCache16 = GetBattIcon(hWnd, uIconID, pbs->hIconCache16, bBolt, 16);
  892. if (pbs->ulBatNum) {
  893. uiMsg = BM_SETIMAGE;
  894. }
  895. else {
  896. uiMsg = STM_SETIMAGE;
  897. }
  898. SendDlgItemMessage(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_ICON],
  899. uiMsg, IMAGE_ICON, (LPARAM) pbs->hIconCache);
  900. ShowItem(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_ICON]);
  901. }
  902. }
  903. /*******************************************************************************
  904. *
  905. * UpdateBatMeterProc
  906. *
  907. * DESCRIPTION:
  908. * Updates the System and per battery UI elements if needed.
  909. *
  910. * PARAMETERS:
  911. *
  912. *******************************************************************************/
  913. BOOL UpdateBatMeterProc(
  914. PBATTERY_STATE pbs,
  915. HWND hWnd,
  916. LPARAM bShowMulti,
  917. LPARAM bForceUpdate
  918. )
  919. {
  920. UINT uIconID, uiHour, uiMin;
  921. LPTSTR lpsz, lpszRemaining;
  922. ULONG ulUpdateStatus;
  923. ulUpdateStatus = CheckUpdateBatteryState(pbs, (BOOL) bForceUpdate);
  924. // Make sure there is work to do.
  925. if (ulUpdateStatus == UPDATESTATUS_NOUPDATE) {
  926. return TRUE;
  927. }
  928. // Determine which icon to display.
  929. uIconID = MapBatInfoToIconID(pbs);
  930. DisplayIcon(hWnd, uIconID, pbs, ulUpdateStatus);
  931. // Are we looking for system power status ?
  932. if (!pbs->ulBatNum) {
  933. // Display the Current Power Source text
  934. lpsz = LoadDynamicString(((pbs->ulPowerState & BATTERY_POWER_ON_LINE) ?
  935. IDS_ACLINEONLINE : IDS_BATTERIES));
  936. DisplayFreeStr(hWnd, IDC_BATTERYLEVEL, lpsz, FREE_STR);
  937. if (pbs->ulBatLifePercent <= 100) {
  938. lpsz = LoadDynamicString(IDS_PERCENTREMAININGFORMAT,
  939. pbs->ulBatLifePercent);
  940. }
  941. else {
  942. lpsz = LoadDynamicString(IDS_UNKNOWN);
  943. }
  944. DisplayFreeStr(hWnd, IDC_REMAINING, lpsz, NO_FREE_STR);
  945. ShowHideItem(hWnd, IDC_CHARGING, pbs->ulPowerState & BATTERY_CHARGING);
  946. // Show and Update the PowerStatusBar only if in single battery mode and
  947. // there is al least one battery installed.
  948. if (!bShowMulti && g_uiBatCount) {
  949. SendDlgItemMessage(hWnd, IDC_POWERSTATUSBAR, PBM_SETPOS,
  950. (WPARAM) pbs->ulBatLifePercent, 0);
  951. lpsz = DisplayFreeStr(hWnd, IDC_BARPERCENT, lpsz, FREE_STR);
  952. }
  953. if (lpsz) {
  954. LocalFree(lpsz);
  955. }
  956. if (pbs->ulBatLifeTime != (UINT) -1) {
  957. uiHour = pbs->ulBatLifeTime / 3600;
  958. uiMin = (pbs->ulBatLifeTime % 3600) / 60;
  959. if (uiHour) {
  960. lpsz = LoadDynamicString(IDS_TIMEREMFORMATHOUR, uiHour, uiMin);
  961. }
  962. else {
  963. lpsz = LoadDynamicString(IDS_TIMEREMFORMATMIN, uiMin);
  964. }
  965. DisplayFreeStr(hWnd, IDC_TIMEREMAINING, lpsz, FREE_STR);
  966. ShowHideItem(hWnd, IDC_TOTALTIME, TRUE);
  967. }
  968. else {
  969. ShowHideItem(hWnd, IDC_TOTALTIME, FALSE);
  970. ShowHideItem(hWnd, IDC_TIMEREMAINING, FALSE);
  971. }
  972. }
  973. else {
  974. // Here when getting the power status of each individual battery
  975. // when in multi-battery display mode.
  976. lpsz = LoadDynamicString(IDS_BATNUM, pbs->ulBatNum);
  977. DisplayFreeStr(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_NUM],
  978. lpsz, FREE_STR);
  979. if (pbs->ulTag != BATTERY_TAG_INVALID) {
  980. if (pbs->ulPowerState & BATTERY_CHARGING) {
  981. lpsz = LoadDynamicString(IDS_BATTCHARGING);
  982. }
  983. else {
  984. lpsz = NULL;
  985. }
  986. lpszRemaining = LoadDynamicString(IDS_PERCENTREMAININGFORMAT,
  987. pbs->ulBatLifePercent);
  988. }
  989. else {
  990. lpsz = LoadDynamicString(IDS_NOT_PRESENT);
  991. lpszRemaining = NULL;
  992. }
  993. DisplayFreeStr(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_STATUS],
  994. lpsz, FREE_STR);
  995. DisplayFreeStr(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_REMAINING],
  996. lpszRemaining, FREE_STR);
  997. }
  998. return TRUE;
  999. }
  1000. /*******************************************************************************
  1001. *
  1002. * FreeBatteryDriverNames
  1003. *
  1004. * DESCRIPTION:
  1005. *
  1006. * PARAMETERS:
  1007. *
  1008. *******************************************************************************/
  1009. VOID FreeBatteryDriverNames(LPTSTR *lpszDriverNames)
  1010. {
  1011. UINT i;
  1012. // Free any old driver names.
  1013. for (i = 0; i < NUM_BAT; i++) {
  1014. if (lpszDriverNames[i]) {
  1015. LocalFree(lpszDriverNames[i]);
  1016. lpszDriverNames[i] = NULL;
  1017. }
  1018. }
  1019. }
  1020. /*******************************************************************************
  1021. *
  1022. * GetBatteryDriverNames
  1023. *
  1024. * DESCRIPTION:
  1025. *
  1026. * PARAMETERS:
  1027. *
  1028. *******************************************************************************/
  1029. UINT GetBatteryDriverNames(LPTSTR *lpszDriverNames)
  1030. {
  1031. UINT uiDriverCount, uiIndex;
  1032. DWORD dwReqSize;
  1033. HDEVINFO hDevInfo;
  1034. SP_INTERFACE_DEVICE_DATA InterfaceDevData;
  1035. PSP_INTERFACE_DEVICE_DETAIL_DATA pFuncClassDevData;
  1036. // Free any old driver names.
  1037. FreeBatteryDriverNames(lpszDriverNames);
  1038. uiDriverCount = 0;
  1039. #ifndef SIM_BATTERY
  1040. // Use the SETUPAPI.DLL interface to get the
  1041. // possible battery driver names.
  1042. hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVICE_BATTERY, NULL, NULL,
  1043. DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
  1044. if (hDevInfo != INVALID_HANDLE_VALUE) {
  1045. InterfaceDevData.cbSize = sizeof(SP_DEVINFO_DATA);
  1046. uiIndex = 0;
  1047. while (uiDriverCount < NUM_BAT) {
  1048. if (SetupDiEnumInterfaceDevice(hDevInfo,
  1049. 0,
  1050. (LPGUID)&GUID_DEVICE_BATTERY,
  1051. uiIndex,
  1052. &InterfaceDevData)) {
  1053. // Get the required size of the function class device data.
  1054. SetupDiGetInterfaceDeviceDetail(hDevInfo,
  1055. &InterfaceDevData,
  1056. NULL,
  1057. 0,
  1058. &dwReqSize,
  1059. NULL);
  1060. pFuncClassDevData = LocalAlloc(0, dwReqSize);
  1061. if (pFuncClassDevData != NULL) {
  1062. pFuncClassDevData->cbSize =
  1063. sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
  1064. if (SetupDiGetInterfaceDeviceDetail(hDevInfo,
  1065. &InterfaceDevData,
  1066. pFuncClassDevData,
  1067. dwReqSize,
  1068. &dwReqSize,
  1069. NULL)) {
  1070. dwReqSize = (lstrlen(pFuncClassDevData->DevicePath) + 1) * sizeof(TCHAR);
  1071. lpszDriverNames[uiDriverCount] = LocalAlloc(0, dwReqSize);
  1072. if (lpszDriverNames[uiDriverCount]) {
  1073. lstrcpyn(lpszDriverNames[uiDriverCount],
  1074. pFuncClassDevData->DevicePath,
  1075. dwReqSize);
  1076. uiDriverCount++;
  1077. }
  1078. }
  1079. else {
  1080. BATTRACE(("SetupDiGetInterfaceDeviceDetail, failed: %d", GetLastError()));
  1081. }
  1082. LocalFree(pFuncClassDevData);
  1083. }
  1084. } else {
  1085. if (ERROR_NO_MORE_ITEMS == GetLastError()) {
  1086. break;
  1087. }
  1088. else {
  1089. BATTRACE(("SetupDiEnumInterfaceDevice, failed: %d", GetLastError()));
  1090. }
  1091. }
  1092. uiIndex++;
  1093. }
  1094. SetupDiDestroyDeviceInfoList(hDevInfo);
  1095. }
  1096. else {
  1097. BATTRACE(("SetupDiGetClassDevs on GUID_DEVICE_BATTERY, failed: %d", GetLastError()));
  1098. }
  1099. #else
  1100. // Simulate batteries.
  1101. {
  1102. UINT i;
  1103. static UINT uiState = 1;
  1104. uiDriverCount = 0;
  1105. for (i = 0; i <= uiState; i++) {
  1106. lpszDriverNames[i] = LocalAlloc(0, STRSIZE(TEXT("SIMULATED_BATTERY_0")));
  1107. if (lpszDriverNames[i]) {
  1108. wsprintf(lpszDriverNames[i], TEXT("SIMULATED_BATTERY_%d"), i);
  1109. uiDriverCount += 1;
  1110. }
  1111. }
  1112. uiState++;
  1113. if (uiState >= NUM_BAT) {
  1114. uiState = 0;
  1115. }
  1116. }
  1117. #endif
  1118. return uiDriverCount;
  1119. }
  1120. /*******************************************************************************
  1121. *
  1122. * UpdateDriverList
  1123. *
  1124. * DESCRIPTION:
  1125. *
  1126. * PARAMETERS:
  1127. *
  1128. *******************************************************************************/
  1129. BOOL UpdateDriverList(
  1130. LPTSTR *lpszDriverNames,
  1131. UINT uiDriverCount
  1132. )
  1133. {
  1134. UINT i;
  1135. PBATTERY_STATE pbs;
  1136. // Walk the bs list, and remove any devices which aren't in pszDeviceNames.
  1137. WalkBatteryState(DEVICES,
  1138. (WALKENUMPROC)RemoveMissingProc,
  1139. NULL,
  1140. (LPARAM)g_lpszDriverNames,
  1141. (LPARAM)REMOVE_MISSING);
  1142. // Scan the pszDeviceNames list and add any devices which aren't in bs.
  1143. for (i = 0; i < uiDriverCount; i++) {
  1144. if (WalkBatteryState(DEVICES,
  1145. (WALKENUMPROC)FindNameProc,
  1146. NULL,
  1147. (LPARAM)g_lpszDriverNames[i],
  1148. (LPARAM)NULL)) {
  1149. #ifndef SIM_BATTERY
  1150. if (!AddBatteryStateDevice(g_lpszDriverNames[i], i + 1)) {
  1151. // We weren't able get minimal info from driver, dec the
  1152. // battery counts. g_uiBatCount should always be > 0.
  1153. if (--g_uiDriverCount) {;
  1154. g_uiBatCount--;
  1155. }
  1156. }
  1157. #else
  1158. SimAddBatteryStateDevice(g_lpszDriverNames[i], i + 1);
  1159. #endif
  1160. }
  1161. }
  1162. // Clear and rebuild g_pbs, the handy batttery number to pbs array.
  1163. memset(&g_pbs, 0, sizeof(g_pbs));
  1164. pbs = &g_bs;
  1165. for (i = 0; i <= g_uiBatCount; i++) {
  1166. if (pbs) {
  1167. g_pbs[i] = pbs;
  1168. pbs = pbs->bsNext;
  1169. }
  1170. }
  1171. return TRUE;
  1172. }