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.

894 lines
29 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation
  3. Module Name:
  4. devgenpg.cpp
  5. Abstract:
  6. This module implements CDeviceGeneralPage -- device general property page
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. // devgenpg.cpp : implementation file
  12. //
  13. #include "devmgr.h"
  14. #include "hwprof.h"
  15. #include "devgenpg.h"
  16. #include "tswizard.h"
  17. #include "utils.h"
  18. //
  19. // help topic ids
  20. //
  21. const DWORD g_a103HelpIDs[]=
  22. {
  23. IDC_DEVGEN_TITLE_TYPE, idh_devmgr_general_devicetype,
  24. IDC_DEVGEN_TITLE_MFG, idh_devmgr_general_manufacturer,
  25. IDC_DEVGEN_STATUSGROUP, IDH_DISABLEHELP,
  26. IDC_DEVGEN_ICON, IDH_DISABLEHELP, // General: "" (Static)
  27. IDC_DEVGEN_DESC, IDH_DISABLEHELP, // General: "" (Static)
  28. IDC_DEVGEN_USAGETEXT, IDH_DISABLEHELP, // General: "Place a check mark next to the configuration(s) where this device should be used." (Static)
  29. IDC_DEVGEN_TYPE, idh_devmgr_general_devicetype, // General: "" (Static)
  30. IDC_DEVGEN_MFG, idh_devmgr_general_manufacturer, // General: "" (Static)
  31. IDC_DEVGEN_STATUS, idh_devmgr_general_device_status, // General: "" (Static)
  32. IDC_DEVGEN_PROFILELIST, idh_devmgr_general_device_usage, // General: "Dropdown Combo" (SysListView32)
  33. IDC_DEVGEN_TITLE_LOCATION, idh_devmgr_general_location, // General: location
  34. IDC_DEVGEN_LOCATION, idh_devmgr_general_location, // General: location
  35. IDC_DEVGEN_TROUBLESHOOTING, idh_devmgr_general_trouble, // General: troubleshooting
  36. 0, 0
  37. };
  38. CDeviceGeneralPage::~CDeviceGeneralPage()
  39. {
  40. if (m_pHwProfileList) {
  41. delete m_pHwProfileList;
  42. }
  43. if (m_pProblemAgent) {
  44. delete m_pProblemAgent;
  45. }
  46. }
  47. HPROPSHEETPAGE
  48. CDeviceGeneralPage::Create(
  49. CDevice* pDevice
  50. )
  51. {
  52. ASSERT(pDevice);
  53. if (pDevice)
  54. {
  55. m_pDevice = pDevice;
  56. // override PROPSHEETPAGE structure here...
  57. m_psp.lParam = (LPARAM)this;
  58. pDevice->m_pMachine->DiTurnOffDiExFlags(*pDevice, DI_FLAGSEX_PROPCHANGE_PENDING);
  59. return CreatePage();
  60. }
  61. return NULL;
  62. }
  63. BOOL
  64. CDeviceGeneralPage::OnInitDialog(
  65. LPPROPSHEETPAGE ppsp
  66. )
  67. {
  68. m_pDevice->m_pMachine->AttachPropertySheet(m_hDlg);
  69. // notify property sheet data that the property sheet is up
  70. m_pDevice->m_psd.PageCreateNotify(m_hDlg);
  71. return CPropSheetPage::OnInitDialog(ppsp);
  72. }
  73. BOOL
  74. CDeviceGeneralPage::OnApply()
  75. {
  76. try
  77. {
  78. HWND hwndCB = GetControl(IDC_DEVGEN_PROFILELIST);
  79. m_SelectedDeviceUsage = ComboBox_GetCurSel(hwndCB);
  80. if ((-1 != m_SelectedDeviceUsage) &&
  81. (m_SelectedDeviceUsage != m_CurrentDeviceUsage)) {
  82. //
  83. // User is changing the device usage
  84. //
  85. UpdateHwProfileStates();
  86. SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  87. return TRUE;
  88. }
  89. }
  90. catch(CMemoryException* e)
  91. {
  92. e->Delete();
  93. MsgBoxParam(m_hDlg, 0, 0, 0);
  94. }
  95. return FALSE;
  96. }
  97. void
  98. CDeviceGeneralPage::UpdateHwProfileStates()
  99. {
  100. // first decide what to do: enabling or disabling
  101. BOOL Canceled;
  102. Canceled = FALSE;
  103. if (m_SelectedDeviceUsage == m_CurrentDeviceUsage) {
  104. return;
  105. }
  106. m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_NODI_DEFAULTACTION);
  107. SP_PROPCHANGE_PARAMS pcp;
  108. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  109. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  110. //
  111. // specific enabling/disabling
  112. //
  113. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  114. CHwProfile* phwpf;
  115. if (m_pHwProfileList->GetCurrentHwProfile(&phwpf))
  116. {
  117. if (DEVICE_ENABLE == m_SelectedDeviceUsage) {
  118. pcp.StateChange = DICS_ENABLE;
  119. } else {
  120. pcp.StateChange = DICS_DISABLE;
  121. }
  122. pcp.HwProfile = phwpf->GetHwProfile();
  123. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  124. &pcp.ClassInstallHeader,
  125. sizeof(pcp)
  126. );
  127. m_pDevice->m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *m_pDevice);
  128. Canceled = (ERROR_CANCELLED == GetLastError());
  129. }
  130. //
  131. // class installer has not objection of our enabling/disabling,
  132. // do real enabling/disabling.
  133. //
  134. if (!Canceled)
  135. {
  136. if (m_pHwProfileList->GetCurrentHwProfile(&phwpf))
  137. {
  138. if (DEVICE_ENABLE == m_SelectedDeviceUsage)
  139. {
  140. //
  141. // we are enabling the device,
  142. // do a specific enabling then a globally enabling.
  143. // the globally enabling will start the device
  144. // The implementation here is different from
  145. // Win9x which does a global enabling, a config
  146. // specific enabling and then a start.
  147. //
  148. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  149. pcp.HwProfile = phwpf->GetHwProfile();
  150. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  151. &pcp.ClassInstallHeader,
  152. sizeof(pcp)
  153. );
  154. m_pDevice->m_pMachine->DiChangeState(*m_pDevice);
  155. //
  156. // this call will start the device is it not started.
  157. //
  158. pcp.Scope = DICS_FLAG_GLOBAL;
  159. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  160. &pcp.ClassInstallHeader,
  161. sizeof(pcp)
  162. );
  163. m_pDevice->m_pMachine->DiChangeState(*m_pDevice);
  164. } else {
  165. //
  166. // Do either a global disable or a configspecific disable
  167. //
  168. if (DEVICE_DISABLE == m_SelectedDeviceUsage) {
  169. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  170. } else {
  171. pcp.Scope = DICS_FLAG_GLOBAL;
  172. }
  173. pcp.StateChange = DICS_DISABLE;
  174. pcp.HwProfile = phwpf->GetHwProfile();
  175. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  176. &pcp.ClassInstallHeader,
  177. sizeof(pcp)
  178. );
  179. m_pDevice->m_pMachine->DiChangeState(*m_pDevice);
  180. }
  181. }
  182. // signal that the property of the device is changed.
  183. m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE);
  184. m_RestartFlags |= (m_pDevice->m_pMachine->DiGetFlags(*m_pDevice)) & (DI_NEEDRESTART | DI_NEEDREBOOT);
  185. }
  186. // remove class install parameters, this also reset
  187. // DI_CLASSINATLLPARAMS
  188. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, NULL, 0);
  189. m_pDevice->m_pMachine->DiTurnOffDiFlags(*m_pDevice, DI_NODI_DEFAULTACTION);
  190. }
  191. BOOL
  192. CDeviceGeneralPage::OnLastChanceApply()
  193. {
  194. //
  195. // The last chance apply message is sent in reverse order page n to page 0.
  196. //
  197. // Since we are the first page in the set of property sheets we can gaurentee
  198. // that the last PSN_LASTCHANCEAPPLY message will be the last message for all
  199. // the pages.
  200. //
  201. // The property sheet is going away, consolidate the changes on the device. We
  202. // do this during the PSN_LASTCHANCEAPPLY message so that the property sheet is
  203. // still displayed while we do the DIF_PROPERTYCHANGE. There are some cases where
  204. // the DIF_PROPERTYCHANGE can take quite a long time so we want the property sheet
  205. // to still be shown while this is happening. If we do this during the DestroyCallback
  206. // the property sheet UI has already been torn down and so the user won't realize
  207. // we are still saving the changes.
  208. //
  209. try
  210. {
  211. ASSERT(m_pDevice);
  212. if (m_pDevice->m_pMachine->DiGetExFlags(*m_pDevice) & DI_FLAGSEX_PROPCHANGE_PENDING)
  213. {
  214. DWORD Status = 0, Problem = 0;
  215. //
  216. // If the device has the DN_WILL_BE_REMOVED flag set and the user is
  217. // attempting to change settings on the driver then we will prompt them for a
  218. // reboot and include text in the prompt that explains this device
  219. // is in the process of being removed.
  220. //
  221. if (m_pDevice->GetStatus(&Status, &Problem) &&
  222. (Status & DN_WILL_BE_REMOVED)) {
  223. //
  224. // First try and send a MMCPropertyChangeNotify message to our
  225. // CComponent so that it can prompt for a reboot inside the
  226. // device manager thread instead of our thread. If this is not
  227. // done then the property sheet will hang around after device
  228. // manager has gone away...which will cause a "hung app" dialog
  229. // to appear.
  230. //
  231. CNotifyRebootRequest* pNRR = new CNotifyRebootRequest(NULL, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS);
  232. if (pNRR) {
  233. if (!m_pDevice->m_psd.PropertyChangeNotify(reinterpret_cast<LONG_PTR>(pNRR))) {
  234. //
  235. // There isn't a CComponent around, so this is just a property
  236. // sheet running outside of MMC.
  237. //
  238. pNRR->Release();
  239. PromptForRestart(m_hDlg, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS);
  240. }
  241. } else {
  242. //
  243. // We couldn't allocate memory to create our CNotifyRebootRequest
  244. // instance, so just prompt for a reboot in this thread.
  245. //
  246. PromptForRestart(m_hDlg, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS);
  247. }
  248. } else {
  249. //
  250. // property change pending, issue a DICS_PROPERTYCHANGE to the
  251. // class installer. A DICS_PROPCHANGE would basically stop the
  252. // device and restart it. If each property page issues
  253. // its own DICS_PROPCHANGE command, the device would
  254. // be stopped/started several times even though one is enough.
  255. // A property page sets DI_FLAGEX_PROPCHANGE_PENDING when it needs
  256. // a DICS_PROPCHANGE command to be issued.
  257. //
  258. SP_PROPCHANGE_PARAMS pcp;
  259. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  260. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  261. HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  262. pcp.Scope = DICS_FLAG_GLOBAL;
  263. pcp.StateChange = DICS_PROPCHANGE;
  264. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  265. &pcp.ClassInstallHeader,
  266. sizeof(pcp)
  267. );
  268. m_pDevice->m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *m_pDevice);
  269. m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE);
  270. m_pDevice->m_pMachine->DiTurnOffDiExFlags(*m_pDevice, DI_FLAGSEX_PROPCHANGE_PENDING);
  271. if (hCursorOld) {
  272. SetCursor(hCursorOld);
  273. }
  274. }
  275. }
  276. }
  277. catch(CMemoryException* e)
  278. {
  279. e->Delete();
  280. MsgBoxParam(m_hDlg, 0, 0, 0);
  281. }
  282. return FALSE;
  283. }
  284. UINT
  285. CDeviceGeneralPage::DestroyCallback()
  286. {
  287. //
  288. // We do this because this is the page we are sure will be created --
  289. // this page is ALWAYS the first page.
  290. //
  291. ASSERT(m_pDevice);
  292. //
  293. // We don't want to prompt for a reboot if the device has the problem
  294. // DN_WILL_BE_REMOVED, because we have already prompted for a reboot
  295. // before we get to this destroy callback.
  296. //
  297. DWORD Status = 0, Problem = 0;
  298. if (m_pDevice->GetStatus(&Status, &Problem) &&
  299. !(Status & DN_WILL_BE_REMOVED)) {
  300. m_RestartFlags |= m_pDevice->m_pMachine->DiGetFlags(*m_pDevice);
  301. if (m_RestartFlags & (DI_NEEDRESTART | DI_NEEDREBOOT))
  302. {
  303. //
  304. // Do not use our window handle(or its parent) as the parent
  305. // to the newly create dialog because they are in "detroyed state".
  306. // WM_CLOSE does not help either.
  307. // NULL window handle(Desktop) should be okay here.
  308. //
  309. // We only want to prompt for a restart if device manager is connected
  310. // to the local machine.
  311. //
  312. if (m_pDevice->m_pMachine->IsLocal())
  313. {
  314. //
  315. // First try and send a MMCPropertyChangeNotify message to our
  316. // CComponent so that it can prompt for a reboot inside the
  317. // device manager thread instead of our thread. If this is not
  318. // done then the property sheet will hang around after device
  319. // manager has gone away...which will cause a "hung app" dialog
  320. // to appear.
  321. //
  322. CNotifyRebootRequest* pNRR = new CNotifyRebootRequest(NULL, m_RestartFlags, 0);
  323. if (pNRR) {
  324. if (!m_pDevice->m_psd.PropertyChangeNotify(reinterpret_cast<LONG_PTR>(pNRR))) {
  325. //
  326. // There isn't a CComponent around, so this is just a property
  327. // sheet running outside of MMC.
  328. //
  329. pNRR->Release();
  330. PromptForRestart(NULL, m_RestartFlags);
  331. }
  332. } else {
  333. //
  334. // We couldn't allocate memory to create our CNotifyRebootRequest
  335. // instance, so just prompt for a reboot in this thread.
  336. //
  337. PromptForRestart(NULL, m_RestartFlags);
  338. }
  339. }
  340. }
  341. }
  342. // notify CPropSheetData that the property sheet is going away
  343. m_pDevice->m_psd.PageDestroyNotify(m_hDlg);
  344. if (m_RestartFlags & DI_PROPERTIES_CHANGE)
  345. {
  346. // Device properties changed. We need to refresh the machine.
  347. // Since we are running in a separate thread, we can not
  348. // call the refresh function, instead, we schedule it.
  349. // This should be done before enabling the refresh
  350. if (m_pDevice->m_pMachine->m_ParentMachine) {
  351. m_pDevice->m_pMachine->m_ParentMachine->ScheduleRefresh();
  352. } else {
  353. m_pDevice->m_pMachine->ScheduleRefresh();
  354. }
  355. }
  356. //
  357. // Detach this property page from the CMachine so that the CMachine can be
  358. // destroyed now if it needs to be.
  359. //
  360. m_pDevice->m_pMachine->DetachPropertySheet(m_hDlg);
  361. ASSERT(!::IsWindow(m_hwndLocationTip));
  362. //
  363. // Destory the CMachine.
  364. //
  365. CMachine* pMachine;
  366. pMachine = m_pDevice->m_pMachine;
  367. if (pMachine->ShouldPropertySheetDestroy()) {
  368. delete pMachine;
  369. }
  370. return CPropSheetPage::DestroyCallback();
  371. }
  372. void
  373. CDeviceGeneralPage::UpdateControls(
  374. LPARAM lParam
  375. )
  376. {
  377. if (lParam)
  378. m_pDevice = (CDevice*)lParam;
  379. m_RestartFlags = 0;
  380. try
  381. {
  382. //
  383. // Calling PropertyChanged() will update the display name for the device. We need
  384. // to do this in case a 3rd party property sheet did something that could change
  385. // the device's display name.
  386. //
  387. m_pDevice->PropertyChanged();
  388. SetDlgItemText(m_hDlg, IDC_DEVGEN_DESC, m_pDevice->GetDisplayName());
  389. TCHAR TempString[512];
  390. String str;
  391. m_pDevice->GetMFGString(str);
  392. SetDlgItemText(m_hDlg, IDC_DEVGEN_MFG, str);
  393. SetDlgItemText(m_hDlg, IDC_DEVGEN_TYPE, m_pDevice->GetClassDisplayName());
  394. HICON hIconNew;
  395. hIconNew = m_pDevice->LoadClassIcon();
  396. if (hIconNew)
  397. {
  398. HICON hIconOld;
  399. m_IDCicon = IDC_DEVGEN_ICON; // Save for cleanup in OnDestroy.
  400. hIconOld = (HICON)SendDlgItemMessage(m_hDlg, IDC_DEVGEN_ICON,
  401. STM_SETICON, (WPARAM)hIconNew,
  402. 0);
  403. if (hIconOld)
  404. DestroyIcon(hIconOld);
  405. }
  406. //
  407. // get the device location information
  408. //
  409. if (::GetLocationInformation(m_pDevice->GetDevNode(),
  410. TempString,
  411. ARRAYLEN(TempString),
  412. m_pDevice->m_pMachine->GetHMachine()) != CR_SUCCESS)
  413. {
  414. // if the devnode does not have location information,
  415. // use the word "unknown"
  416. LoadString(g_hInstance, IDS_UNKNOWN, TempString, ARRAYLEN(TempString));
  417. }
  418. SetDlgItemText(m_hDlg, IDC_DEVGEN_LOCATION, TempString);
  419. AddToolTips(m_hDlg, IDC_DEVGEN_LOCATION, TempString, &m_hwndLocationTip);
  420. ShowWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), SW_HIDE);
  421. DWORD Problem, Status;
  422. if (m_pDevice->GetStatus(&Status, &Problem) || m_pDevice->IsPhantom())
  423. {
  424. //
  425. // if the device is a phantom device, use the CM_PROB_PHANTOM
  426. //
  427. if (m_pDevice->IsPhantom())
  428. {
  429. Problem = CM_PROB_PHANTOM;
  430. Status = DN_HAS_PROBLEM;
  431. }
  432. //
  433. // if the device is not started and no problem is assigned to it
  434. // fake the problem number to be failed start.
  435. //
  436. if (!(Status & DN_STARTED) && !Problem && m_pDevice->IsRAW())
  437. {
  438. Problem = CM_PROB_FAILED_START;
  439. }
  440. //
  441. // if a device has a private problem then give it special text telling
  442. // the user to contact the manufacturer of this driver.
  443. //
  444. if (Status & DN_PRIVATE_PROBLEM)
  445. {
  446. str.LoadString(g_hInstance, IDS_SPECIALPROB_PRIVATEPROB);
  447. }
  448. //
  449. // if a device is not started and still does not have a problem
  450. // then give it special problem text saying that this device
  451. // does not have a driver.
  452. //
  453. else if (!(Status & DN_STARTED) && !(Status & DN_HAS_PROBLEM))
  454. {
  455. if (::GetSystemMetrics(SM_CLEANBOOT) == 0) {
  456. str.LoadString(g_hInstance, IDS_SPECIALPROB_NODRIVERS);
  457. } else {
  458. str.LoadString(g_hInstance, IDS_SPECIALPROB_SAFEMODE);
  459. }
  460. }
  461. //
  462. // Display normal problem text
  463. //
  464. else
  465. {
  466. UINT len = GetDeviceProblemText(Problem, TempString, ARRAYLEN(TempString));
  467. if (len)
  468. {
  469. if (len < ARRAYLEN(TempString))
  470. {
  471. SetDlgItemText(m_hDlg, IDC_DEVGEN_STATUS, TempString);
  472. str = TempString;
  473. }
  474. else
  475. {
  476. BufferPtr<TCHAR> TextPtr(len + 1);
  477. GetDeviceProblemText(Problem, TextPtr, len + 1);
  478. str = (LPTSTR)TextPtr;
  479. }
  480. }
  481. else
  482. {
  483. str.LoadString(g_hInstance, IDS_PROB_UNKNOWN);
  484. }
  485. }
  486. //
  487. // Add the 'related driver blocked' text if the device has the devnode
  488. // flag DN_DRIVER_BLOCKED set and it does not have the problem
  489. // CM_PROB_DRIVER_BLOCKED.
  490. //
  491. if ((Status & DN_DRIVER_BLOCKED) &&
  492. (Problem != CM_PROB_DRIVER_BLOCKED)) {
  493. LoadString(g_hInstance, IDS_DRIVER_BLOCKED, TempString, ARRAYLEN(TempString));
  494. str += TempString;
  495. }
  496. //
  497. // Add the 'child device with invalid Id' text if the device has
  498. // the devnode flag DN_CHILD_WITH_INVALID_ID set.
  499. //
  500. if (Status & DN_CHILD_WITH_INVALID_ID) {
  501. LoadString(g_hInstance, IDS_CHILD_WITH_INVALID_ID, TempString, ARRAYLEN(TempString));
  502. str += TempString;
  503. }
  504. //
  505. // Add the 'will be removed' text if the device is going to be removed
  506. // on the next restart.
  507. //
  508. if (Status & DN_WILL_BE_REMOVED) {
  509. LoadString(g_hInstance, IDS_WILL_BE_REMOVED, TempString, ARRAYLEN(TempString));
  510. str += TempString;
  511. }
  512. //
  513. // Add the restart text if the device needs to be restarted
  514. //
  515. if (Status & DN_NEED_RESTART) {
  516. LoadString(g_hInstance, IDS_NEED_RESTART, TempString, ARRAYLEN(TempString));
  517. str += TempString;
  518. m_RestartFlags |= DI_NEEDRESTART;
  519. }
  520. //
  521. // Create the problem agent and update the control text
  522. //
  523. if (!(Status & DN_PRIVATE_PROBLEM))
  524. {
  525. if (m_pProblemAgent) {
  526. delete m_pProblemAgent;
  527. }
  528. m_pProblemAgent = new CProblemAgent(m_pDevice, Problem, FALSE);
  529. DWORD Len;
  530. Len = m_pProblemAgent->InstructionText(TempString, ARRAYLEN(TempString));
  531. if (Len)
  532. {
  533. str += TempString;
  534. }
  535. Len = m_pProblemAgent->FixitText(TempString, ARRAYLEN(TempString));
  536. if (Len)
  537. {
  538. ::ShowWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), SW_SHOW);
  539. SetDlgItemText(m_hDlg, IDC_DEVGEN_TROUBLESHOOTING, TempString);
  540. }
  541. }
  542. }
  543. else
  544. {
  545. TRACE((TEXT("%s has not status, devnode =%lx, cr = %lx\n"),
  546. m_pDevice->GetDisplayName(), m_pDevice->GetDevNode(),
  547. m_pDevice->m_pMachine->GetLastCR()));
  548. str.LoadString(g_hInstance, IDS_PROB_UNKNOWN);
  549. ::ShowWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), SW_HIDE);
  550. }
  551. SetDlgItemText(m_hDlg, IDC_DEVGEN_STATUS, str);
  552. if (m_pDevice->NoChangeUsage() ||
  553. !m_pDevice->IsDisableable() ||
  554. (CM_PROB_HARDWARE_DISABLED == Problem))
  555. {
  556. // the device disallows any changes on hw profile.
  557. // disable all profile related controls.
  558. ::EnableWindow(GetControl(IDC_DEVGEN_PROFILELIST), FALSE);
  559. ::EnableWindow(GetControl(IDC_DEVGEN_USAGETEXT), FALSE);
  560. }
  561. else
  562. {
  563. HWND hwndCB = GetControl(IDC_DEVGEN_PROFILELIST);
  564. DWORD ConfigFlags;
  565. if (!m_pDevice->GetConfigFlags(&ConfigFlags)) {
  566. ConfigFlags = 0;
  567. }
  568. //
  569. // only want the disabled bit
  570. //
  571. ConfigFlags &= CONFIGFLAG_DISABLED;
  572. //
  573. // rebuild the profile list.
  574. //
  575. if (m_pHwProfileList) {
  576. delete m_pHwProfileList;
  577. }
  578. m_pHwProfileList = new CHwProfileList();
  579. if (m_pHwProfileList->Create(m_pDevice, ConfigFlags))
  580. {
  581. ComboBox_ResetContent(hwndCB);
  582. //
  583. // Get the current device usage
  584. //
  585. if (m_pDevice->IsStateDisabled()) {
  586. if ((m_pHwProfileList->GetCount() > 1) && ConfigFlags) {
  587. m_CurrentDeviceUsage = DEVICE_DISABLE_GLOBAL;
  588. } else {
  589. m_CurrentDeviceUsage = DEVICE_DISABLE;
  590. }
  591. } else {
  592. m_CurrentDeviceUsage = DEVICE_ENABLE;
  593. }
  594. //
  595. // Always add the Enable item
  596. //
  597. String Enable;
  598. Enable.LoadString(g_hInstance, IDS_ENABLE_CURRENT);
  599. ComboBox_AddString(hwndCB, Enable);
  600. //
  601. // Add the disable items. There will either be one disable
  602. // item if there is only one hardware profile or two if there
  603. // are more than one hardware profile.
  604. //
  605. if (m_pHwProfileList->GetCount() > 1) {
  606. String DisableInCurrent;
  607. DisableInCurrent.LoadString(g_hInstance, IDS_DISABLE_IN_PROFILE);
  608. ComboBox_AddString(hwndCB, DisableInCurrent);
  609. String DisableGlobal;
  610. DisableGlobal.LoadString(g_hInstance, IDS_DISABLE_GLOBAL);
  611. ComboBox_AddString(hwndCB, DisableGlobal);
  612. } else {
  613. String Disable;
  614. Disable.LoadString(g_hInstance, IDS_DISABLE_CURRENT);
  615. ComboBox_AddString(hwndCB, Disable);
  616. }
  617. ComboBox_SetCurSel(hwndCB, m_CurrentDeviceUsage);
  618. }
  619. }
  620. //
  621. // If this is a remote computer or the user is not an administrator
  622. // then disable the enable/disable drop down list along with the
  623. // TroubleShooter button.
  624. //
  625. if (!m_pDevice->m_pMachine->IsLocal() ||
  626. !g_IsAdmin)
  627. {
  628. ::EnableWindow(GetControl(IDC_DEVGEN_PROFILELIST), FALSE);
  629. ::EnableWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), FALSE);
  630. }
  631. //
  632. // Check if we need to autolauch the troubleshooter
  633. //
  634. if (m_pDevice->m_pMachine->IsLocal() &&
  635. g_IsAdmin &&
  636. m_pDevice->m_bLaunchTroubleShooter) {
  637. m_pDevice->m_bLaunchTroubleShooter = FALSE;
  638. ::PostMessage(m_hDlg, WM_COMMAND, MAKELONG(IDC_DEVGEN_TROUBLESHOOTING, BN_CLICKED), 0);
  639. }
  640. }
  641. catch (CMemoryException* e)
  642. {
  643. e->Delete();
  644. MsgBoxParam(m_hDlg, 0, 0, 0);
  645. }
  646. }
  647. BOOL
  648. CDeviceGeneralPage::OnQuerySiblings(
  649. WPARAM wParam,
  650. LPARAM lParam
  651. )
  652. {
  653. DMQUERYSIBLINGCODE Code = (DMQUERYSIBLINGCODE)wParam;
  654. if (QSC_TO_FOREGROUND == Code)
  655. {
  656. HWND hwndSheet;
  657. hwndSheet = m_pDevice->m_psd.GetWindowHandle();
  658. if (GetForegroundWindow() != hwndSheet)
  659. {
  660. SetForegroundWindow(hwndSheet);
  661. }
  662. SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, 1);
  663. return TRUE;
  664. }
  665. return CPropSheetPage::OnQuerySiblings(wParam, lParam);
  666. }
  667. BOOL
  668. CDeviceGeneralPage::OnCommand(
  669. WPARAM wParam,
  670. LPARAM lParam
  671. )
  672. {
  673. UNREFERENCED_PARAMETER(lParam);
  674. if (BN_CLICKED == HIWORD(wParam) &&
  675. IDC_DEVGEN_TROUBLESHOOTING == LOWORD(wParam)) {
  676. BOOL fChanged = FALSE;
  677. if (m_pProblemAgent) {
  678. fChanged = m_pProblemAgent->FixIt(GetParent(m_hDlg));
  679. }
  680. if (fChanged) {
  681. m_pDevice->PropertyChanged();
  682. m_pDevice->GetClass()->PropertyChanged();
  683. m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE);
  684. UpdateControls();
  685. PropSheet_SetTitle(GetParent(m_hDlg), PSH_PROPTITLE, m_pDevice->GetDisplayName());
  686. PropSheet_CancelToClose(GetParent(m_hDlg));
  687. //
  688. // ISSUE: JasonC 2/7/2000
  689. //
  690. // A refresh on m_pDevice->m_pMachine is necessary here.
  691. // Since we are running on a different thread and each
  692. // property page may have cached the HDEVINFO and the
  693. // SP_DEVINFO_DATA, refresh on the CMachine object can not
  694. // be done here. The problem is worsen by the fact that
  695. // user can go back to the device tree and work on the tree
  696. // while this property sheet is still up.
  697. // It would be nice if MMC would support modal dialog boxes.
  698. //
  699. }
  700. }
  701. return FALSE;
  702. }
  703. BOOL
  704. CDeviceGeneralPage::OnHelp(
  705. LPHELPINFO pHelpInfo
  706. )
  707. {
  708. WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP,
  709. (ULONG_PTR)g_a103HelpIDs);
  710. return FALSE;
  711. }
  712. BOOL
  713. CDeviceGeneralPage::OnContextMenu(
  714. HWND hWnd,
  715. WORD xPos,
  716. WORD yPos
  717. )
  718. {
  719. UNREFERENCED_PARAMETER(xPos);
  720. UNREFERENCED_PARAMETER(yPos);
  721. WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU,
  722. (ULONG_PTR)g_a103HelpIDs);
  723. return FALSE;
  724. }