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.

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