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.

475 lines
14 KiB

  1. /*++
  2. Copyright (C) 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. UNREFERENCED_PARAMETER(lParam);
  120. switch (LOWORD(wParam)) {
  121. case IDC_DEVPOWER_WAKEENABLE:
  122. if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  123. BM_GETCHECK, 0, 0) ) {
  124. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
  125. } else {
  126. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  127. }
  128. break;
  129. case IDC_DEVPOWER_DEVICEENABLE:
  130. //
  131. // This is a special case for network class devices. Wake on Lan will
  132. // only work if the device is enabled for power management. So, if the
  133. // user unchecks the 'power manage this device' then we need to disable
  134. // the WOL and management stations controls.
  135. //
  136. GUID ClassGuid;
  137. m_pDevice->ClassGuid(ClassGuid);
  138. if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_NET)) {
  139. if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
  140. BM_GETCHECK, 0, 0) ) {
  141. if (m_poWakeEnable.IsOpened()) {
  142. ::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), TRUE);
  143. }
  144. if (m_poWakeMgmtEnable.IsOpened()) {
  145. //
  146. // The 'allow management stations to bring the computer out of standby'
  147. // option is only allowed if the 'Allow this device to bring the computer
  148. // out of standby' option is checked.
  149. //
  150. if (m_poWakeEnable.IsOpened() &&
  151. (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  152. BM_GETCHECK, 0, 0))) {
  153. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
  154. } else {
  155. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  156. }
  157. }
  158. } else {
  159. ::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
  160. ::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
  161. }
  162. }
  163. break;
  164. }
  165. return FALSE;
  166. }
  167. //
  168. // This function saves the settings(if any)
  169. //
  170. BOOL
  171. CDevicePowerMgmtPage::OnApply()
  172. {
  173. BOOLEAN Enabled;
  174. if (m_poWakeEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_WAKEENABLE))) {
  175. Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
  176. BM_GETCHECK, 0, 0);
  177. m_poWakeEnable.Set(Enabled);
  178. }
  179. if (m_poWakeMgmtEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE))) {
  180. Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE),
  181. BM_GETCHECK, 0, 0);
  182. m_poWakeMgmtEnable.Set(Enabled);
  183. }
  184. if (m_poShutdownEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_DEVICEENABLE))) {
  185. Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
  186. BM_GETCHECK, 0, 0);
  187. m_poShutdownEnable.Set(Enabled);
  188. }
  189. return FALSE;
  190. }
  191. //
  192. // This function refreshes every control in the dialog. It may be called
  193. // when the dialog is being initialized
  194. //
  195. void
  196. CDevicePowerMgmtPage::UpdateControls(
  197. LPARAM lParam
  198. )
  199. {
  200. if (lParam) {
  201. m_pDevice = (CDevice*) lParam;
  202. }
  203. try {
  204. //
  205. // Calling PropertyChanged() will update the display name for the device. We need
  206. // to do this in case a 3rd party property sheet did something that could change
  207. // the device's display name.
  208. //
  209. m_pDevice->PropertyChanged();
  210. HICON hIconOld;
  211. m_IDCicon = IDC_DEVPOWER_ICON; // Save for cleanup in OnDestroy.
  212. hIconOld = (HICON)SendDlgItemMessage(m_hDlg, IDC_DEVPOWER_ICON, STM_SETICON,
  213. (WPARAM)(m_pDevice->LoadClassIcon()),
  214. 0
  215. );
  216. if (hIconOld) {
  217. DestroyIcon(hIconOld);
  218. }
  219. SetDlgItemText(m_hDlg, IDC_DEVPOWER_DESC, m_pDevice->GetDisplayName());
  220. //
  221. // Get any power message that the class installer might want to display
  222. //
  223. SP_POWERMESSAGEWAKE_PARAMS pmp;
  224. DWORD RequiredSize;
  225. pmp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  226. pmp.ClassInstallHeader.InstallFunction = DIF_POWERMESSAGEWAKE;
  227. pmp.PowerMessageWake[0] = TEXT('\0');
  228. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  229. &pmp.ClassInstallHeader,
  230. sizeof(pmp)
  231. );
  232. //
  233. // If the class installer returns NO_ERROR and there is text to display in the
  234. // PowerMessageWake field of the SP_POWERMESSAGEWAKE_PARAMS structure then display
  235. // the text.
  236. //
  237. if ((m_pDevice->m_pMachine->DiCallClassInstaller(DIF_POWERMESSAGEWAKE, *m_pDevice)) &&
  238. (m_pDevice->m_pMachine->DiGetClassInstallParams(*m_pDevice,
  239. &pmp.ClassInstallHeader,
  240. sizeof(pmp),
  241. &RequiredSize)) &&
  242. (pmp.PowerMessageWake[0] != TEXT('\0'))) {
  243. SetDlgItemText(m_hDlg, IDC_DEVPOWER_MESSAGE, pmp.PowerMessageWake);
  244. }
  245. } catch (CMemoryException* e) {
  246. e->Delete();
  247. // report memory error
  248. MsgBoxParam(m_hDlg, 0, 0, 0);
  249. }
  250. }
  251. BOOL
  252. CDevicePowerMgmtPage::OnHelp(
  253. LPHELPINFO pHelpInfo
  254. )
  255. {
  256. WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP,
  257. (ULONG_PTR)g_a15HelpIDs);
  258. return FALSE;
  259. }
  260. BOOL
  261. CDevicePowerMgmtPage::OnContextMenu(
  262. HWND hWnd,
  263. WORD xPos,
  264. WORD yPos
  265. )
  266. {
  267. UNREFERENCED_PARAMETER(xPos);
  268. UNREFERENCED_PARAMETER(yPos);
  269. WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU,
  270. (ULONG_PTR)g_a15HelpIDs);
  271. return FALSE;
  272. }
  273. //
  274. // This function enables/disables the device power capability
  275. // INPUT:
  276. // fEnable -- TRUE to enable
  277. // -- FALSE to disable
  278. // OUTPUT:
  279. // TRUE if the state is set
  280. // FALSE if the state is not set.
  281. BOOL
  282. CPowerEnable::Set(
  283. BOOLEAN fEnable
  284. )
  285. {
  286. if (IsOpened()) {
  287. DWORD Error;
  288. BOOLEAN fNewValue = fEnable;
  289. Error = WmiSetSingleInstance(m_hWmiBlock, m_DevInstId, m_Version,
  290. sizeof(fNewValue), &fNewValue);
  291. //
  292. // Get the value back to see if the change is really succeeded.
  293. //
  294. if (ERROR_SUCCESS == Error && Get(fNewValue) && fNewValue == fEnable) {
  295. return TRUE;
  296. }
  297. }
  298. return FALSE;
  299. }
  300. BOOL
  301. CPowerEnable::Get(
  302. BOOLEAN& fEnable
  303. )
  304. {
  305. fEnable = FALSE;
  306. if (IsOpened()) {
  307. ULONG Size = m_WmiInstDataSize;
  308. DWORD Error;
  309. Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &Size, m_pWmiInstData);
  310. if (ERROR_SUCCESS == Error && Size == m_WmiInstDataSize &&
  311. m_DataBlockSize == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->SizeDataBlock &&
  312. m_Version == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->WnodeHeader.Version) {
  313. fEnable = *((BOOLEAN*)(m_pWmiInstData + ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->DataBlockOffset));
  314. return TRUE;
  315. }
  316. }
  317. return FALSE;
  318. }
  319. //
  320. // Function to open the wmi block.
  321. // INPUT:
  322. // DeviceId -- the device id
  323. // OUTPUT:
  324. // TRUE if the device can be turned off
  325. // FALSE if the device can not be turned off.
  326. BOOL
  327. CPowerEnable::Open(
  328. LPCTSTR DeviceId
  329. )
  330. {
  331. if (!DeviceId) {
  332. return FALSE;
  333. }
  334. //
  335. // Do nothing if already opened
  336. //
  337. if (IsOpened()) {
  338. return TRUE;
  339. }
  340. if (lstrlen(DeviceId) >= ARRAYLEN(m_DevInstId) - 2) {
  341. return FALSE;
  342. }
  343. WmiDevInstToInstanceName(m_DevInstId, ARRAYLEN(m_DevInstId), (PTCHAR)DeviceId, 0);
  344. ULONG Error;
  345. Error = WmiOpenBlock(&m_wmiGuid, 0, &m_hWmiBlock);
  346. if (ERROR_SUCCESS == Error) {
  347. //
  348. // Get the required block size.
  349. //
  350. ULONG BufferSize = 0;
  351. Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &BufferSize, NULL);
  352. if (BufferSize && Error == ERROR_INSUFFICIENT_BUFFER) {
  353. //
  354. // The device does support the GUID, remember the size
  355. // and allocate a buffer to the data block.
  356. //
  357. m_WmiInstDataSize = BufferSize;
  358. m_pWmiInstData = new BYTE[BufferSize];
  359. if (m_pWmiInstData) {
  360. Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &BufferSize, m_pWmiInstData);
  361. } else {
  362. Error = ERROR_NOT_ENOUGH_MEMORY;
  363. }
  364. if (ERROR_SUCCESS == Error &&
  365. m_DataBlockSize == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->SizeDataBlock) {
  366. //
  367. // Remember the version
  368. //
  369. m_Version = ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->WnodeHeader.Version;
  370. return TRUE;
  371. }
  372. }
  373. Close();
  374. }
  375. SetLastError(Error);
  376. return FALSE;
  377. }