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.

558 lines
20 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1996
  4. *
  5. * TITLE: PWRSWTCH.C
  6. *
  7. * VERSION: 2.0
  8. *
  9. * AUTHOR: ReedB
  10. *
  11. * DATE: 17 Oct, 1996
  12. *
  13. * DESCRIPTION:
  14. * Support for Advanced page of PowerCfg.Cpl.
  15. *
  16. *******************************************************************************/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include <commctrl.h>
  22. #include <systrayp.h>
  23. #include <help.h>
  24. #include <powercfp.h>
  25. #include "powercfg.h"
  26. #include "pwrresid.h"
  27. #include "PwrMn_cs.h"
  28. /*******************************************************************************
  29. *
  30. * G L O B A L D A T A
  31. *
  32. *******************************************************************************/
  33. // This structure is filled in by the Power Policy Manager at CPL_INIT time.
  34. extern SYSTEM_POWER_CAPABILITIES g_SysPwrCapabilities;
  35. extern BOOL g_bRunningUnderNT;
  36. // Machine is currently capable of hibernate, managed by code in hibernat.c.
  37. extern UINT g_uiPwrActIDs[];
  38. extern UINT g_uiLidActIDs[];
  39. // A systary change requires PowerSchemeDlgProc re-init.
  40. extern BOOL g_bSystrayChange;
  41. // Persistant storage of this data is managed by POWRPROF.DLL API's.
  42. GLOBAL_POWER_POLICY g_gpp;
  43. // Show/hide UI state variables.
  44. DWORD g_dwShowPowerButtonUI;
  45. DWORD g_dwShowSleepButtonUI;
  46. DWORD g_dwShowLidUI;
  47. DWORD g_dwShowPwrButGrpUI;
  48. DWORD g_dwShowEnableSysTray;
  49. DWORD g_uiPasswordState;
  50. DWORD g_uiVideoDimState;
  51. // Static flags:
  52. UINT g_uiEnableSysTrayFlag = EnableSysTrayBatteryMeter;
  53. UINT g_uiEnablePWLogonFlag = EnablePasswordLogon;
  54. UINT g_uiEnableVideoDimDisplay = EnableVideoDimDisplay;
  55. // Indicies into combobox selections
  56. UINT g_uiDoNothing;
  57. UINT g_uiAskMeWhatToDo;
  58. UINT g_uiShutdown;
  59. // Global marking whether sheet is dirty
  60. BOOL g_bDirty;
  61. // Button policies dialog controls descriptions:
  62. #define NUM_BUTTON_POL_CONTROLS 10
  63. // Handy indicies into our g_pcButtonPol control array:
  64. #define ID_LIDCLOSETEXT 0
  65. #define ID_LIDCLOSEACTION 1
  66. #define ID_PWRBUTTONTEXT 2
  67. #define ID_PWRBUTACTION 3
  68. #define ID_SLPBUTTONTEXT 4
  69. #define ID_SLPBUTACTION 5
  70. #define ID_ENABLEMETER 6
  71. #define ID_PASSWORD 7
  72. #define ID_VIDEODIM 8
  73. #define ID_POWERBUTGROUP 9
  74. POWER_CONTROLS g_pcButtonPol[NUM_BUTTON_POL_CONTROLS] =
  75. {// Control ID Control Type Data Address Data Size Parameter Pointer Enable/Visible State Pointer
  76. IDC_LIDCLOSETEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowLidUI,
  77. IDC_LIDCLOSEACTION, COMBO_BOX, NULL, sizeof(g_gpp.user.LidCloseDc.Action), (LPDWORD)&g_gpp.user.LidCloseDc.Action, &g_dwShowLidUI,
  78. IDC_PWRBUTTONTEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowPowerButtonUI,
  79. IDC_PWRBUTACTION, COMBO_BOX, NULL, sizeof(g_gpp.user.PowerButtonDc.Action), (LPDWORD)&g_gpp.user.PowerButtonDc.Action, &g_dwShowPowerButtonUI,
  80. IDC_SLPBUTTONTEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowSleepButtonUI,
  81. IDC_SLPBUTACTION, COMBO_BOX, NULL, sizeof(g_gpp.user.SleepButtonDc.Action), (LPDWORD)&g_gpp.user.SleepButtonDc.Action, &g_dwShowSleepButtonUI,
  82. IDC_ENABLEMETER, CHECK_BOX, &g_gpp.user.GlobalFlags, sizeof(g_gpp.user.GlobalFlags), &g_uiEnableSysTrayFlag, &g_dwShowEnableSysTray,
  83. IDC_PASSWORD, CHECK_BOX, &g_gpp.user.GlobalFlags, sizeof(g_gpp.user.GlobalFlags), &g_uiEnablePWLogonFlag, &g_uiPasswordState,
  84. IDC_VIDEODIM, CHECK_BOX, &g_gpp.user.GlobalFlags, sizeof(g_gpp.user.GlobalFlags), &g_uiEnableVideoDimDisplay, &g_uiVideoDimState,
  85. IDC_POWERBUTGROUP, STATIC_TEXT, NULL, 0, NULL, &g_dwShowPwrButGrpUI,
  86. };
  87. // "Power Switches" Dialog Box (IDD_BUTTONPOLICY == 104) help array:
  88. const DWORD g_PowerSwitchHelpIDs[]=
  89. {
  90. IDC_OPTIONSGROUPBOX,IDH_COMM_GROUPBOX,
  91. IDC_POWERBUTGROUP, IDH_COMM_GROUPBOX,
  92. IDC_LIDCLOSEACTION, IDH_104_1301, // "Lid close action dropdown" (ComboBox)
  93. IDC_LIDCLOSETEXT, IDH_104_1301,
  94. IDC_PWRBUTACTION, IDH_104_1303, // "Power button action dropdown" (ComboBox)
  95. IDC_PWRBUTTONTEXT, IDH_104_1303,
  96. IDC_SLPBUTACTION, IDH_104_1304, // "Sleep button action dropdown" (ComboBox)
  97. IDC_SLPBUTTONTEXT, IDH_104_1304,
  98. IDC_ENABLEMETER, IDH_102_1203, // "&Show meter on taskbar." (Button)
  99. IDC_PASSWORD, IDH_107_1500, // "Prompt for &password when bringing computer out of standby." (Button)
  100. IDC_VIDEODIM, IDH_108_1503, // "&Dim display when running on batteries." (Button)
  101. IDI_PWRMNG, NO_HELP,
  102. IDC_NO_HELP_5, NO_HELP,
  103. 0, 0
  104. };
  105. void ActionEventCodeToSelection (HWND hwnd, int iDlgItem, const POWER_ACTION_POLICY *pPAP)
  106. {
  107. ULONG ulEventCode;
  108. DWORD dwSelection;
  109. // Special case PowerActionNone. This could be:
  110. // "Shut Down"
  111. // "Ask me what to do"
  112. // "Do nothing"
  113. if (pPAP->Action == PowerActionNone)
  114. {
  115. ulEventCode = pPAP->EventCode & (POWER_USER_NOTIFY_BUTTON | POWER_USER_NOTIFY_SHUTDOWN);
  116. if ((ulEventCode & POWER_USER_NOTIFY_SHUTDOWN) != 0)
  117. {
  118. dwSelection = g_uiShutdown;
  119. }
  120. else if ((ulEventCode & POWER_USER_NOTIFY_BUTTON) != 0)
  121. {
  122. dwSelection = g_uiAskMeWhatToDo;
  123. }
  124. else
  125. {
  126. dwSelection = g_uiDoNothing;
  127. }
  128. (LRESULT)SendDlgItemMessage(hwnd, iDlgItem, CB_SETCURSEL, dwSelection, 0);
  129. }
  130. }
  131. void SelectionToActionEventCode (HWND hwnd, int iDlgItem, DWORD dwMissingItems, POWER_ACTION_POLICY *pPAP)
  132. {
  133. ULONG ulEventCode;
  134. DWORD dwSelection;
  135. // Special case the "Power Switch" UI. Always turn off the POWER_USER_NOTIFY_POWER_BUTTON
  136. // and POWER_USER_NOTIFY_SLEEP_BUTTON flag because it doesn't mean anything for action
  137. // other than PowerActionNone. Turn it on for PowerActionNone otherwise the SAS
  138. // window will not get the message posted. The SAS window has the logic to check
  139. // the registry setting.
  140. pPAP->EventCode &= ~(POWER_USER_NOTIFY_BUTTON | POWER_USER_NOTIFY_SHUTDOWN | POWER_FORCE_TRIGGER_RESET);
  141. if (pPAP->Action == PowerActionNone)
  142. {
  143. dwSelection = (DWORD)SendDlgItemMessage(hwnd, iDlgItem, CB_GETCURSEL, 0, 0);
  144. // dwMissingItems is a special variable that's used SOLELY for the purpose of
  145. // getting the lid switch to work. The other switches have 5 options available:
  146. //
  147. // Do nothing
  148. // Ask me what to do
  149. // Sleep
  150. // Hibernate
  151. // Shut Down
  152. //
  153. // The lid switch doesn't allow "Ask me what to do" so all of the items get
  154. // shifted by one and the comparisons are wrong. What the lid switch selection
  155. // extractor passes in to this function is the "fudge factor" to get this right.
  156. // Note because "Do nothing" is always available there's no need to compromise
  157. // for it. Just keep doing the same old same old.
  158. if (dwSelection == g_uiDoNothing)
  159. {
  160. ulEventCode = POWER_FORCE_TRIGGER_RESET;
  161. }
  162. else if ((dwSelection + dwMissingItems) == g_uiAskMeWhatToDo)
  163. {
  164. ulEventCode = POWER_USER_NOTIFY_BUTTON;
  165. }
  166. else if ((dwSelection + dwMissingItems) == g_uiShutdown)
  167. {
  168. ulEventCode = POWER_USER_NOTIFY_SHUTDOWN;
  169. }
  170. else
  171. {
  172. ulEventCode = 0;
  173. }
  174. pPAP->EventCode |= ulEventCode;
  175. }
  176. }
  177. /*******************************************************************************
  178. *
  179. * SetAdvancedDlgProcData
  180. *
  181. * DESCRIPTION:
  182. * Set up the data pointers in g_pcButtonPol depending on hibernate state.
  183. * Set the data to the controls. If bPreserve is TRUE get the current
  184. * values UI values and restore them after updating the listboxes.
  185. *
  186. * PARAMETERS:
  187. *
  188. *******************************************************************************/
  189. VOID SetAdvancedDlgProcData(HWND hWnd, BOOL bRestoreCurrent)
  190. {
  191. UINT ii;
  192. UINT jj;
  193. // Set the state of the show/hide UI state variables.
  194. if (g_SysPwrCapabilities.SystemS1 ||
  195. g_SysPwrCapabilities.SystemS2 ||
  196. g_SysPwrCapabilities.SystemS3 ||
  197. (g_SysPwrCapabilities.SystemS4 &&
  198. g_SysPwrCapabilities.HiberFilePresent)) {
  199. int err;
  200. HKEY hPowerPolicy;
  201. DWORD Value;
  202. DWORD dwType ;
  203. DWORD dwSize ;
  204. g_uiPasswordState = CONTROL_ENABLE;
  205. //
  206. // Check for policy forcing the password always on
  207. //
  208. err = RegOpenKeyEx( HKEY_CURRENT_USER,
  209. POWER_POLICY_KEY,
  210. 0,
  211. KEY_READ,
  212. &hPowerPolicy );
  213. if (err == 0) {
  214. dwSize = sizeof(Value);
  215. err = RegQueryValueEx(hPowerPolicy,
  216. LOCK_ON_RESUME,
  217. NULL,
  218. &dwType,
  219. (LPBYTE)&Value,
  220. &dwSize);
  221. if ( (err == 0) && (dwType == REG_DWORD) && (Value != 0)) {
  222. g_uiPasswordState = CONTROL_DISABLE;
  223. g_gpp.user.GlobalFlags |= EnablePasswordLogon;
  224. }
  225. RegCloseKey( hPowerPolicy );
  226. }
  227. }
  228. else {
  229. g_uiPasswordState = CONTROL_HIDE;
  230. }
  231. if (bRestoreCurrent) {
  232. GetControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
  233. }
  234. //
  235. // Build the Action ID's for the Lid, Power Button and/or Sleep Button
  236. //
  237. ii=0;
  238. jj=0;
  239. g_uiLidActIDs[jj++] = IDS_DONOTHING;
  240. g_uiLidActIDs[jj++] = PowerActionNone;
  241. g_uiDoNothing = ii / 2;
  242. g_uiPwrActIDs[ii++] = IDS_DONOTHING;
  243. g_uiPwrActIDs[ii++] = PowerActionNone;
  244. g_uiAskMeWhatToDo = ii / 2;
  245. g_uiPwrActIDs[ii++] = IDS_PROMPT;
  246. g_uiPwrActIDs[ii++] = PowerActionNone;
  247. if (g_SysPwrCapabilities.SystemS1 ||
  248. g_SysPwrCapabilities.SystemS2 || g_SysPwrCapabilities.SystemS3) {
  249. g_uiPwrActIDs[ii++] = IDS_STANDBY;
  250. g_uiPwrActIDs[ii++] = PowerActionSleep;
  251. g_uiLidActIDs[jj++] = IDS_STANDBY;
  252. g_uiLidActIDs[jj++] = PowerActionSleep;
  253. }
  254. if (g_SysPwrCapabilities.HiberFilePresent) {
  255. g_uiPwrActIDs[ii++] = IDS_HIBERNATE;
  256. g_uiPwrActIDs[ii++] = PowerActionHibernate;
  257. g_uiLidActIDs[jj++] = IDS_HIBERNATE;
  258. g_uiLidActIDs[jj++] = PowerActionHibernate;
  259. }
  260. g_uiShutdown = ii / 2;
  261. g_uiPwrActIDs[ii++] = IDS_POWEROFF;
  262. g_uiPwrActIDs[ii++] = PowerActionNone;
  263. //g_uiLidActIDs[jj++] = IDS_POWEROFF; WinBug 5.1 #352752 - "Shutdown" isn't valid for
  264. //g_uiLidActIDs[jj++] = PowerActionNone; closing the lid.
  265. g_uiPwrActIDs[ii++] = 0;
  266. g_uiPwrActIDs[ii++] = 0;
  267. g_uiLidActIDs[jj++] = 0;
  268. g_uiLidActIDs[jj++] = 0;
  269. g_pcButtonPol[ID_LIDCLOSEACTION].lpvData = g_uiLidActIDs;
  270. g_pcButtonPol[ID_PWRBUTACTION].lpvData = g_uiPwrActIDs;
  271. g_pcButtonPol[ID_SLPBUTACTION].lpvData = g_uiPwrActIDs;
  272. // Special case PowerActionShutdownOff. This is no longer
  273. // supported in the UI. Convert this to "Shut Down".
  274. if (g_gpp.user.PowerButtonDc.Action == PowerActionShutdownOff)
  275. {
  276. g_gpp.user.PowerButtonDc.Action = PowerActionNone;
  277. g_gpp.user.PowerButtonDc.EventCode = POWER_USER_NOTIFY_SHUTDOWN;
  278. g_bDirty = TRUE;
  279. }
  280. if (g_gpp.user.SleepButtonDc.Action == PowerActionShutdownOff)
  281. {
  282. g_gpp.user.SleepButtonDc.Action = PowerActionNone;
  283. g_gpp.user.SleepButtonDc.EventCode = POWER_USER_NOTIFY_SHUTDOWN;
  284. g_bDirty = TRUE;
  285. }
  286. // Map power actions to allowed UI values.
  287. MapPwrAct(&g_gpp.user.LidCloseDc.Action, TRUE);
  288. MapPwrAct(&g_gpp.user.PowerButtonDc.Action, TRUE);
  289. MapPwrAct(&g_gpp.user.SleepButtonDc.Action, TRUE);
  290. // Only update the list boxes.
  291. SetControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
  292. // Map action and event code group to combobox selection.
  293. ActionEventCodeToSelection(hWnd, IDC_PWRBUTACTION, &g_gpp.user.PowerButtonDc);
  294. ActionEventCodeToSelection(hWnd, IDC_SLPBUTACTION, &g_gpp.user.SleepButtonDc);
  295. ActionEventCodeToSelection(hWnd, IDC_LIDCLOSEACTION, &g_gpp.user.LidCloseDc);
  296. }
  297. /*******************************************************************************
  298. *
  299. * InitAdvancedDlg
  300. *
  301. * DESCRIPTION:
  302. *
  303. * PARAMETERS:
  304. *
  305. *******************************************************************************/
  306. BOOLEAN InitAdvancedDlg(HWND hWnd)
  307. {
  308. // Start off with the page not dirty.
  309. g_bDirty = FALSE;
  310. // If we can't read the global power policies hide
  311. // the controls on this page.
  312. if (!GetGlobalPwrPolicy(&g_gpp)) {
  313. HideControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
  314. return TRUE;
  315. }
  316. // Get the enable systray icon mask based on AC online/offline.
  317. g_uiEnableSysTrayFlag = EnableSysTrayBatteryMeter;
  318. if (g_SysPwrCapabilities.VideoDimPresent) {
  319. g_uiVideoDimState = CONTROL_ENABLE;
  320. }
  321. else {
  322. g_uiVideoDimState = CONTROL_HIDE;
  323. }
  324. g_dwShowEnableSysTray = CONTROL_ENABLE;
  325. g_dwShowPwrButGrpUI = CONTROL_HIDE;
  326. if (g_SysPwrCapabilities.LidPresent) {
  327. g_dwShowLidUI = CONTROL_ENABLE;
  328. g_dwShowPwrButGrpUI = CONTROL_ENABLE;
  329. }
  330. else {
  331. g_dwShowLidUI = CONTROL_HIDE;
  332. }
  333. //
  334. // Don't show the Power Button if S5 is not supported on the system
  335. //
  336. if (g_SysPwrCapabilities.PowerButtonPresent && g_SysPwrCapabilities.SystemS5) {
  337. g_dwShowPowerButtonUI = CONTROL_ENABLE;
  338. g_dwShowPwrButGrpUI = CONTROL_ENABLE;
  339. }
  340. else {
  341. g_dwShowPowerButtonUI = CONTROL_HIDE;
  342. }
  343. //
  344. // Sleep Button - Don't show the sleep button if there are not any actions.
  345. //
  346. if (g_SysPwrCapabilities.SleepButtonPresent &&
  347. (g_SysPwrCapabilities.SystemS1 ||
  348. g_SysPwrCapabilities.SystemS2 ||
  349. g_SysPwrCapabilities.SystemS3 ||
  350. (g_SysPwrCapabilities.SystemS4 && g_SysPwrCapabilities.HiberFilePresent)))
  351. {
  352. g_dwShowSleepButtonUI = CONTROL_ENABLE;
  353. g_dwShowPwrButGrpUI = CONTROL_ENABLE;
  354. }
  355. else {
  356. g_dwShowSleepButtonUI = CONTROL_HIDE;
  357. }
  358. SetAdvancedDlgProcData(hWnd, FALSE);
  359. // If we can't write the global power policies disable
  360. // the controls this page.
  361. if (!WriteGlobalPwrPolicyReport(hWnd, &g_gpp, FALSE))
  362. {
  363. DisableControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
  364. }
  365. return TRUE;
  366. }
  367. /*******************************************************************************
  368. *
  369. * P U B L I C E N T R Y P O I N T S
  370. *
  371. *******************************************************************************/
  372. /*******************************************************************************
  373. *
  374. * AdvancedDlgProc
  375. *
  376. * DESCRIPTION:
  377. *
  378. * PARAMETERS:
  379. *
  380. *******************************************************************************/
  381. INT_PTR CALLBACK AdvancedDlgProc(
  382. HWND hWnd,
  383. UINT uMsg,
  384. WPARAM wParam,
  385. LPARAM lParam
  386. )
  387. {
  388. NMHDR FAR *lpnm;
  389. UINT uiID;
  390. switch (uMsg)
  391. {
  392. case WM_INITDIALOG:
  393. return InitAdvancedDlg(hWnd);
  394. #ifdef WINNT
  395. case WM_CHILDACTIVATE:
  396. // Reinitialize since the hibernate tab may have changed
  397. // the hibernate state, NT only.
  398. SetAdvancedDlgProcData(hWnd, TRUE);
  399. break;
  400. #endif
  401. case WM_NOTIFY:
  402. lpnm = (NMHDR FAR *)lParam;
  403. switch(lpnm->code)
  404. {
  405. case PSN_APPLY:
  406. // Fetch data from dialog controls.
  407. if (g_bDirty)
  408. {
  409. GetControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
  410. // Map combobox selection to action and event code group.
  411. SelectionToActionEventCode(hWnd, IDC_PWRBUTACTION, 0, &g_gpp.user.PowerButtonDc);
  412. SelectionToActionEventCode(hWnd, IDC_SLPBUTACTION, 0, &g_gpp.user.SleepButtonDc);
  413. SelectionToActionEventCode(hWnd, IDC_LIDCLOSEACTION, 1, &g_gpp.user.LidCloseDc);
  414. g_gpp.user.LidCloseAc.Action =
  415. g_gpp.user.LidCloseDc.Action;
  416. g_gpp.user.LidCloseAc.EventCode =
  417. g_gpp.user.LidCloseDc.EventCode;
  418. g_gpp.user.PowerButtonAc.Action =
  419. g_gpp.user.PowerButtonDc.Action;
  420. g_gpp.user.PowerButtonAc.EventCode =
  421. g_gpp.user.PowerButtonDc.EventCode;
  422. g_gpp.user.SleepButtonAc.Action =
  423. g_gpp.user.SleepButtonDc.Action;
  424. g_gpp.user.SleepButtonAc.EventCode =
  425. g_gpp.user.SleepButtonDc.EventCode;
  426. if (WriteGlobalPwrPolicyReport(hWnd, &g_gpp, TRUE))
  427. {
  428. GetActivePwrScheme(&uiID);
  429. SetActivePwrSchemeReport(hWnd, uiID, &g_gpp, NULL);
  430. // Enable or disable battery meter service on systray.
  431. SysTray_EnableService(STSERVICE_POWER,
  432. g_gpp.user.GlobalFlags &
  433. g_uiEnableSysTrayFlag);
  434. g_bDirty = FALSE;
  435. }
  436. }
  437. break;
  438. case PSN_SETACTIVE:
  439. // Hibernate page may have changed the hibernate state,
  440. // reinitialize the dependent part of Advanced page.
  441. SetAdvancedDlgProcData(hWnd, TRUE);
  442. break;
  443. }
  444. break;
  445. case WM_COMMAND:
  446. switch (LOWORD(wParam)) {
  447. case IDC_SLPBUTACTION:
  448. case IDC_PWRBUTACTION:
  449. case IDC_LIDCLOSEACTION:
  450. if (HIWORD(wParam) == LBN_SELCHANGE) {
  451. // Let parent know something changed.
  452. MarkSheetDirty(hWnd, &g_bDirty);
  453. }
  454. break;
  455. case IDC_VIDEODIM:
  456. case IDC_PASSWORD:
  457. case IDC_ENABLEMETER:
  458. // Enable the parent dialog Apply button on change.
  459. MarkSheetDirty(hWnd, &g_bDirty);
  460. break;
  461. }
  462. break;
  463. case PCWM_NOTIFYPOWER:
  464. // Notification from systray, user has changed a PM UI setting.
  465. g_bSystrayChange = TRUE;
  466. break;
  467. case WM_HELP: // F1
  468. WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_PowerSwitchHelpIDs);
  469. return TRUE;
  470. case WM_CONTEXTMENU: // right mouse click
  471. WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_PowerSwitchHelpIDs);
  472. return TRUE;
  473. }
  474. return FALSE;
  475. }