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.

1652 lines
39 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation
  3. Module Name:
  4. cnode.cpp
  5. Abstract:
  6. This module implements CDevice, CClass, CResource and CComputer classes.
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "devmgr.h"
  12. #include "cdriver.h"
  13. #include "hwprof.h"
  14. #include "sysinfo.h"
  15. #include <initguid.h>
  16. #include <mountmgr.h>
  17. #include <devguid.h>
  18. #include <wdmguid.h>
  19. //
  20. // CClass implementation
  21. //
  22. CClass::CClass(
  23. CMachine* pMachine,
  24. GUID* pGuid
  25. )
  26. {
  27. m_Guid = *pGuid;
  28. ASSERT(pMachine);
  29. ASSERT(pGuid);
  30. m_NoDisplay = FALSE;
  31. m_pMachine = pMachine;
  32. m_TotalDevices = 0;
  33. m_TotalHiddenDevices = 0;
  34. m_pDevInfoList = NULL;
  35. m_pos = NULL;
  36. if (!m_pMachine->DiGetClassFriendlyNameString(pGuid, m_strDisplayName))
  37. {
  38. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN);
  39. }
  40. m_pMachine->DiGetClassImageIndex(pGuid, &m_iImage);
  41. HKEY hKey = m_pMachine->DiOpenClassRegKey(pGuid, KEY_READ, DIOCR_INSTALLER);
  42. if (INVALID_HANDLE_VALUE != hKey)
  43. {
  44. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL))
  45. {
  46. m_NoDisplay = TRUE;
  47. }
  48. RegCloseKey(hKey);
  49. }
  50. }
  51. CDevInfoList*
  52. CClass::GetDevInfoList(
  53. HWND hwndParent
  54. )
  55. {
  56. if (!m_pDevInfoList)
  57. {
  58. HDEVINFO hDevInfo = m_pMachine->DiCreateDeviceInfoList(&m_Guid, hwndParent);
  59. if (hDevInfo && INVALID_HANDLE_VALUE != hDevInfo)
  60. {
  61. m_pDevInfoList = new CDevInfoList(hDevInfo, hwndParent);
  62. }
  63. }
  64. return m_pDevInfoList;
  65. }
  66. inline
  67. CItemIdentifier*
  68. CClass::CreateIdentifier()
  69. {
  70. return new CClassIdentifier(*this);
  71. }
  72. CClass::~CClass()
  73. {
  74. m_listDevice.RemoveAll();
  75. if (m_pDevInfoList)
  76. {
  77. delete m_pDevInfoList;
  78. }
  79. }
  80. HICON
  81. CClass::LoadIcon()
  82. {
  83. HICON hClassIcon;
  84. if (!m_pMachine->DiLoadClassIcon(&m_Guid, &hClassIcon, NULL))
  85. {
  86. return NULL;
  87. }
  88. return hClassIcon;
  89. }
  90. void
  91. CClass::AddDevice(CDevice* pDevice)
  92. {
  93. ASSERT(pDevice);
  94. m_listDevice.AddTail(pDevice);
  95. m_TotalDevices++;
  96. if (pDevice->IsHidden()) {
  97. m_TotalHiddenDevices++;
  98. }
  99. }
  100. BOOL
  101. CClass::GetFirstDevice(
  102. CDevice** ppDevice,
  103. PVOID& Context
  104. )
  105. {
  106. ASSERT(ppDevice);
  107. if (!m_listDevice.IsEmpty())
  108. {
  109. POSITION pos;
  110. pos = m_listDevice.GetHeadPosition();
  111. *ppDevice = m_listDevice.GetNext(pos);
  112. Context = pos;
  113. return TRUE;
  114. }
  115. *ppDevice = NULL;
  116. return FALSE;
  117. }
  118. BOOL
  119. CClass::GetNextDevice(
  120. CDevice** ppDevice,
  121. PVOID& Context
  122. )
  123. {
  124. ASSERT(ppDevice);
  125. POSITION pos = (POSITION)(Context);
  126. if(NULL != pos)
  127. {
  128. *ppDevice = m_listDevice.GetNext(pos);
  129. Context = pos;
  130. return TRUE;
  131. }
  132. *ppDevice = NULL;
  133. return FALSE;
  134. }
  135. void
  136. CClass::PropertyChanged()
  137. {
  138. if (!m_pMachine->DiGetClassFriendlyNameString(&m_Guid, m_strDisplayName))
  139. {
  140. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN);
  141. }
  142. m_pMachine->DiGetClassImageIndex(&m_Guid, &m_iImage);
  143. if (m_pDevInfoList)
  144. {
  145. delete m_pDevInfoList;
  146. m_pDevInfoList = NULL;
  147. }
  148. HKEY hKey = m_pMachine->DiOpenClassRegKey(&m_Guid, KEY_READ, DIOCR_INSTALLER);
  149. if (INVALID_HANDLE_VALUE != hKey)
  150. {
  151. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL))
  152. {
  153. m_NoDisplay = TRUE;
  154. }
  155. RegCloseKey(hKey);
  156. }
  157. }
  158. // CDevice implementation
  159. //
  160. CDevice::CDevice(
  161. CMachine* pMachine,
  162. CClass* pClass,
  163. PSP_DEVINFO_DATA pDevData
  164. )
  165. {
  166. ASSERT(pMachine && pDevData && pClass);
  167. m_DevData = *pDevData;
  168. m_pClass = pClass;
  169. m_pMachine = pMachine;
  170. m_pSibling = NULL;
  171. m_pParent = NULL;
  172. m_pChild = NULL;
  173. if (!m_pMachine->CmGetDescriptionString(m_DevData.DevInst, m_strDisplayName))
  174. {
  175. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN_DEVICE);
  176. }
  177. m_pMachine->CmGetDeviceIDString(m_DevData.DevInst, m_strDeviceID);
  178. m_iImage = m_pClass->GetImageIndex();
  179. }
  180. inline
  181. CItemIdentifier*
  182. CDevice::CreateIdentifier()
  183. {
  184. return new CDeviceIdentifier(*this);
  185. }
  186. void
  187. CDevice::PropertyChanged()
  188. {
  189. if (!m_pMachine->CmGetDescriptionString(m_DevData.DevInst, m_strDisplayName))
  190. {
  191. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN_DEVICE);
  192. }
  193. m_pMachine->CmGetDeviceIDString(m_DevData.DevInst, m_strDeviceID);
  194. m_iImage = m_pClass->GetImageIndex();
  195. }
  196. HICON
  197. CDevice::LoadClassIcon()
  198. {
  199. HICON hClassIcon;
  200. hClassIcon = NULL;
  201. if (m_pMachine->DiLoadClassIcon(&m_DevData.ClassGuid, &hClassIcon, NULL))
  202. {
  203. return hClassIcon;
  204. }
  205. return NULL;
  206. }
  207. BOOL
  208. CDevice::GetStatus(
  209. DWORD* pStatus,
  210. DWORD* pProblem
  211. )
  212. {
  213. return m_pMachine->CmGetStatus(m_DevData.DevInst, pProblem, pStatus);
  214. }
  215. BOOL
  216. CDevice::GetCapabilities(
  217. DWORD* pCapabilities
  218. )
  219. {
  220. return m_pMachine->CmGetCapabilities(m_DevData.DevInst, pCapabilities);
  221. }
  222. BOOL
  223. CDevice::GetPowerCapabilities(
  224. DWORD* pCapabilities
  225. )
  226. {
  227. CM_POWER_DATA CmPowerData;
  228. ULONG Size;
  229. Size = sizeof(CmPowerData);
  230. if (m_pMachine->CmGetRegistryProperty(m_DevData.DevInst,
  231. CM_DRP_DEVICE_POWER_DATA,
  232. &CmPowerData,
  233. &Size
  234. ) == CR_SUCCESS) {
  235. *pCapabilities = CmPowerData.PD_Capabilities;
  236. return TRUE;
  237. }
  238. *pCapabilities = 0;
  239. return FALSE;
  240. }
  241. BOOL
  242. CDevice::IsRAW()
  243. {
  244. DWORD Capabilities;
  245. return (m_pMachine->CmGetCapabilities(m_DevData.DevInst, &Capabilities) &&
  246. (CM_DEVCAP_RAWDEVICEOK & Capabilities));
  247. }
  248. BOOL
  249. CDevice::IsHidden()
  250. {
  251. CClass *pClass = GetClass();
  252. //
  253. // A device is hidden if one of the following are TRUE:
  254. //
  255. // - It's class is a NoDisplayClass
  256. // - It has the DN_NO_SHOW_IN_DM Status flag set
  257. // - It is a Phantom devnode
  258. //
  259. return (NoShowInDM() || IsPhantom() || pClass->NoDisplay());
  260. }
  261. BOOL
  262. CDevice::IsPhantom()
  263. {
  264. DWORD Status, Problem;
  265. return !m_pMachine->CmGetStatus(m_DevData.DevInst, &Problem, &Status) &&
  266. (CR_NO_SUCH_VALUE == m_pMachine->GetLastCR() ||
  267. CR_NO_SUCH_DEVINST == m_pMachine->GetLastCR());
  268. }
  269. BOOL
  270. CDevice::NoShowInDM()
  271. {
  272. DWORD Status, Problem;
  273. Status = 0;
  274. if (GetStatus(&Status, &Problem) &&
  275. (Status & DN_NO_SHOW_IN_DM)) {
  276. return TRUE;
  277. }
  278. return FALSE;
  279. }
  280. BOOL
  281. CDevice::IsUninstallable(
  282. )
  283. /*++
  284. This function determins whether a device can be uninstalled. A device
  285. cannot be uninstalled if it is a ROOT device and it does not have
  286. the DN_DISABLEABLE DevNode status bit set.
  287. Return Value:
  288. TRUE if the device can be uninstalled.
  289. FALSE if the device cannot be uninstalled.
  290. --*/
  291. {
  292. DWORD Status, Problem;
  293. if (GetStatus(&Status, &Problem) &&
  294. !(Status & DN_DISABLEABLE) &&
  295. (Status & DN_ROOT_ENUMERATED)) {
  296. return FALSE;
  297. }
  298. return TRUE;
  299. }
  300. BOOL
  301. CDevice::IsDisableable(
  302. )
  303. /*++
  304. This function determins whether a device can be disabled or not by
  305. checking the DN_DISABLEABLE DevNode status bit.
  306. A device that is currently Hardware Disabled cannot be software disabled.
  307. Return Value:
  308. TRUE if the device can be disabled.
  309. FALSE if the device cannot be disabled.
  310. --*/
  311. {
  312. DWORD Status, Problem;
  313. if (GetStatus(&Status, &Problem) &&
  314. (Status & DN_DISABLEABLE) &&
  315. (CM_PROB_HARDWARE_DISABLED != Problem)) {
  316. return TRUE;
  317. }
  318. return FALSE;
  319. }
  320. BOOL
  321. CDevice::IsDisabled(
  322. )
  323. /*++
  324. A device is disabled if it has the problem CM_PROB_DISABLED.
  325. Return Value:
  326. TRUE if device is disabled.
  327. FALSE if device is NOT disabled.
  328. --*/
  329. {
  330. DWORD Status, Problem;
  331. if (GetStatus(&Status, &Problem))
  332. {
  333. return ((Status & DN_HAS_PROBLEM) && (CM_PROB_DISABLED == Problem));
  334. }
  335. return FALSE;
  336. }
  337. BOOL
  338. CDevice::IsStateDisabled(
  339. )
  340. /*++
  341. A device state is disabled if it has the CONFIGFLAG_DISABLED ConfigFlag
  342. set or the CSCONFIGFLAG_DISABLED Config Specific ConfigFlag disabled in
  343. the current profile.
  344. Note that a device disabled State has nothing to do with whether the device
  345. is currently physically disabled or not. The disabled state is just a registry
  346. flag that tells Plug and Play what to do with the device the next time it is
  347. started.
  348. Return Value:
  349. TRUE if device's state is disabled.
  350. FALSE if device's state is NOT disabled.
  351. --*/
  352. {
  353. ULONG hwpfCurrent;
  354. DWORD Flags;
  355. //
  356. // Check if the device state is globally disabled by checking it's ConfigFlags
  357. //
  358. GetConfigFlags(&Flags);
  359. if (Flags & CONFIGFLAG_DISABLED) {
  360. return TRUE;
  361. }
  362. //
  363. // Check if the device state is disabled in the current hardware profile by
  364. // checking it's Config Specific ConfigFlags.
  365. //
  366. if (m_pMachine->CmGetCurrentHwProfile(&hwpfCurrent) &&
  367. m_pMachine->CmGetHwProfileFlags(m_DevData.DevInst, hwpfCurrent, &Flags) &&
  368. (Flags & CSCONFIGFLAG_DISABLED)) {
  369. return TRUE;
  370. }
  371. return FALSE;
  372. }
  373. BOOL
  374. CDevice::IsStarted()
  375. {
  376. DWORD Status, Problem;
  377. //
  378. // Check to see if the DN_STARTED devnode status flag is set.
  379. //
  380. if (GetStatus(&Status, &Problem) &&
  381. (Status & DN_STARTED))
  382. {
  383. return TRUE;
  384. }
  385. return FALSE;
  386. }
  387. BOOL
  388. CDevice::HasProblem(
  389. )
  390. /*++
  391. This function returns whether a device has a problem or not.
  392. Return Value:
  393. TRUE if device has a problem.
  394. FALSE if device does not have a problem.
  395. --*/
  396. {
  397. DWORD Status, Problem;
  398. if (GetStatus(&Status, &Problem))
  399. {
  400. //
  401. // If the DN_HAS_PROBLEM or DN_PRIVATE_PROBLEM status bits are set
  402. // then this device has a problem, unless the problem is CM_PROB_MOVED.
  403. //
  404. if ((Status & DN_PRIVATE_PROBLEM) ||
  405. ((Status & DN_HAS_PROBLEM) && (Problem != CM_PROB_MOVED)))
  406. {
  407. return TRUE;
  408. }
  409. //
  410. // If the device is not started and RAW capable then it also has a problem
  411. //
  412. if (!(Status & DN_STARTED) && IsRAW())
  413. {
  414. return TRUE;
  415. }
  416. }
  417. return FALSE;
  418. }
  419. BOOL
  420. CDevice::NeedsRestart(
  421. )
  422. /*++
  423. This function returns whether a device needs a restart or not. It checks the
  424. DN_NEED_RESTART Status flag.
  425. Return Value:
  426. TRUE if device needs the computer to be restarted for it to work properly.
  427. FALSE if device does not need the computer to be restarted.
  428. --*/
  429. {
  430. DWORD Status, Problem;
  431. if (GetStatus(&Status, &Problem))
  432. {
  433. return (Status & DN_NEED_RESTART);
  434. }
  435. return FALSE;
  436. }
  437. BOOL
  438. CDevice::IsPCIDevice()
  439. {
  440. GUID BusGuid;
  441. if (m_pMachine->CmGetBusGuid(GetDevNode(), &BusGuid) &&
  442. IsEqualGUID(BusGuid, GUID_BUS_TYPE_PCI)) {
  443. return TRUE;
  444. }
  445. return FALSE;
  446. }
  447. BOOL
  448. CDevice::GetConfigFlags(
  449. DWORD* pFlags
  450. )
  451. {
  452. return m_pMachine->CmGetConfigFlags(m_DevData.DevInst, pFlags);
  453. }
  454. BOOL
  455. CDevice::GetConfigSpecificConfigFlags(
  456. DWORD* pCSStatus
  457. )
  458. {
  459. ULONG hwpfCurrent;
  460. if (m_pMachine->CmGetCurrentHwProfile(&hwpfCurrent) &&
  461. m_pMachine->CmGetHwProfileFlags(m_DevData.DevInst, hwpfCurrent, pCSStatus)) {
  462. return TRUE;
  463. }
  464. return FALSE;
  465. }
  466. BOOL
  467. CDevice::GetKnownLogConf(LOG_CONF* plc, DWORD* plcType)
  468. {
  469. return m_pMachine->CmGetKnownLogConf(m_DevData.DevInst, plc, plcType);
  470. }
  471. BOOL
  472. CDevice::HasResources()
  473. {
  474. return m_pMachine->CmHasResources(m_DevData.DevInst);
  475. }
  476. void
  477. CDevice::GetMFGString(
  478. String& strMFG
  479. )
  480. {
  481. m_pMachine->CmGetMFGString(m_DevData.DevInst, strMFG);
  482. if (strMFG.IsEmpty())
  483. {
  484. strMFG.LoadString(g_hInstance, IDS_UNKNOWN);
  485. }
  486. }
  487. void
  488. CDevice::GetProviderString(
  489. String& strProvider
  490. )
  491. {
  492. m_pMachine->CmGetProviderString(m_DevData.DevInst, strProvider);
  493. if (strProvider.IsEmpty()) {
  494. strProvider.LoadString(g_hInstance, IDS_UNKNOWN);
  495. }
  496. }
  497. void
  498. CDevice::GetDriverDateString(
  499. String& strDriverDate
  500. )
  501. {
  502. FILETIME ft;
  503. strDriverDate.Empty();
  504. //
  505. // First try to get the driver date FileTime data from the registry,
  506. // this way we can localize the date.
  507. //
  508. if (m_pMachine->CmGetDriverDateData(m_DevData.DevInst, &ft)) {
  509. SYSTEMTIME SystemTime;
  510. TCHAR DriverDate[MAX_PATH];
  511. DriverDate[0] = TEXT('\0');
  512. if (FileTimeToSystemTime(&ft, &SystemTime)) {
  513. if (GetDateFormat(LOCALE_USER_DEFAULT,
  514. DATE_SHORTDATE,
  515. &SystemTime,
  516. NULL,
  517. DriverDate,
  518. ARRAYLEN(DriverDate)
  519. ) != 0) {
  520. strDriverDate = DriverDate;
  521. }
  522. }
  523. } else {
  524. //
  525. // We couldn't get the FileTime data so just get the DriverDate string
  526. // from the registry.
  527. //
  528. m_pMachine->CmGetDriverDateString(m_DevData.DevInst, strDriverDate);
  529. }
  530. if (strDriverDate.IsEmpty()) {
  531. strDriverDate.LoadString(g_hInstance, IDS_NOT_AVAILABLE);
  532. }
  533. }
  534. void
  535. CDevice::GetDriverVersionString(
  536. String& strDriverVersion
  537. )
  538. {
  539. m_pMachine->CmGetDriverVersionString(m_DevData.DevInst, strDriverVersion);
  540. if (strDriverVersion.IsEmpty()) {
  541. strDriverVersion.LoadString(g_hInstance, IDS_NOT_AVAILABLE);
  542. }
  543. }
  544. LPCTSTR
  545. CDevice::GetClassDisplayName()
  546. {
  547. if (m_pClass)
  548. {
  549. return m_pClass->GetDisplayName();
  550. }
  551. else
  552. {
  553. return NULL;
  554. }
  555. }
  556. BOOL
  557. CDevice::NoChangeUsage()
  558. {
  559. SP_DEVINSTALL_PARAMS dip;
  560. dip.cbSize = sizeof(dip);
  561. if (m_pMachine->DiGetDeviceInstallParams(&m_DevData, &dip))
  562. {
  563. return (dip.Flags & DI_PROPS_NOCHANGEUSAGE);
  564. }
  565. else
  566. {
  567. return TRUE;
  568. }
  569. }
  570. CDriver*
  571. CDevice::CreateDriver()
  572. {
  573. CDriver* pDriver = NULL;
  574. pDriver = new CDriver();
  575. if (!pDriver) {
  576. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  577. return NULL;
  578. }
  579. pDriver->Create(this);
  580. return pDriver;
  581. }
  582. DWORD
  583. CDevice::EnableDisableDevice(
  584. HWND hDlg,
  585. BOOL Enabling
  586. )
  587. {
  588. BOOL Disabling = !Enabling;
  589. BOOL Canceled;
  590. Canceled = FALSE;
  591. DWORD RestartFlags = 0;
  592. DWORD ConfigFlags;
  593. HCURSOR hCursorOld = NULL;
  594. BOOL Refresh = FALSE;
  595. //
  596. // Disable refreshing the TREE while we are enabling/disabling this device
  597. //
  598. m_pMachine->EnableRefresh(FALSE);
  599. if (!GetConfigFlags(&ConfigFlags)) {
  600. ConfigFlags = 0;
  601. }
  602. //
  603. // Only want the disabled bit
  604. //
  605. ConfigFlags &= CONFIGFLAG_DISABLED;
  606. CHwProfileList* pHwProfileList = new CHwProfileList();
  607. if (!pHwProfileList) {
  608. goto clean0;
  609. }
  610. pHwProfileList->Create(this, ConfigFlags);
  611. //
  612. // Get the current profile
  613. //
  614. CHwProfile* phwpf;
  615. if (!(pHwProfileList->GetCurrentHwProfile(&phwpf))) {
  616. goto clean0;
  617. }
  618. //
  619. // Can only enable a device that is currently disabled
  620. //
  621. if (IsStateDisabled() && Enabling) {
  622. phwpf->SetEnablePending();
  623. }
  624. //
  625. // Can only disable a device that is currently enabled
  626. //
  627. else if (!IsStateDisabled() && Disabling) {
  628. phwpf->SetDisablePending();
  629. }
  630. //
  631. // If we don't have a valid enable or disable then exit
  632. //
  633. if (!(phwpf->IsEnablePending()) && !(phwpf->IsDisablePending())) {
  634. goto clean0;
  635. }
  636. //
  637. // This device is not a boot device so just display the normal disable
  638. // warning to the user.
  639. //
  640. if (Disabling) {
  641. int MsgBoxResult;
  642. TCHAR szText[MAX_PATH];
  643. LoadResourceString(IDS_WARN_NORMAL_DISABLE, szText, ARRAYLEN(szText));
  644. MsgBoxResult = MessageBox(hDlg,
  645. szText,
  646. GetDisplayName(),
  647. MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2
  648. );
  649. if (IDYES != MsgBoxResult) {
  650. goto clean0;
  651. }
  652. }
  653. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  654. //
  655. // If this isn't a live devnode then we need to do a manual refresh if we
  656. // are diabling the device.
  657. //
  658. Refresh = (!Enabling &&
  659. (IsPhantom() ||
  660. HasProblem() ||
  661. !IsStarted()));
  662. m_pMachine->DiTurnOnDiFlags(*this, DI_NODI_DEFAULTACTION);
  663. SP_PROPCHANGE_PARAMS pcp;
  664. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  665. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  666. //
  667. // Now ask the class installer if the device can be specifically enabled/disabled
  668. //
  669. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  670. pcp.StateChange = DICS_DISABLE;
  671. if (phwpf->IsEnablePending()) {
  672. pcp.StateChange = DICS_ENABLE;
  673. }
  674. pcp.HwProfile = phwpf->GetHwProfile();
  675. m_pMachine->DiSetClassInstallParams(*this,
  676. &pcp.ClassInstallHeader,
  677. sizeof(pcp)
  678. );
  679. m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *this);
  680. Canceled = (ERROR_CANCELLED == GetLastError());
  681. //
  682. // class installer has not objection of our enabling/disabling,
  683. // do real enabling/disabling.
  684. //
  685. if (!Canceled) {
  686. if (phwpf->IsDisablePending()) {
  687. pcp.StateChange = DICS_DISABLE;
  688. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  689. pcp.HwProfile = phwpf->GetHwProfile();
  690. m_pMachine->DiSetClassInstallParams(*this,
  691. &pcp.ClassInstallHeader,
  692. sizeof(pcp)
  693. );
  694. m_pMachine->DiChangeState(*this);
  695. }
  696. else {
  697. //
  698. // We are enabling the device,
  699. // do a specific enabling then a globally enabling.
  700. // the globally enabling will start the device
  701. // The implementation here is different from
  702. // Win9x which does a global enabling, a config
  703. // specific enabling and then a start.
  704. //
  705. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  706. pcp.HwProfile = phwpf->GetHwProfile();
  707. m_pMachine->DiSetClassInstallParams(*this,
  708. &pcp.ClassInstallHeader,
  709. sizeof(pcp)
  710. );
  711. m_pMachine->DiChangeState(*this);
  712. //
  713. // This call will start the device is it not started.
  714. //
  715. pcp.Scope = DICS_FLAG_GLOBAL;
  716. m_pMachine->DiSetClassInstallParams(*this,
  717. &pcp.ClassInstallHeader,
  718. sizeof(pcp)
  719. );
  720. m_pMachine->DiChangeState(*this);
  721. }
  722. if (phwpf->IsEnablePending()) {
  723. phwpf->ResetEnablePending();
  724. }
  725. else if (phwpf->IsDisablePending()) {
  726. phwpf->ResetDisablePending();
  727. }
  728. //
  729. // signal that the property of the device is changed.
  730. //
  731. m_pMachine->DiTurnOnDiFlags(*this, DI_PROPERTIES_CHANGE);
  732. //
  733. // See if we need a restart.
  734. //
  735. RestartFlags |= (m_pMachine->DiGetFlags(*this)) & (DI_NEEDRESTART | DI_NEEDREBOOT);
  736. if (NeedsRestart()) {
  737. RestartFlags |= DI_NEEDRESTART;
  738. }
  739. }
  740. //
  741. // Remove class install parameters, this also reset
  742. // DI_CLASSINATLLPARAMS
  743. //
  744. m_pMachine->DiSetClassInstallParams(*this, NULL, 0);
  745. m_pMachine->DiTurnOffDiFlags(*this, DI_NODI_DEFAULTACTION);
  746. clean0:
  747. if (pHwProfileList) {
  748. delete pHwProfileList;
  749. }
  750. //
  751. // Enable the tree for refreshing.
  752. // We will only schedule a refresh ourselves if the device was not started
  753. // before we tried to disable it, and we are not going to prompt for a reboot.
  754. // In all other cases we should get a WM_DEVICECHANGE which will cause us
  755. // to refresh our tree.
  756. //
  757. if (Refresh && !NeedsRestart()) {
  758. m_pMachine->ScheduleRefresh();
  759. }
  760. m_pMachine->EnableRefresh(TRUE);
  761. if (hCursorOld != NULL) {
  762. SetCursor(hCursorOld);
  763. }
  764. return RestartFlags;
  765. }
  766. //
  767. // CComputer implementation
  768. //
  769. CComputer::CComputer(
  770. CMachine* pMachine,
  771. DEVNODE dnRoot
  772. )
  773. {
  774. ASSERT(pMachine);
  775. ASSERT(!GetChild() && !GetParent() && !GetSibling());
  776. m_pMachine = pMachine;
  777. m_strDisplayName.Empty();
  778. m_strDisplayName = pMachine->GetMachineDisplayName();
  779. m_iImage = pMachine->GetComputerIconIndex();
  780. m_dnRoot = dnRoot;
  781. }
  782. inline
  783. CItemIdentifier*
  784. CComputer::CreateIdentifier()
  785. {
  786. return new CComputerIdentifier(*this);
  787. }
  788. CResource::CResource(
  789. CDevice* pDevice,
  790. RESOURCEID ResType,
  791. DWORDLONG dlBase,
  792. DWORDLONG dlLen,
  793. BOOL Forced,
  794. BOOL Free
  795. )
  796. {
  797. m_pChild = NULL;
  798. m_pSibling = NULL;
  799. m_pParent = NULL;
  800. m_ResType = ResType;
  801. m_dlBase = dlBase;
  802. m_dlLen = dlLen;
  803. m_Forced = Forced;
  804. m_dlEnd = m_dlBase + m_dlLen - 1;
  805. m_Allocated = !Free;
  806. ASSERT(pDevice);
  807. m_pDevice = pDevice;
  808. m_iImage = pDevice->GetImageIndex();
  809. ASSERT(ResType >= ResType_Mem && ResType <= ResType_IRQ);
  810. m_strDisplayName.Empty();
  811. m_strDisplayName = pDevice->GetDisplayName();
  812. if (ResType_IRQ == m_ResType)
  813. {
  814. String strBus;
  815. strBus.LoadString(g_hInstance,
  816. pDevice->IsPCIDevice() ? IDS_PCI : IDS_ISA
  817. );
  818. m_strViewName.Format(TEXT("%2d "), m_dlBase);
  819. m_strViewName = strBus + m_strViewName;
  820. }
  821. else if (ResType_DMA == m_ResType)
  822. {
  823. m_strViewName.Format(TEXT("%2d " ), m_dlBase);
  824. }
  825. else
  826. {
  827. #ifdef _WIN64
  828. m_strViewName.Format(TEXT("[%016I64X - %016I64X] "), m_dlBase, m_dlEnd);
  829. #else
  830. m_strViewName.Format(TEXT("[%08lX - %08lX] "), (ULONG)m_dlBase, (ULONG)m_dlEnd);
  831. #endif
  832. }
  833. if (m_Allocated)
  834. {
  835. m_strViewName += pDevice->GetDisplayName();
  836. }
  837. }
  838. BOOL
  839. CResource::operator <=(
  840. const CResource& resSrc
  841. )
  842. {
  843. DWORDLONG dlBase, dlLen;
  844. resSrc.GetValue(&dlBase, &dlLen);
  845. if (m_dlBase < dlBase)
  846. return TRUE;
  847. //
  848. // If this resource contain the given resource,
  849. // we are smaller!
  850. //
  851. if (m_dlBase == dlBase)
  852. return (m_dlBase + m_dlLen > dlBase + dlLen);
  853. return FALSE;
  854. }
  855. BOOL
  856. CResource::EnclosedBy(
  857. const CResource& resSrc
  858. )
  859. {
  860. DWORDLONG dlBase, dlLen;
  861. resSrc.GetValue(&dlBase, &dlLen);
  862. return m_dlBase >= dlBase && m_dlBase + m_dlLen <= dlBase + dlLen;
  863. }
  864. CResourceType::CResourceType(
  865. CMachine* pMachine,
  866. RESOURCEID ResType
  867. )
  868. {
  869. int iStringID;
  870. m_ResType = ResType;
  871. m_pChild = NULL;
  872. m_pSibling = NULL;
  873. m_pParent = NULL;
  874. m_pMachine = pMachine;
  875. ASSERT(ResType >= ResType_Mem && ResType <= ResType_IRQ);
  876. switch (ResType)
  877. {
  878. case ResType_IRQ:
  879. iStringID = IDS_VIEW_RESOURCE_IRQ;
  880. break;
  881. case ResType_IO:
  882. iStringID = IDS_VIEW_RESOURCE_IO;
  883. break;
  884. case ResType_DMA:
  885. iStringID = IDS_VIEW_RESOURCE_DMA;
  886. break;
  887. case ResType_Mem:
  888. iStringID = IDS_VIEW_RESOURCE_MEM;
  889. break;
  890. default:
  891. iStringID = IDS_UNKNOWN;
  892. break;
  893. }
  894. m_strDisplayName.Empty();
  895. m_strDisplayName.LoadString(g_hInstance, iStringID);
  896. m_iImage = pMachine->GetResourceIconIndex();
  897. }
  898. inline
  899. CItemIdentifier*
  900. CResourceType::CreateIdentifier()
  901. {
  902. return new CResourceTypeIdentifier(*this);
  903. }
  904. // This function creates CResourceList object to contain the designated
  905. // resources for the given device.
  906. // INPUT:
  907. // pDevice -- the device
  908. // ResType -- what type of resource
  909. // LogConfType -- what type of logconf
  910. // OUTPUT:
  911. // NONE.
  912. //
  913. // This function may throw CMemoryException
  914. //
  915. CResourceList::CResourceList(
  916. CDevice* pDevice,
  917. RESOURCEID ResType,
  918. ULONG LogConfType,
  919. ULONG AltLogConfType
  920. )
  921. {
  922. ASSERT(ResType_All != ResType);
  923. ASSERT(BOOT_LOG_CONF == LogConfType ||
  924. FORCED_LOG_CONF == LogConfType ||
  925. ALLOC_LOG_CONF == LogConfType);
  926. ASSERT(pDevice);
  927. UNREFERENCED_PARAMETER(AltLogConfType);
  928. LOG_CONF lc;
  929. RES_DES rd, rdPrev;
  930. rdPrev;
  931. RESOURCEID ResId;
  932. BOOL Forced;
  933. CMachine* pMachine = pDevice->m_pMachine;
  934. ASSERT(pMachine);
  935. rdPrev = 0;
  936. //
  937. // Even though we have a valid logconf, it does not mean
  938. // GetNextResDes would succeed because the ResType is not
  939. // ResType_All.
  940. //
  941. if (pMachine->CmGetFirstLogConf(pDevice->GetDevNode(), &lc, LogConfType))
  942. {
  943. if (pMachine->CmGetNextResDes(&rd, lc, ResType, &ResId))
  944. {
  945. ULONG DataSize;
  946. DWORDLONG dlBase, dlLen;
  947. do
  948. {
  949. DataSize = pMachine->CmGetResDesDataSize(rd);
  950. if (DataSize)
  951. {
  952. BufferPtr<BYTE> DataPtr(DataSize);
  953. if (pMachine->CmGetResDesData(rd, DataPtr, DataSize))
  954. {
  955. //
  956. // Need this to use a different image overlay for
  957. // forced allocated resource
  958. //
  959. Forced = pMachine->CmGetFirstLogConf(pDevice->GetDevNode(),
  960. NULL, FORCED_LOG_CONF);
  961. if (ExtractResourceValue(ResType, DataPtr, &dlBase, &dlLen))
  962. {
  963. SafePtr<CResource> ResPtr;
  964. CResource* pRes;
  965. pRes = new CResource(pDevice, ResType, dlBase,
  966. dlLen, Forced, FALSE);
  967. if (pRes)
  968. {
  969. ResPtr.Attach(pRes);
  970. InsertResourceToList(pRes);
  971. ResPtr.Detach();
  972. }
  973. }
  974. }
  975. }
  976. if (rdPrev)
  977. {
  978. pMachine->CmFreeResDesHandle(rdPrev);
  979. }
  980. rdPrev = rd;
  981. } while (pMachine->CmGetNextResDes(&rd, rdPrev, ResType, &ResId));
  982. //
  983. // free the last resource descriptor handle
  984. //
  985. pMachine->CmFreeResDesHandle(rd);
  986. }
  987. pMachine->CmFreeLogConfHandle(lc);
  988. }
  989. }
  990. // This function creates CResourceList object to contain the designated
  991. // resources for the given machine.
  992. // INPUT:
  993. // pMachine -- the machine
  994. // ResType -- what type of resource
  995. // LogConfType -- what type of logconf
  996. // OUTPUT:
  997. // NONE.
  998. //
  999. // This function may throw CMemoryException
  1000. //
  1001. CResourceList::CResourceList(
  1002. CMachine* pMachine,
  1003. RESOURCEID ResType,
  1004. ULONG LogConfType,
  1005. ULONG AltLogConfType
  1006. )
  1007. {
  1008. ASSERT(ResType_All != ResType);
  1009. ASSERT(BOOT_LOG_CONF == LogConfType ||
  1010. FORCED_LOG_CONF == LogConfType ||
  1011. ALLOC_LOG_CONF == LogConfType ||
  1012. ALL_LOG_CONF == LogConfType);
  1013. ASSERT(pMachine);
  1014. if (pMachine->GetNumberOfDevices())
  1015. {
  1016. ASSERT(pMachine->m_pComputer && pMachine->m_pComputer->GetChild());
  1017. CDevice* pFirstDevice;
  1018. pFirstDevice = pMachine->m_pComputer->GetChild();
  1019. CreateSubtreeResourceList(pFirstDevice, ResType, LogConfType, AltLogConfType);
  1020. }
  1021. }
  1022. //
  1023. // This function extracts resource value from the provided buffer
  1024. //
  1025. // INPUT:
  1026. // ResType -- resource type the data contain
  1027. // pData -- the raw data
  1028. // pdlBase -- buffer to hold the base of the value
  1029. // pdlLen -- buffer to hold the length of the value
  1030. //
  1031. // OUTPUT:
  1032. // TRUE if this is a valid resource descriptor or FALSE if we should ignore it.
  1033. //
  1034. // NOTE:
  1035. // If the return value is FALSE then pdlBase and pdlLen are not filled in.
  1036. //
  1037. BOOL
  1038. CResourceList::ExtractResourceValue(
  1039. RESOURCEID ResType,
  1040. PVOID pData,
  1041. DWORDLONG* pdlBase,
  1042. DWORDLONG* pdlLen
  1043. )
  1044. {
  1045. BOOL bValidResDes = TRUE;
  1046. ASSERT(pData && pdlBase && pdlLen);
  1047. switch (ResType)
  1048. {
  1049. case ResType_Mem:
  1050. if (pMemResData(pData)->MEM_Header.MD_Alloc_Base <= pMemResData(pData)->MEM_Header.MD_Alloc_End) {
  1051. *pdlBase = pMemResData(pData)->MEM_Header.MD_Alloc_Base;
  1052. *pdlLen = pMemResData(pData)->MEM_Header.MD_Alloc_End - *pdlBase + 1;
  1053. } else {
  1054. //
  1055. // If base > end then ignore this resource descriptor
  1056. //
  1057. *pdlBase = 0;
  1058. *pdlLen = 0;
  1059. bValidResDes = FALSE;
  1060. }
  1061. break;
  1062. case ResType_IRQ:
  1063. *pdlBase = pIRQResData(pData)->IRQ_Header.IRQD_Alloc_Num;
  1064. // IRQ len is always 1
  1065. *pdlLen = 1;
  1066. break;
  1067. case ResType_DMA:
  1068. *pdlBase = pDMAResData(pData)->DMA_Header.DD_Alloc_Chan;
  1069. // DMA len is always 1
  1070. *pdlLen = 1;
  1071. break;
  1072. case ResType_IO:
  1073. if (pIOResData(pData)->IO_Header.IOD_Alloc_Base <= pIOResData(pData)->IO_Header.IOD_Alloc_End) {
  1074. *pdlBase = pIOResData(pData)->IO_Header.IOD_Alloc_Base;
  1075. *pdlLen = pIOResData(pData)->IO_Header.IOD_Alloc_End -
  1076. *pdlBase + 1;
  1077. } else {
  1078. //
  1079. // If base > end then ignore this resource descriptor
  1080. //
  1081. *pdlBase = 0;
  1082. *pdlLen = 0;
  1083. bValidResDes = FALSE;
  1084. }
  1085. break;
  1086. default:
  1087. ASSERT(FALSE);
  1088. *pdlBase = 0;
  1089. *pdlLen = 0;
  1090. break;
  1091. }
  1092. return bValidResDes;
  1093. }
  1094. //
  1095. //This function creates resources for the given subtree rooted at
  1096. //the given device
  1097. //
  1098. //INPUT:
  1099. // pDevice -- the root device of the subtree
  1100. // ResType -- resource type to be created
  1101. // LogConfType -- logconf type to be created from
  1102. //
  1103. //OUTPUT:
  1104. // NONE
  1105. //
  1106. // This function may throw CMemoryException
  1107. //
  1108. void
  1109. CResourceList::CreateSubtreeResourceList(
  1110. CDevice* pDeviceStart,
  1111. RESOURCEID ResType,
  1112. ULONG LogConfType,
  1113. ULONG AltLogConfType
  1114. )
  1115. {
  1116. LOG_CONF lc;
  1117. RES_DES rd, rdPrev;
  1118. RESOURCEID ResId;
  1119. BOOL Forced;
  1120. CMachine* pMachine = pDeviceStart->m_pMachine;
  1121. ASSERT(pMachine);
  1122. while (pDeviceStart)
  1123. {
  1124. //
  1125. // We will try to get a LogConf for either the LogConfType (which defaults to
  1126. // ALLOC_LOG_CONF) or the AltLogConfType (which defaults to BOOT_LOG_CONF).
  1127. // We need to do this because on Win2000 a device that only has a BOOT_LOG_CONF
  1128. // will still consume those resources, even if it does not have an ALLOC_LOG_CONF.
  1129. // So we need to first check the ALLOC_LOG_CONF and if that fails check the
  1130. // BOOT_LOG_CONF.
  1131. //
  1132. if (pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), &lc, LogConfType) ||
  1133. pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), &lc, AltLogConfType))
  1134. {
  1135. rdPrev = 0;
  1136. if (pMachine->CmGetNextResDes(&rd, lc, ResType, &ResId))
  1137. {
  1138. ULONG DataSize;
  1139. DWORDLONG dlBase, dlLen;
  1140. do
  1141. {
  1142. DataSize = pMachine->CmGetResDesDataSize(rd);
  1143. if (DataSize)
  1144. {
  1145. //
  1146. // Need this to use a different image overlay for
  1147. // forced allocated resource
  1148. //
  1149. Forced = pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(),
  1150. NULL, FORCED_LOG_CONF);
  1151. BufferPtr<BYTE> DataPtr(DataSize);
  1152. if (pMachine->CmGetResDesData(rd, DataPtr, DataSize))
  1153. {
  1154. if (ExtractResourceValue(ResType, DataPtr, &dlBase, &dlLen))
  1155. {
  1156. SafePtr<CResource> ResPtr;
  1157. CResource* pRes;
  1158. pRes = new CResource(pDeviceStart, ResType, dlBase,
  1159. dlLen, Forced, FALSE);
  1160. ResPtr.Attach(pRes);
  1161. InsertResourceToList(pRes);
  1162. ResPtr.Detach();
  1163. }
  1164. }
  1165. }
  1166. if (rdPrev)
  1167. pMachine->CmFreeResDesHandle(rdPrev);
  1168. rdPrev = rd;
  1169. }while (pMachine->CmGetNextResDes(&rd, rdPrev, ResType, &ResId));
  1170. //
  1171. // Free the last resource descriptor handle
  1172. //
  1173. pMachine->CmFreeResDesHandle(rd);
  1174. }
  1175. pMachine->CmFreeLogConfHandle(lc);
  1176. }
  1177. if (pDeviceStart->GetChild())
  1178. CreateSubtreeResourceList(pDeviceStart->GetChild(), ResType, LogConfType, AltLogConfType);
  1179. pDeviceStart = pDeviceStart->GetSibling();
  1180. }
  1181. }
  1182. // This function creates a resource tree
  1183. // INPUT:
  1184. // ppResRoot -- buffer to receive the tree root
  1185. //
  1186. BOOL
  1187. CResourceList::CreateResourceTree(
  1188. CResource** ppResRoot
  1189. )
  1190. {
  1191. ASSERT(ppResRoot);
  1192. *ppResRoot = NULL;
  1193. if (!m_listRes.IsEmpty())
  1194. {
  1195. POSITION pos = m_listRes.GetHeadPosition();
  1196. CResource* pResFirst;
  1197. pResFirst = m_listRes.GetNext(pos);
  1198. *ppResRoot = pResFirst;
  1199. while (NULL != pos)
  1200. {
  1201. CResource* pRes = m_listRes.GetNext(pos);
  1202. InsertResourceToTree(pRes, pResFirst, TRUE);
  1203. }
  1204. }
  1205. return TRUE;
  1206. }
  1207. BOOL
  1208. CResourceList::InsertResourceToTree(
  1209. CResource* pRes,
  1210. CResource* pResRoot,
  1211. BOOL ForcedInsert
  1212. )
  1213. {
  1214. CResource* pResLast = NULL;
  1215. while (pResRoot)
  1216. {
  1217. if (pRes->EnclosedBy(*pResRoot))
  1218. {
  1219. //
  1220. // This resource is either the pResRoot child or grand child
  1221. // figure out which one it is
  1222. //
  1223. if (!pResRoot->GetChild())
  1224. {
  1225. pResRoot->SetChild(pRes);
  1226. pRes->SetParent(pResRoot);
  1227. }
  1228. else if (!InsertResourceToTree(pRes, pResRoot->GetChild(), FALSE))
  1229. {
  1230. //
  1231. // The Resource is not a grand child of pResRoot.
  1232. // search for the last child of pResRoot
  1233. //
  1234. CResource* pResSibling;
  1235. pResSibling = pResRoot->GetChild();
  1236. while (pResSibling->GetSibling())
  1237. pResSibling = pResSibling->GetSibling();
  1238. pResSibling->SetSibling(pRes);
  1239. pRes->SetParent(pResRoot);
  1240. }
  1241. return TRUE;
  1242. }
  1243. pResLast = pResRoot;
  1244. pResRoot = pResRoot->GetSibling();
  1245. }
  1246. if (ForcedInsert)
  1247. {
  1248. if (pResLast) {
  1249. // when we reach here, pResLast is the last child
  1250. pResLast->SetSibling(pRes);
  1251. pRes->SetParent(pResLast->GetParent());
  1252. }
  1253. return TRUE;
  1254. }
  1255. return FALSE;
  1256. }
  1257. CResourceList::~CResourceList()
  1258. {
  1259. if (!m_listRes.IsEmpty())
  1260. {
  1261. POSITION pos = m_listRes.GetHeadPosition();
  1262. while (NULL != pos)
  1263. {
  1264. delete m_listRes.GetNext(pos);
  1265. }
  1266. m_listRes.RemoveAll();
  1267. }
  1268. }
  1269. BOOL
  1270. CResourceList::GetFirst(
  1271. CResource** ppRes,
  1272. PVOID& Context
  1273. )
  1274. {
  1275. ASSERT(ppRes);
  1276. if (!m_listRes.IsEmpty())
  1277. {
  1278. POSITION pos = m_listRes.GetHeadPosition();
  1279. *ppRes = m_listRes.GetNext(pos);
  1280. Context = pos;
  1281. return TRUE;
  1282. }
  1283. Context = NULL;
  1284. *ppRes = NULL;
  1285. return FALSE;
  1286. }
  1287. BOOL
  1288. CResourceList::GetNext(
  1289. CResource** ppRes,
  1290. PVOID& Context
  1291. )
  1292. {
  1293. ASSERT(ppRes);
  1294. POSITION pos = (POSITION)Context;
  1295. if (NULL != pos)
  1296. {
  1297. *ppRes = m_listRes.GetNext(pos);
  1298. Context = pos;
  1299. return TRUE;
  1300. }
  1301. *ppRes = NULL;
  1302. return FALSE;
  1303. }
  1304. //
  1305. // This function inserts the given resource to class's resource list
  1306. // The resources are kept in accending sorted order
  1307. void
  1308. CResourceList::InsertResourceToList(
  1309. CResource* pRes
  1310. )
  1311. {
  1312. POSITION pos;
  1313. CResource* pSrc;
  1314. DWORDLONG dlBase, dlLen;
  1315. pRes->GetValue(&dlBase, &dlLen);
  1316. pos = m_listRes.GetHeadPosition();
  1317. while (NULL != pos)
  1318. {
  1319. POSITION posSave = pos;
  1320. pSrc = m_listRes.GetNext(pos);
  1321. if (*pRes <= *pSrc)
  1322. {
  1323. m_listRes.InsertBefore(posSave, pRes);
  1324. return;
  1325. }
  1326. }
  1327. m_listRes.AddTail(pRes);
  1328. }
  1329. inline
  1330. CItemIdentifier*
  1331. CResource::CreateIdentifier()
  1332. {
  1333. return new CResourceIdentifier(*this);
  1334. }