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.

476 lines
14 KiB

  1. /*++
  2. Copyright (C) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. devpopg.cpp
  5. Abstract:
  6. This module implements CDevicePowerMgmtPage -- device power management
  7. property page
  8. Author:
  9. William Hsieh (williamh) created
  10. Revision History:
  11. --*/
  12. // devdrvpg.cpp : implementation file
  13. //
  14. #include "devmgr.h"
  15. #include "devpopg.h"
  16. extern "C" {
  17. #include <initguid.h>
  18. #include <wdmguid.h>
  19. #include <devguid.h>
  20. }
  21. //
  22. // help topic ids
  23. //
  24. const DWORD g_a15HelpIDs[]=
  25. {
  26. IDC_DEVPOWER_DESC, IDH_DISABLEHELP,
  27. IDC_DEVPOWER_ICON, IDH_DISABLEHELP,
  28. IDC_DEVPOWER_WAKEENABLE, IDH_DEVMGR_PWRMGR_WAKEENABLE,
  29. IDC_DEVPOWER_MGMT_WAKEENABLE, IDH_DEVMGR_PWRMGR_MGMT_WAKEENABLE,
  30. IDC_DEVPOWER_DEVICEENABLE, IDH_DEVMGR_PWRMGR_DEVICEENABLE,
  31. IDC_DEVPOWER_MESSAGE, IDH_DISABLEHELP,
  32. 0,0
  33. };
  34. BOOL
  35. CDevicePowerMgmtPage::OnInitDialog(
  36. LPPROPSHEETPAGE ppsp
  37. )
  38. {
  39. //
  40. // Notify CPropSheetData about the page creation
  41. // the controls will be initialize in UpdateControls virtual function.
  42. //
  43. m_pDevice->m_psd.PageCreateNotify(m_hDlg);
  44. BOOLEAN Enabled;
  45. //
  46. // First see if the device is able to wake the system
  47. //
  48. if (m_poWakeEnable.Open(m_pDevice->GetDeviceID())) {
  49. m_poWakeEnable.Get(Enabled);
  50. ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE), BM_SETCHECK,
  51. Enabled ? BST_CHECKED : BST_UNCHECKED, 0);
  52. EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), Enabled);
  53. } else {
  54. EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
  55. ShowWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  56. }
  57. //
  58. // See if the device can be turned off to save power
  59. //
  60. if (m_poShutdownEnable.Open(m_pDevice->GetDeviceID())) {
  61. m_poShutdownEnable.Get(Enabled);
  62. ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE), BM_SETCHECK,
  63. Enabled ? BST_CHECKED : BST_UNCHECKED, 0);
  64. } else {
  65. EnableWindow(GetControl(IDC_DEVPOWER_DEVICEENABLE), FALSE);
  66. }
  67. //
  68. // Special network card code.
  69. //
  70. GUID ClassGuid;
  71. m_pDevice->ClassGuid(ClassGuid);
  72. if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_NET)) {
  73. if (m_poWakeMgmtEnable.Open(m_pDevice->GetDeviceID())) {
  74. m_poWakeMgmtEnable.Get(Enabled);
  75. ::SendMessage(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), BM_SETCHECK,
  76. Enabled ? BST_CHECKED : BST_UNCHECKED, 0);
  77. }
  78. //
  79. // This is a special case for network class devices. Wake on Lan will
  80. // only work if the device is enabled for power management. So, if the
  81. // user unchecks the 'power manage this device' then we need to disable
  82. // the WOL and management stations controls.
  83. //
  84. if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
  85. BM_GETCHECK, 0, 0) ) {
  86. if (m_poWakeEnable.IsOpened()) {
  87. ::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), TRUE);
  88. }
  89. if (m_poWakeMgmtEnable.IsOpened()) {
  90. //
  91. // The 'allow management stations to bring the computer out of standby'
  92. // option is only allowed if the 'Allow this device to bring the computer
  93. // out of standby' option is checked.
  94. //
  95. if (m_poWakeEnable.IsOpened() &&
  96. (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  97. BM_GETCHECK, 0, 0))) {
  98. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
  99. } else {
  100. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  101. }
  102. }
  103. } else {
  104. ::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
  105. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  106. }
  107. } else {
  108. ShowWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  109. EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  110. }
  111. return CPropSheetPage::OnInitDialog(ppsp);
  112. }
  113. BOOL
  114. CDevicePowerMgmtPage::OnCommand(
  115. WPARAM wParam,
  116. LPARAM lParam
  117. )
  118. {
  119. switch (LOWORD(wParam)) {
  120. case IDC_DEVPOWER_WAKEENABLE:
  121. if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  122. BM_GETCHECK, 0, 0) ) {
  123. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
  124. } else {
  125. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  126. }
  127. break;
  128. case IDC_DEVPOWER_DEVICEENABLE:
  129. //
  130. // This is a special case for network class devices. Wake on Lan will
  131. // only work if the device is enabled for power management. So, if the
  132. // user unchecks the 'power manage this device' then we need to disable
  133. // the WOL and management stations controls.
  134. //
  135. GUID ClassGuid;
  136. m_pDevice->ClassGuid(ClassGuid);
  137. if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_NET)) {
  138. if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
  139. BM_GETCHECK, 0, 0) ) {
  140. if (m_poWakeEnable.IsOpened()) {
  141. ::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), TRUE);
  142. }
  143. if (m_poWakeMgmtEnable.IsOpened()) {
  144. //
  145. // The 'allow management stations to bring the computer out of standby'
  146. // option is only allowed if the 'Allow this device to bring the computer
  147. // out of standby' option is checked.
  148. //
  149. if (m_poWakeEnable.IsOpened() &&
  150. (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  151. BM_GETCHECK, 0, 0))) {
  152. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
  153. } else {
  154. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  155. }
  156. }
  157. } else {
  158. ::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
  159. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  160. }
  161. }
  162. break;
  163. }
  164. return FALSE;
  165. }
  166. //
  167. // This function saves the settings(if any)
  168. //
  169. BOOL
  170. CDevicePowerMgmtPage::OnApply()
  171. {
  172. BOOLEAN Enabled;
  173. if (m_poWakeEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_WAKEENABLE))) {
  174. Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  175. BM_GETCHECK, 0, 0);
  176. m_poWakeEnable.Set(Enabled);
  177. }
  178. if (m_poWakeMgmtEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE))) {
  179. Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE),
  180. BM_GETCHECK, 0, 0);
  181. m_poWakeMgmtEnable.Set(Enabled);
  182. }
  183. if (m_poShutdownEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_DEVICEENABLE))) {
  184. Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
  185. BM_GETCHECK, 0, 0);
  186. m_poShutdownEnable.Set(Enabled);
  187. }
  188. return FALSE;
  189. }
  190. //
  191. // This function refreshes every control in the dialog. It may be called
  192. // when the dialog is being initialized
  193. //
  194. void
  195. CDevicePowerMgmtPage::UpdateControls(
  196. LPARAM lParam
  197. )
  198. {
  199. if (lParam) {
  200. m_pDevice = (CDevice*) lParam;
  201. }
  202. try {
  203. //
  204. // Calling PropertyChanged() will update the display name for the device. We need
  205. // to do this in case a 3rd party property sheet did something that could change
  206. // the device's display name.
  207. //
  208. m_pDevice->PropertyChanged();
  209. HICON hIconOld;
  210. m_IDCicon = IDC_DEVPOWER_ICON; // Save for cleanup in OnDestroy.
  211. hIconOld = (HICON)SendDlgItemMessage(m_hDlg, IDC_DEVPOWER_ICON, STM_SETICON,
  212. (WPARAM)(m_pDevice->LoadClassIcon()),
  213. 0
  214. );
  215. if (hIconOld) {
  216. DestroyIcon(hIconOld);
  217. }
  218. SetDlgItemText(m_hDlg, IDC_DEVPOWER_DESC, m_pDevice->GetDisplayName());
  219. //
  220. // Get any power message that the class installer might want to display
  221. //
  222. SP_POWERMESSAGEWAKE_PARAMS pmp;
  223. DWORD RequiredSize;
  224. pmp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  225. pmp.ClassInstallHeader.InstallFunction = DIF_POWERMESSAGEWAKE;
  226. pmp.PowerMessageWake[0] = TEXT('\0');
  227. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  228. &pmp.ClassInstallHeader,
  229. sizeof(pmp)
  230. );
  231. //
  232. // If the class installer returns NO_ERROR and there is text to display in the
  233. // PowerMessageWake field of the SP_POWERMESSAGEWAKE_PARAMS structure then display
  234. // the text.
  235. //
  236. if ((m_pDevice->m_pMachine->DiCallClassInstaller(DIF_POWERMESSAGEWAKE, *m_pDevice)) &&
  237. (m_pDevice->m_pMachine->DiGetClassInstallParams(*m_pDevice,
  238. &pmp.ClassInstallHeader,
  239. sizeof(pmp),
  240. &RequiredSize)) &&
  241. (pmp.PowerMessageWake[0] != TEXT('\0'))) {
  242. SetDlgItemText(m_hDlg, IDC_DEVPOWER_MESSAGE, pmp.PowerMessageWake);
  243. }
  244. } catch (CMemoryException* e) {
  245. e->Delete();
  246. // report memory error
  247. MsgBoxParam(m_hDlg, 0, 0, 0);
  248. }
  249. }
  250. BOOL
  251. CDevicePowerMgmtPage::OnHelp(
  252. LPHELPINFO pHelpInfo
  253. )
  254. {
  255. WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP,
  256. (ULONG_PTR)g_a15HelpIDs);
  257. return FALSE;
  258. }
  259. BOOL
  260. CDevicePowerMgmtPage::OnContextMenu(
  261. HWND hWnd,
  262. WORD xPos,
  263. WORD yPos
  264. )
  265. {
  266. WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU,
  267. (ULONG_PTR)g_a15HelpIDs);
  268. return FALSE;
  269. }
  270. //
  271. // This function enables/disables the device power capability
  272. // INPUT:
  273. // fEnable -- TRUE to enable
  274. // -- FALSE to disable
  275. // OUTPUT:
  276. // TRUE if the state is set
  277. // FALSE if the state is not set.
  278. BOOL
  279. CPowerEnable::Set(
  280. BOOLEAN fEnable
  281. )
  282. {
  283. if (IsOpened()) {
  284. DWORD Error;
  285. BOOLEAN fNewValue = fEnable;
  286. Error = WmiSetSingleInstance(m_hWmiBlock, m_DevInstId, m_Version,
  287. sizeof(fNewValue), &fNewValue);
  288. //
  289. // Get the value back to see if the change is really succeeded.
  290. //
  291. if (ERROR_SUCCESS == Error && Get(fNewValue) && fNewValue == fEnable) {
  292. return TRUE;
  293. }
  294. }
  295. return FALSE;
  296. }
  297. BOOL
  298. CPowerEnable::Get(
  299. BOOLEAN& fEnable
  300. )
  301. {
  302. fEnable = FALSE;
  303. if (IsOpened()) {
  304. ULONG Size = m_WmiInstDataSize;
  305. DWORD Error;
  306. Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &Size, m_pWmiInstData);
  307. if (ERROR_SUCCESS == Error && Size == m_WmiInstDataSize &&
  308. m_DataBlockSize == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->SizeDataBlock &&
  309. m_Version == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->WnodeHeader.Version) {
  310. fEnable = *((BOOLEAN*)(m_pWmiInstData + ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->DataBlockOffset));
  311. return TRUE;
  312. }
  313. }
  314. return FALSE;
  315. }
  316. //
  317. // Function to open the wmi block.
  318. // INPUT:
  319. // DeviceId -- the device id
  320. // OUTPUT:
  321. // TRUE if the device can be turned off
  322. // FALSE if the device can not be turned off.
  323. BOOL
  324. CPowerEnable::Open(
  325. LPCTSTR DeviceId
  326. )
  327. {
  328. if (!DeviceId) {
  329. return FALSE;
  330. }
  331. //
  332. // Do nothing if already opened
  333. //
  334. if (IsOpened()) {
  335. return TRUE;
  336. }
  337. int len = lstrlen(DeviceId);
  338. if (len >= ARRAYLEN(m_DevInstId) - 2) {
  339. return FALSE;
  340. }
  341. WmiDevInstToInstanceName(m_DevInstId, len+3, (PTCHAR)DeviceId, 0);
  342. ULONG Error;
  343. Error = WmiOpenBlock(&m_wmiGuid, 0, &m_hWmiBlock);
  344. if (ERROR_SUCCESS == Error) {
  345. //
  346. // Get the required block size.
  347. //
  348. ULONG BufferSize = 0;
  349. Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &BufferSize, NULL);
  350. if (BufferSize && Error == ERROR_INSUFFICIENT_BUFFER) {
  351. //
  352. // The device does support the GUID, remember the size
  353. // and allocate a buffer to the data block.
  354. //
  355. m_WmiInstDataSize = BufferSize;
  356. m_pWmiInstData = new BYTE[BufferSize];
  357. if (m_pWmiInstData) {
  358. Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &BufferSize, m_pWmiInstData);
  359. } else {
  360. Error = ERROR_NOT_ENOUGH_MEMORY;
  361. }
  362. if (ERROR_SUCCESS == Error &&
  363. m_DataBlockSize == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->SizeDataBlock) {
  364. //
  365. // Remember the version
  366. //
  367. m_Version = ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->WnodeHeader.Version;
  368. return TRUE;
  369. }
  370. }
  371. Close();
  372. }
  373. SetLastError(Error);
  374. return FALSE;
  375. }