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.

1881 lines
42 KiB

  1. /*++
  2. Copyright (C) 1997-1999 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. HKEY hKey = NULL;
  31. m_NoDisplay = FALSE;
  32. m_pMachine = pMachine;
  33. m_TotalDevices = 0;
  34. m_TotalHiddenDevices = 0;
  35. m_pDevInfoList = NULL;
  36. m_pos = NULL;
  37. if (!m_pMachine->DiGetClassFriendlyNameString(pGuid, m_strDisplayName))
  38. {
  39. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN);
  40. }
  41. m_pMachine->DiGetClassImageIndex(pGuid, &m_iImage);
  42. hKey = m_pMachine->DiOpenClassRegKey(pGuid, KEY_READ, DIOCR_INSTALLER);
  43. if (INVALID_HANDLE_VALUE != hKey)
  44. {
  45. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL))
  46. {
  47. m_NoDisplay = TRUE;
  48. }
  49. RegCloseKey(hKey);
  50. }
  51. }
  52. CDevInfoList*
  53. CClass::GetDevInfoList(
  54. HWND hwndParent
  55. )
  56. {
  57. if (!m_pDevInfoList)
  58. {
  59. HDEVINFO hDevInfo = m_pMachine->DiCreateDeviceInfoList(&m_Guid, hwndParent);
  60. if (hDevInfo && INVALID_HANDLE_VALUE != hDevInfo)
  61. {
  62. m_pDevInfoList = new CDevInfoList(hDevInfo, hwndParent);
  63. }
  64. }
  65. return m_pDevInfoList;
  66. }
  67. inline
  68. CItemIdentifier*
  69. CClass::CreateIdentifier()
  70. {
  71. return new CClassIdentifier(*this);
  72. }
  73. CClass::~CClass()
  74. {
  75. m_listDevice.RemoveAll();
  76. if (m_pDevInfoList)
  77. {
  78. delete m_pDevInfoList;
  79. }
  80. }
  81. HICON
  82. CClass::LoadIcon()
  83. {
  84. HICON hClassIcon;
  85. if (!m_pMachine->DiLoadClassIcon(&m_Guid, &hClassIcon, NULL))
  86. {
  87. return NULL;
  88. }
  89. return hClassIcon;
  90. }
  91. void
  92. CClass::AddDevice(CDevice* pDevice)
  93. {
  94. ASSERT(pDevice);
  95. m_listDevice.AddTail(pDevice);
  96. m_TotalDevices++;
  97. // Every device under a NoDisplay class is a hidden device
  98. if (m_NoDisplay || pDevice->IsHidden()) {
  99. m_TotalHiddenDevices++;
  100. }
  101. }
  102. BOOL
  103. CClass::GetFirstDevice(
  104. CDevice** ppDevice,
  105. PVOID& Context
  106. )
  107. {
  108. ASSERT(ppDevice);
  109. if (!m_listDevice.IsEmpty())
  110. {
  111. POSITION pos;
  112. pos = m_listDevice.GetHeadPosition();
  113. *ppDevice = m_listDevice.GetNext(pos);
  114. Context = pos;
  115. return TRUE;
  116. }
  117. *ppDevice = NULL;
  118. return FALSE;
  119. }
  120. BOOL
  121. CClass::GetNextDevice(
  122. CDevice** ppDevice,
  123. PVOID& Context
  124. )
  125. {
  126. ASSERT(ppDevice);
  127. POSITION pos = (POSITION)(Context);
  128. if(NULL != pos)
  129. {
  130. *ppDevice = m_listDevice.GetNext(pos);
  131. Context = pos;
  132. return TRUE;
  133. }
  134. *ppDevice = NULL;
  135. return FALSE;
  136. }
  137. void
  138. CClass::PropertyChanged()
  139. {
  140. HKEY hKey = NULL;
  141. if (!m_pMachine->DiGetClassFriendlyNameString(&m_Guid, m_strDisplayName))
  142. {
  143. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN);
  144. }
  145. m_pMachine->DiGetClassImageIndex(&m_Guid, &m_iImage);
  146. if (m_pDevInfoList)
  147. {
  148. delete m_pDevInfoList;
  149. m_pDevInfoList = NULL;
  150. }
  151. hKey = m_pMachine->DiOpenClassRegKey(&m_Guid, KEY_READ, DIOCR_INSTALLER);
  152. if (INVALID_HANDLE_VALUE != hKey)
  153. {
  154. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL))
  155. {
  156. m_NoDisplay = TRUE;
  157. }
  158. RegCloseKey(hKey);
  159. }
  160. }
  161. // CDevice implementation
  162. //
  163. CDevice::CDevice(
  164. CMachine* pMachine,
  165. CClass* pClass,
  166. PSP_DEVINFO_DATA pDevData
  167. )
  168. {
  169. ASSERT(pMachine && pDevData && pClass);
  170. m_DevData = *pDevData;
  171. m_pClass = pClass;
  172. m_pMachine = pMachine;
  173. m_pSibling = NULL;
  174. m_pParent = NULL;
  175. m_pChild = NULL;
  176. if (!m_pMachine->CmGetDescriptionString(m_DevData.DevInst, m_strDisplayName))
  177. {
  178. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN_DEVICE);
  179. }
  180. m_pMachine->CmGetDeviceIDString(m_DevData.DevInst, m_strDeviceID);
  181. m_iImage = m_pClass->GetImageIndex();
  182. }
  183. inline
  184. CItemIdentifier*
  185. CDevice::CreateIdentifier()
  186. {
  187. return new CDeviceIdentifier(*this);
  188. }
  189. void
  190. CDevice::PropertyChanged()
  191. {
  192. if (!m_pMachine->CmGetDescriptionString(m_DevData.DevInst, m_strDisplayName))
  193. {
  194. m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN_DEVICE);
  195. }
  196. m_pMachine->CmGetDeviceIDString(m_DevData.DevInst, m_strDeviceID);
  197. m_iImage = m_pClass->GetImageIndex();
  198. }
  199. HICON
  200. CDevice::LoadClassIcon()
  201. {
  202. HICON hClassIcon;
  203. hClassIcon = NULL;
  204. if (m_pMachine->DiLoadClassIcon(&m_DevData.ClassGuid, &hClassIcon, NULL))
  205. {
  206. return hClassIcon;
  207. }
  208. return NULL;
  209. }
  210. BOOL
  211. CDevice::GetStatus(
  212. DWORD* pStatus,
  213. DWORD* pProblem
  214. )
  215. {
  216. return m_pMachine->CmGetStatus(m_DevData.DevInst, pProblem, pStatus);
  217. }
  218. BOOL
  219. CDevice::GetCapabilities(
  220. DWORD* pCapabilities
  221. )
  222. {
  223. return m_pMachine->CmGetCapabilities(m_DevData.DevInst, pCapabilities);
  224. }
  225. BOOL
  226. CDevice::GetPowerCapabilities(
  227. DWORD* pCapabilities
  228. )
  229. {
  230. CM_POWER_DATA CmPowerData;
  231. ULONG Size;
  232. Size = sizeof(CmPowerData);
  233. if (m_pMachine->CmGetRegistryProperty(m_DevData.DevInst,
  234. CM_DRP_DEVICE_POWER_DATA,
  235. &CmPowerData,
  236. &Size
  237. ) == CR_SUCCESS) {
  238. *pCapabilities = CmPowerData.PD_Capabilities;
  239. return TRUE;
  240. }
  241. *pCapabilities = 0;
  242. return FALSE;
  243. }
  244. BOOL
  245. CDevice::IsRAW()
  246. {
  247. DWORD Capabilities;
  248. return (m_pMachine->CmGetCapabilities(m_DevData.DevInst, &Capabilities) &&
  249. (CM_DEVCAP_RAWDEVICEOK & Capabilities));
  250. }
  251. BOOL
  252. CDevice::IsHidden()
  253. {
  254. CClass *pClass = GetClass();
  255. //
  256. // A device is hidden if one of the following are TRUE:
  257. //
  258. // - It's class is a NoDisplayClass
  259. // - It has the DN_NO_SHOW_IN_DM Status flag set
  260. // - It is a Phantom devnode
  261. //
  262. return (NoShowInDM() || IsPhantom() || pClass->NoDisplay());
  263. }
  264. BOOL
  265. CDevice::IsPhantom()
  266. {
  267. DWORD Status, Problem;
  268. return !m_pMachine->CmGetStatus(m_DevData.DevInst, &Problem, &Status) &&
  269. (CR_NO_SUCH_VALUE == m_pMachine->GetLastCR() ||
  270. CR_NO_SUCH_DEVINST == m_pMachine->GetLastCR());
  271. }
  272. BOOL
  273. CDevice::NoShowInDM()
  274. {
  275. DWORD Status, Problem;
  276. Status = 0;
  277. GetStatus(&Status, &Problem);
  278. return (Status & DN_NO_SHOW_IN_DM);
  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. CDevice*
  438. CDevice::FindMFParent()
  439. {
  440. if (!IsMFChild())
  441. {
  442. return NULL;
  443. }
  444. ASSERT(m_pParent);
  445. CDevice* pDevice = m_pParent;
  446. while (pDevice->IsMFChild())
  447. {
  448. pDevice = pDevice->GetParent();
  449. }
  450. return pDevice;
  451. }
  452. BOOL
  453. CDevice::IsMFChild(
  454. )
  455. {
  456. DWORD Status, Problem;
  457. Status = 0;
  458. GetStatus(&Status, &Problem);
  459. return (Status & DN_MF_CHILD);
  460. }
  461. BOOL
  462. CDevice::IsSpecialMFChild(
  463. )
  464. {
  465. if (IsMFChild())
  466. {
  467. DWORD Flags;
  468. if (GetConfigFlags(&Flags))
  469. {
  470. return (Flags & CONFIGFLAG_CANTSTOPACHILD);
  471. }
  472. }
  473. return FALSE;
  474. }
  475. // This function determines if the device is a pnp device
  476. // INPUT:
  477. // None
  478. // OUTPUT:
  479. // TRUE if the device is a pnp device
  480. // FLASE if the device is not a pnp device or undetermined
  481. BOOL
  482. CDevice::IsPnpDevice()
  483. {
  484. // A device is pnp device if the device id is not led
  485. // by "root" and DN_ROOT_ENUMERATED is not set
  486. // in its status.
  487. if (!m_strDeviceID.IsEmpty())
  488. {
  489. // unfortunately, we do not have lstrcmpin library function
  490. TCHAR DeviceId[MAX_DEVICE_ID_LEN + 1];
  491. int len = lstrlen(REGSTR_KEY_ROOTENUM);
  492. lstrcpyn(DeviceId, (LPCTSTR)m_strDeviceID, len);
  493. DeviceId[len] = _T('\0');
  494. if (lstrcmpi(DeviceId, REGSTR_KEY_ROOTENUM))
  495. {
  496. // the device id does not start with "root"
  497. // check the status
  498. DWORD Problem, Status;
  499. if (GetStatus(&Status, &Problem))
  500. {
  501. return !(Status & DN_ROOT_ENUMERATED);
  502. }
  503. }
  504. }
  505. return FALSE;
  506. }
  507. BOOL
  508. CDevice::IsBiosDevice()
  509. {
  510. // A device is bios enumerated if its device id
  511. // is led by "root" and its status does not
  512. // have DN_ROOT_ENUMERATED
  513. if (!m_strDeviceID.IsEmpty())
  514. {
  515. TCHAR DeviceId[MAX_DEVICE_ID_LEN + 1];
  516. int len = lstrlen(REGSTR_KEY_ROOTENUM);
  517. lstrcpyn(DeviceId, (LPCTSTR)m_strDeviceID, len);
  518. DeviceId[len] = _T('\0');
  519. if (!lstrcmpi(DeviceId, REGSTR_KEY_ROOTENUM))
  520. {
  521. // the device id starts with "root"
  522. // check the status
  523. DWORD Problem, Status;
  524. if (GetStatus(&Status, &Problem))
  525. {
  526. return !(Status & DN_ROOT_ENUMERATED);
  527. }
  528. }
  529. }
  530. return FALSE;
  531. }
  532. BOOL
  533. CDevice::IsPCMCIA()
  534. {
  535. ASSERT(m_pClass);
  536. // if the device's class is PCMCIA, it is a PCMCIA device
  537. if (IsEqualGUID(*m_pClass, GUID_DEVCLASS_PCMCIA))
  538. {
  539. return TRUE;
  540. }
  541. // if the device has ancestor(s), it is a PCMCIA if one of
  542. // its ancestor is PCMCIA
  543. if (m_pParent)
  544. {
  545. return m_pParent->IsPCMCIA();
  546. }
  547. return FALSE;
  548. }
  549. BOOL
  550. CDevice::IsPCIDevice()
  551. {
  552. GUID BusGuid;
  553. CONFIGRET ConfigRet;
  554. if (m_pMachine->CmGetBusGuid(GetDevNode(), &BusGuid) &&
  555. IsEqualGUID(BusGuid, GUID_BUS_TYPE_PCI)) {
  556. return TRUE;
  557. }
  558. return FALSE;
  559. }
  560. BOOL
  561. CDevice::GetConfigFlags(
  562. DWORD* pFlags
  563. )
  564. {
  565. return m_pMachine->CmGetConfigFlags(m_DevData.DevInst, pFlags);
  566. }
  567. BOOL
  568. CDevice::GetConfigSpecificConfigFlags(
  569. DWORD* pCSStatus
  570. )
  571. {
  572. ULONG hwpfCurrent;
  573. if (m_pMachine->CmGetCurrentHwProfile(&hwpfCurrent) &&
  574. m_pMachine->CmGetHwProfileFlags(m_DevData.DevInst, hwpfCurrent, pCSStatus)) {
  575. return TRUE;
  576. }
  577. return FALSE;
  578. }
  579. BOOL
  580. CDevice::GetKnownLogConf(LOG_CONF* plc, DWORD* plcType)
  581. {
  582. return m_pMachine->CmGetKnownLogConf(m_DevData.DevInst, plc, plcType);
  583. }
  584. BOOL
  585. CDevice::HasResources()
  586. {
  587. return m_pMachine->CmHasResources(m_DevData.DevInst);
  588. }
  589. void
  590. CDevice::GetMFGString(
  591. String& strMFG
  592. )
  593. {
  594. m_pMachine->CmGetMFGString(m_DevData.DevInst, strMFG);
  595. if (strMFG.IsEmpty())
  596. {
  597. strMFG.LoadString(g_hInstance, IDS_UNKNOWN);
  598. }
  599. }
  600. void
  601. CDevice::GetProviderString(
  602. String& strProvider
  603. )
  604. {
  605. m_pMachine->CmGetProviderString(m_DevData.DevInst, strProvider);
  606. if (strProvider.IsEmpty()) {
  607. strProvider.LoadString(g_hInstance, IDS_UNKNOWN);
  608. }
  609. }
  610. void
  611. CDevice::GetDriverDateString(
  612. String& strDriverDate
  613. )
  614. {
  615. FILETIME ft;
  616. strDriverDate.Empty();
  617. //
  618. // First try to get the driver date FileTime data from the registry,
  619. // this way we can localize the date.
  620. //
  621. if (m_pMachine->CmGetDriverDateData(m_DevData.DevInst, &ft)) {
  622. SYSTEMTIME SystemTime;
  623. TCHAR DriverDate[MAX_PATH];
  624. DriverDate[0] = TEXT('\0');
  625. if (FileTimeToSystemTime(&ft, &SystemTime)) {
  626. if (GetDateFormat(LOCALE_USER_DEFAULT,
  627. DATE_SHORTDATE,
  628. &SystemTime,
  629. NULL,
  630. DriverDate,
  631. sizeof(DriverDate)/sizeof(TCHAR)
  632. ) != 0) {
  633. strDriverDate = DriverDate;
  634. }
  635. }
  636. } else {
  637. //
  638. // We couldn't get the FileTime data so just get the DriverDate string
  639. // from the registry.
  640. //
  641. m_pMachine->CmGetDriverDateString(m_DevData.DevInst, strDriverDate);
  642. }
  643. if (strDriverDate.IsEmpty()) {
  644. strDriverDate.LoadString(g_hInstance, IDS_NOT_AVAILABLE);
  645. }
  646. }
  647. void
  648. CDevice::GetDriverVersionString(
  649. String& strDriverVersion
  650. )
  651. {
  652. m_pMachine->CmGetDriverVersionString(m_DevData.DevInst, strDriverVersion);
  653. if (strDriverVersion.IsEmpty()) {
  654. strDriverVersion.LoadString(g_hInstance, IDS_NOT_AVAILABLE);
  655. }
  656. }
  657. LPCTSTR
  658. CDevice::GetClassDisplayName()
  659. {
  660. if (m_pClass)
  661. {
  662. return m_pClass->GetDisplayName();
  663. }
  664. else
  665. {
  666. return NULL;
  667. }
  668. }
  669. BOOL
  670. CDevice::NoChangeUsage()
  671. {
  672. SP_DEVINSTALL_PARAMS dip;
  673. dip.cbSize = sizeof(dip);
  674. if (m_pMachine->DiGetDeviceInstallParams(&m_DevData, &dip))
  675. {
  676. return (dip.Flags & DI_PROPS_NOCHANGEUSAGE);
  677. }
  678. else
  679. {
  680. return TRUE;
  681. }
  682. }
  683. CDriver*
  684. CDevice::CreateDriver()
  685. {
  686. SP_DRVINFO_DATA DrvInfoData;
  687. PSP_DRVINFO_DATA pDrvInfoData;
  688. CDriver* pDriver = NULL;
  689. DrvInfoData.cbSize = sizeof(DrvInfoData);
  690. // If the device has a selected driver, use it. Otherwise,
  691. // we pass a NULL drvinfodata so that CDriver will search
  692. // for the device driver key or service to create
  693. // a list of driver files.
  694. if (m_pMachine->DiGetSelectedDriver(&m_DevData, &DrvInfoData))
  695. {
  696. pDrvInfoData = &DrvInfoData;
  697. }
  698. else
  699. {
  700. pDrvInfoData = NULL;
  701. }
  702. pDriver = new CDriver();
  703. if (!pDriver) {
  704. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  705. return NULL;
  706. }
  707. // if we have a selected driver and we failed to
  708. // to create the driver, retry it without the selected driver
  709. //
  710. if (pDrvInfoData && pDriver->Create(this, pDrvInfoData)) {
  711. return pDriver;
  712. }
  713. pDriver->Create(this, NULL);
  714. return pDriver;
  715. }
  716. BOOL
  717. CDevice::HasDrivers()
  718. {
  719. HKEY hKey;
  720. BOOL HasDriverKey, HasServiceKey;
  721. CDriver DeviceDriver;
  722. BOOL Result;
  723. HasDriverKey = FALSE;
  724. if (m_pMachine->IsLocal())
  725. {
  726. // open drvice's driver registry key
  727. hKey = m_pMachine->DiOpenDevRegKey(&m_DevData, DICS_FLAG_GLOBAL,
  728. 0, DIREG_DRV, KEY_ALL_ACCESS);
  729. HasDriverKey = INVALID_HANDLE_VALUE != hKey;
  730. if (INVALID_HANDLE_VALUE != hKey)
  731. {
  732. RegCloseKey(hKey);
  733. }
  734. }
  735. DWORD Size = 0;
  736. m_pMachine->DiGetDeviceRegistryProperty(&m_DevData, SPDRP_SERVICE,
  737. NULL, NULL, 0, &Size);
  738. HasServiceKey = (0 != Size);
  739. if (HasServiceKey || HasDriverKey)
  740. {
  741. // either we have a driver or a service key.
  742. // try to find out if we can find any valid driver files.
  743. Result = DeviceDriver.Create(this);
  744. }
  745. else
  746. {
  747. if (m_pMachine->IsLocal() && g_HasLoadDriverNamePrivilege)
  748. {
  749. // If the target machine is local and the user has the
  750. // administrator privilege, we need the driver page
  751. // for users to update the drivers.
  752. //
  753. Result = TRUE;
  754. }
  755. else
  756. {
  757. Result = FALSE;
  758. }
  759. }
  760. return Result;
  761. }
  762. DWORD
  763. CDevice::EnableDisableDevice(
  764. HWND hDlg,
  765. BOOL Enabling
  766. )
  767. {
  768. BOOL Disabling = !Enabling;
  769. BOOL Canceled;
  770. Canceled = FALSE;
  771. DWORD RestartFlags = 0;
  772. DWORD ConfigFlags;
  773. HCURSOR hCursorOld = NULL;
  774. BOOL Refresh = FALSE;
  775. //
  776. // Disable refreshing the TREE while we are enabling/disabling this device
  777. //
  778. m_pMachine->EnableRefresh(FALSE);
  779. if (!GetConfigFlags(&ConfigFlags)) {
  780. ConfigFlags = 0;
  781. }
  782. //
  783. // Only want the disabled bit
  784. //
  785. ConfigFlags &= CONFIGFLAG_DISABLED;
  786. CHwProfileList* pHwProfileList = new CHwProfileList();
  787. if (!pHwProfileList) {
  788. goto clean0;
  789. }
  790. pHwProfileList->Create(this, ConfigFlags);
  791. //
  792. // Get the current profile
  793. //
  794. CHwProfile* phwpf;
  795. if (!(pHwProfileList->GetCurrentHwProfile(&phwpf))) {
  796. goto clean0;
  797. }
  798. //
  799. // Can only enable a device that is currently disabled
  800. //
  801. if (IsStateDisabled() && Enabling) {
  802. phwpf->SetEnablePending();
  803. }
  804. //
  805. // Can only disable a device that is currently enabled
  806. //
  807. else if (!IsStateDisabled() && Disabling) {
  808. phwpf->SetDisablePending();
  809. }
  810. //
  811. // If we don't have a valid enable or disable then exit
  812. //
  813. if (!(phwpf->IsEnablePending()) && !(phwpf->IsDisablePending())) {
  814. goto clean0;
  815. }
  816. //
  817. // This device is not a boot device so just display the normal disable
  818. // warning to the user.
  819. //
  820. if (Disabling) {
  821. int MsgBoxResult;
  822. TCHAR szText[MAX_PATH];
  823. DWORD Size;
  824. Size = LoadResourceString(IDS_WARN_NORMAL_DISABLE, szText, ARRAYLEN(szText));
  825. MsgBoxResult = MessageBox(hDlg,
  826. szText,
  827. GetDisplayName(),
  828. MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2
  829. );
  830. if (IDYES != MsgBoxResult) {
  831. goto clean0;
  832. }
  833. }
  834. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  835. //
  836. // If this isn't a live devnode then we need to do a manual refresh if we
  837. // are diabling the device.
  838. //
  839. Refresh = (!Enabling &&
  840. (IsPhantom() ||
  841. HasProblem() ||
  842. !IsStarted()));
  843. m_pMachine->DiTurnOnDiFlags(*this, DI_NODI_DEFAULTACTION);
  844. SP_PROPCHANGE_PARAMS pcp;
  845. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  846. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  847. //
  848. // Now ask the class installer if the device can be specifically enabled/disabled
  849. //
  850. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  851. pcp.StateChange = DICS_DISABLE;
  852. if (phwpf->IsEnablePending()) {
  853. pcp.StateChange = DICS_ENABLE;
  854. }
  855. pcp.HwProfile = phwpf->GetHwProfile();
  856. m_pMachine->DiSetClassInstallParams(*this,
  857. &pcp.ClassInstallHeader,
  858. sizeof(pcp)
  859. );
  860. m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *this);
  861. Canceled = (ERROR_CANCELLED == GetLastError());
  862. //
  863. // class installer has not objection of our enabling/disabling,
  864. // do real enabling/disabling.
  865. //
  866. if (!Canceled) {
  867. if (phwpf->IsDisablePending()) {
  868. pcp.StateChange = DICS_DISABLE;
  869. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  870. pcp.HwProfile = phwpf->GetHwProfile();
  871. m_pMachine->DiSetClassInstallParams(*this,
  872. &pcp.ClassInstallHeader,
  873. sizeof(pcp)
  874. );
  875. m_pMachine->DiChangeState(*this);
  876. }
  877. else {
  878. //
  879. // We are enabling the device,
  880. // do a specific enabling then a globally enabling.
  881. // the globally enabling will start the device
  882. // The implementation here is different from
  883. // Win9x which does a global enabling, a config
  884. // specific enabling and then a start.
  885. //
  886. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  887. pcp.HwProfile = phwpf->GetHwProfile();
  888. m_pMachine->DiSetClassInstallParams(*this,
  889. &pcp.ClassInstallHeader,
  890. sizeof(pcp)
  891. );
  892. m_pMachine->DiChangeState(*this);
  893. //
  894. // This call will start the device is it not started.
  895. //
  896. pcp.Scope = DICS_FLAG_GLOBAL;
  897. m_pMachine->DiSetClassInstallParams(*this,
  898. &pcp.ClassInstallHeader,
  899. sizeof(pcp)
  900. );
  901. m_pMachine->DiChangeState(*this);
  902. }
  903. if (phwpf->IsEnablePending()) {
  904. phwpf->ResetEnablePending();
  905. }
  906. else if (phwpf->IsDisablePending()) {
  907. phwpf->ResetDisablePending();
  908. }
  909. //
  910. // signal that the property of the device is changed.
  911. //
  912. m_pMachine->DiTurnOnDiFlags(*this, DI_PROPERTIES_CHANGE);
  913. //
  914. // See if we need a restart.
  915. //
  916. RestartFlags |= (m_pMachine->DiGetFlags(*this)) & (DI_NEEDRESTART | DI_NEEDREBOOT);
  917. if (NeedsRestart()) {
  918. RestartFlags |= DI_NEEDRESTART;
  919. }
  920. }
  921. //
  922. // Remove class install parameters, this also reset
  923. // DI_CLASSINATLLPARAMS
  924. //
  925. m_pMachine->DiSetClassInstallParams(*this, NULL, 0);
  926. m_pMachine->DiTurnOffDiFlags(*this, DI_NODI_DEFAULTACTION);
  927. clean0:
  928. if (pHwProfileList) {
  929. delete pHwProfileList;
  930. }
  931. //
  932. // Enable the tree for refreshing.
  933. // We will only schedule a refresh ourselves if the device was not started
  934. // before we tried to disable it, and we are not going to prompt for a reboot.
  935. // In all other cases we should get a WM_DEVICECHANGE which will cause us
  936. // to refresh our tree.
  937. //
  938. if (Refresh && !NeedsRestart()) {
  939. m_pMachine->ScheduleRefresh();
  940. }
  941. m_pMachine->EnableRefresh(TRUE);
  942. if (hCursorOld != NULL) {
  943. SetCursor(hCursorOld);
  944. }
  945. return RestartFlags;
  946. }
  947. BOOL
  948. CDevice::operator ==(
  949. CDevice& OtherDevice
  950. )
  951. {
  952. return \
  953. (*m_pClass == *(OtherDevice.GetClass())) &&
  954. !lstrcmpi(m_strDeviceID, OtherDevice.GetDeviceID()) &&
  955. !lstrcmpi(m_strDisplayName, OtherDevice.GetDisplayName());
  956. }
  957. //
  958. // CComputer implementation
  959. //
  960. CComputer::CComputer(
  961. CMachine* pMachine,
  962. DEVNODE dnRoot
  963. )
  964. {
  965. ASSERT(pMachine);
  966. ASSERT(!GetChild() && !GetParent() && !GetSibling());
  967. m_pMachine = pMachine;
  968. m_strDisplayName.Empty();
  969. m_strDisplayName = pMachine->GetMachineDisplayName();
  970. m_iImage = pMachine->GetComputerIconIndex();
  971. m_dnRoot = dnRoot;
  972. }
  973. inline
  974. CItemIdentifier*
  975. CComputer::CreateIdentifier()
  976. {
  977. return new CComputerIdentifier(*this);
  978. }
  979. CResource::CResource(
  980. CDevice* pDevice,
  981. RESOURCEID ResType,
  982. DWORDLONG dlBase,
  983. DWORDLONG dlLen,
  984. BOOL Forced,
  985. BOOL Free
  986. )
  987. {
  988. m_pChild = NULL;
  989. m_pSibling = NULL;
  990. m_pParent = NULL;
  991. m_ResType = ResType;
  992. m_dlBase = dlBase;
  993. m_dlLen = dlLen;
  994. m_Forced = Forced;
  995. m_dlEnd = m_dlBase + m_dlLen - 1;
  996. m_Allocated = !Free;
  997. ASSERT(pDevice);
  998. m_pDevice = pDevice;
  999. m_iImage = pDevice->GetImageIndex();
  1000. ASSERT(ResType >= ResType_Mem && ResType <= ResType_IRQ);
  1001. m_strDisplayName.Empty();
  1002. m_strDisplayName = pDevice->GetDisplayName();
  1003. if (ResType_IRQ == m_ResType)
  1004. {
  1005. String strBus;
  1006. strBus.LoadString(g_hInstance,
  1007. pDevice->IsPCIDevice() ? IDS_PCI : IDS_ISA
  1008. );
  1009. m_strViewName.Format(TEXT("%2d "), m_dlBase);
  1010. m_strViewName = strBus + m_strViewName;
  1011. }
  1012. else if (ResType_DMA == m_ResType)
  1013. {
  1014. m_strViewName.Format(TEXT("%2d " ), m_dlBase);
  1015. }
  1016. else
  1017. {
  1018. #ifdef _WIN64
  1019. m_strViewName.Format(TEXT("[%016I64X - %016I64X] "), m_dlBase, m_dlEnd);
  1020. #else
  1021. m_strViewName.Format(TEXT("[%08lX - %08lX] "), (ULONG)m_dlBase, (ULONG)m_dlEnd);
  1022. #endif
  1023. }
  1024. if (m_Allocated)
  1025. {
  1026. m_strViewName += pDevice->GetDisplayName();
  1027. }
  1028. }
  1029. void
  1030. CResource::GetRangeString(
  1031. String& strRange
  1032. )
  1033. {
  1034. if (ResType_IRQ == m_ResType ||
  1035. ResType_DMA == m_ResType)
  1036. {
  1037. strRange.Format(TEXT("%2d"), m_dlBase);
  1038. }
  1039. else
  1040. {
  1041. strRange.Format(TEXT("[%08lX - %08lX]"), (ULONG)m_dlBase, (ULONG)m_dlEnd);
  1042. }
  1043. }
  1044. BOOL
  1045. CResource::operator <=(
  1046. const CResource& resSrc
  1047. )
  1048. {
  1049. DWORDLONG dlBase, dlLen;
  1050. resSrc.GetValue(&dlBase, &dlLen);
  1051. if (m_dlBase < dlBase)
  1052. return TRUE;
  1053. // if this resource contain the given resource,
  1054. // we are smaller!
  1055. if (m_dlBase == dlBase)
  1056. return (m_dlBase + m_dlLen > dlBase + dlLen);
  1057. return FALSE;
  1058. }
  1059. BOOL
  1060. CResource::EnclosedBy(
  1061. const CResource& resSrc
  1062. )
  1063. {
  1064. DWORDLONG dlBase, dlLen;
  1065. resSrc.GetValue(&dlBase, &dlLen);
  1066. return m_dlBase >= dlBase && m_dlBase + m_dlLen <= dlBase + dlLen;
  1067. }
  1068. CResourceType::CResourceType(
  1069. CMachine* pMachine,
  1070. RESOURCEID ResType
  1071. )
  1072. {
  1073. int iStringID;
  1074. m_ResType = ResType;
  1075. m_pChild = NULL;
  1076. m_pSibling = NULL;
  1077. m_pParent = NULL;
  1078. m_pMachine = pMachine;
  1079. ASSERT(ResType >= ResType_Mem && ResType <= ResType_IRQ);
  1080. switch (ResType)
  1081. {
  1082. case ResType_IRQ:
  1083. iStringID = IDS_VIEW_RESOURCE_IRQ;
  1084. break;
  1085. case ResType_IO:
  1086. iStringID = IDS_VIEW_RESOURCE_IO;
  1087. break;
  1088. case ResType_DMA:
  1089. iStringID = IDS_VIEW_RESOURCE_DMA;
  1090. break;
  1091. case ResType_Mem:
  1092. iStringID = IDS_VIEW_RESOURCE_MEM;
  1093. break;
  1094. default:
  1095. iStringID = IDS_UNKNOWN;
  1096. break;
  1097. }
  1098. m_strDisplayName.Empty();
  1099. m_strDisplayName.LoadString(g_hInstance, iStringID);
  1100. m_iImage = pMachine->GetResourceIconIndex();
  1101. }
  1102. inline
  1103. CItemIdentifier*
  1104. CResourceType::CreateIdentifier()
  1105. {
  1106. return new CResourceTypeIdentifier(*this);
  1107. }
  1108. // This function creates CResourceList object to contain the designated
  1109. // resources for the given device.
  1110. // INPUT:
  1111. // pDevice -- the device
  1112. // ResType -- what type of resource
  1113. // LogConfType -- what type of logconf
  1114. // OUTPUT:
  1115. // NONE.
  1116. //
  1117. // This function may throw CMemoryException
  1118. //
  1119. CResourceList::CResourceList(
  1120. CDevice* pDevice,
  1121. RESOURCEID ResType,
  1122. ULONG LogConfType,
  1123. ULONG AltLogConfType
  1124. )
  1125. {
  1126. ASSERT(ResType_All != ResType);
  1127. ASSERT(BOOT_LOG_CONF == LogConfType ||
  1128. FORCED_LOG_CONF == LogConfType ||
  1129. ALLOC_LOG_CONF == LogConfType);
  1130. ASSERT(pDevice);
  1131. LOG_CONF lc;
  1132. RES_DES rd, rdPrev;
  1133. rdPrev;
  1134. RESOURCEID ResId;
  1135. BOOL Forced;
  1136. CMachine* pMachine = pDevice->m_pMachine;
  1137. ASSERT(pMachine);
  1138. rdPrev = 0;
  1139. // even though we have a valid logconf, it does not mean
  1140. // GetNextResDes would succeed because the ResType is not
  1141. // ResType_All.
  1142. if (pMachine->CmGetFirstLogConf(pDevice->GetDevNode(), &lc, LogConfType))
  1143. {
  1144. if (pMachine->CmGetNextResDes(&rd, lc, ResType, &ResId))
  1145. {
  1146. ULONG DataSize;
  1147. DWORDLONG dlBase, dlLen;
  1148. do
  1149. {
  1150. DataSize = pMachine->CmGetResDesDataSize(rd);
  1151. if (DataSize)
  1152. {
  1153. BufferPtr<BYTE> DataPtr(DataSize);
  1154. if (pMachine->CmGetResDesData(rd, DataPtr, DataSize))
  1155. {
  1156. // need this to use a different image overlay for
  1157. // forced allocated resource
  1158. Forced = pMachine->CmGetFirstLogConf(pDevice->GetDevNode(),
  1159. NULL, FORCED_LOG_CONF);
  1160. if (ExtractResourceValue(ResType, DataPtr, &dlBase, &dlLen))
  1161. {
  1162. SafePtr<CResource> ResPtr;
  1163. CResource* pRes;
  1164. pRes = new CResource(pDevice, ResType, dlBase,
  1165. dlLen, Forced, FALSE);
  1166. if (pRes)
  1167. {
  1168. ResPtr.Attach(pRes);
  1169. InsertResourceToList(pRes);
  1170. ResPtr.Detach();
  1171. }
  1172. }
  1173. }
  1174. }
  1175. if (rdPrev)
  1176. {
  1177. pMachine->CmFreeResDesHandle(rdPrev);
  1178. }
  1179. rdPrev = rd;
  1180. } while (pMachine->CmGetNextResDes(&rd, rdPrev, ResType, &ResId));
  1181. //free the last resource descriptor handle
  1182. pMachine->CmFreeResDesHandle(rd);
  1183. }
  1184. pMachine->CmFreeLogConfHandle(lc);
  1185. }
  1186. }
  1187. // This function creates CResourceList object to contain the designated
  1188. // resources for the given machine.
  1189. // INPUT:
  1190. // pMachine -- the machine
  1191. // ResType -- what type of resource
  1192. // LogConfType -- what type of logconf
  1193. // OUTPUT:
  1194. // NONE.
  1195. //
  1196. // This function may throw CMemoryException
  1197. //
  1198. CResourceList::CResourceList(
  1199. CMachine* pMachine,
  1200. RESOURCEID ResType,
  1201. ULONG LogConfType,
  1202. ULONG AltLogConfType
  1203. )
  1204. {
  1205. ASSERT(ResType_All != ResType);
  1206. ASSERT(BOOT_LOG_CONF == LogConfType ||
  1207. FORCED_LOG_CONF == LogConfType ||
  1208. ALLOC_LOG_CONF == LogConfType ||
  1209. ALL_LOG_CONF == LogConfType);
  1210. ASSERT(pMachine);
  1211. if (pMachine->GetNumberOfDevices())
  1212. {
  1213. ASSERT(pMachine->m_pComputer && pMachine->m_pComputer->GetChild());
  1214. CDevice* pFirstDevice;
  1215. pFirstDevice = pMachine->m_pComputer->GetChild();
  1216. CreateSubtreeResourceList(pFirstDevice, ResType, LogConfType, AltLogConfType);
  1217. }
  1218. }
  1219. //
  1220. // This function extracts resource value from the provided buffer
  1221. //
  1222. // INPUT:
  1223. // ResType -- resource type the data contain
  1224. // pData -- the raw data
  1225. // pdlBase -- buffer to hold the base of the value
  1226. // pdlLen -- buffer to hold the length of the value
  1227. //
  1228. // OUTPUT:
  1229. // TRUE if this is a valid resource descriptor or FALSE if we should ignore it.
  1230. //
  1231. // NOTE:
  1232. // If the return value is FALSE then pdlBase and pdlLen are not filled in.
  1233. //
  1234. BOOL
  1235. CResourceList::ExtractResourceValue(
  1236. RESOURCEID ResType,
  1237. PVOID pData,
  1238. DWORDLONG* pdlBase,
  1239. DWORDLONG* pdlLen
  1240. )
  1241. {
  1242. BOOL bValidResDes = TRUE;
  1243. ASSERT(pData && pdlBase && pdlLen);
  1244. switch (ResType)
  1245. {
  1246. case ResType_Mem:
  1247. if (pMemResData(pData)->MEM_Header.MD_Alloc_Base <= pMemResData(pData)->MEM_Header.MD_Alloc_End) {
  1248. *pdlBase = pMemResData(pData)->MEM_Header.MD_Alloc_Base;
  1249. *pdlLen = pMemResData(pData)->MEM_Header.MD_Alloc_End -
  1250. *pdlBase + 1;
  1251. } else {
  1252. //
  1253. // If base > end then ignore this resource descriptor
  1254. //
  1255. *pdlBase = 0;
  1256. *pdlLen = 0;
  1257. bValidResDes = FALSE;
  1258. }
  1259. break;
  1260. case ResType_IRQ:
  1261. *pdlBase = pIRQResData(pData)->IRQ_Header.IRQD_Alloc_Num;
  1262. // IRQ len is always 1
  1263. *pdlLen = 1;
  1264. break;
  1265. case ResType_DMA:
  1266. *pdlBase = pDMAResData(pData)->DMA_Header.DD_Alloc_Chan;
  1267. // DMA len is always 1
  1268. *pdlLen = 1;
  1269. break;
  1270. case ResType_IO:
  1271. if (pIOResData(pData)->IO_Header.IOD_Alloc_Base <= pIOResData(pData)->IO_Header.IOD_Alloc_End) {
  1272. *pdlBase = pIOResData(pData)->IO_Header.IOD_Alloc_Base;
  1273. *pdlLen = pIOResData(pData)->IO_Header.IOD_Alloc_End -
  1274. *pdlBase + 1;
  1275. } else {
  1276. //
  1277. // If base > end then ignore this resource descriptor
  1278. //
  1279. *pdlBase = 0;
  1280. *pdlLen = 0;
  1281. bValidResDes = FALSE;
  1282. }
  1283. break;
  1284. default:
  1285. ASSERT(FALSE);
  1286. *pdlBase = 0;
  1287. *pdlLen = 0;
  1288. break;
  1289. }
  1290. return bValidResDes;
  1291. }
  1292. //
  1293. //This function creates resources for the given subtree rooted at
  1294. //the given device
  1295. //
  1296. //INPUT:
  1297. // pDevice -- the root device of the subtree
  1298. // ResType -- resource type to be created
  1299. // LogConfType -- logconf type to be created from
  1300. //
  1301. //OUTPUT:
  1302. // NONE
  1303. //
  1304. // This function may throw CMemoryException
  1305. //
  1306. void
  1307. CResourceList::CreateSubtreeResourceList(
  1308. CDevice* pDeviceStart,
  1309. RESOURCEID ResType,
  1310. ULONG LogConfType,
  1311. ULONG AltLogConfType
  1312. )
  1313. {
  1314. LOG_CONF lc;
  1315. RES_DES rd, rdPrev;
  1316. RESOURCEID ResId;
  1317. BOOL Forced;
  1318. CMachine* pMachine = pDeviceStart->m_pMachine;
  1319. ASSERT(pMachine);
  1320. while (pDeviceStart)
  1321. {
  1322. //
  1323. // We will try to get a LogConf for either the LogConfType (which defaults to
  1324. // ALLOC_LOG_CONF) or the AltLogConfType (which defaults to BOOT_LOG_CONF).
  1325. // We need to do this because on Win2000 a device that only has a BOOT_LOG_CONF
  1326. // will still consume those resources, even if it does not have an ALLOC_LOG_CONF.
  1327. // So we need to first check the ALLOC_LOG_CONF and if that fails check the
  1328. // BOOT_LOG_CONF.
  1329. //
  1330. if (pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), &lc, LogConfType) ||
  1331. pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), &lc, AltLogConfType))
  1332. {
  1333. rdPrev = 0;
  1334. if (pMachine->CmGetNextResDes(&rd, lc, ResType, &ResId))
  1335. {
  1336. ULONG DataSize;
  1337. DWORDLONG dlBase, dlLen;
  1338. do
  1339. {
  1340. DataSize = pMachine->CmGetResDesDataSize(rd);
  1341. if (DataSize)
  1342. {
  1343. // need this to use a different image overlay for
  1344. // forced allocated resource
  1345. Forced = pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(),
  1346. NULL, FORCED_LOG_CONF);
  1347. BufferPtr<BYTE> DataPtr(DataSize);
  1348. if (pMachine->CmGetResDesData(rd, DataPtr, DataSize))
  1349. {
  1350. if (ExtractResourceValue(ResType, DataPtr, &dlBase, &dlLen))
  1351. {
  1352. SafePtr<CResource> ResPtr;
  1353. CResource* pRes;
  1354. pRes = new CResource(pDeviceStart, ResType, dlBase,
  1355. dlLen, Forced, FALSE);
  1356. ResPtr.Attach(pRes);
  1357. InsertResourceToList(pRes);
  1358. ResPtr.Detach();
  1359. }
  1360. }
  1361. }
  1362. if (rdPrev)
  1363. pMachine->CmFreeResDesHandle(rdPrev);
  1364. rdPrev = rd;
  1365. }while (pMachine->CmGetNextResDes(&rd, rdPrev, ResType, &ResId));
  1366. //free the last resource descriptor handle
  1367. pMachine->CmFreeResDesHandle(rd);
  1368. }
  1369. pMachine->CmFreeLogConfHandle(lc);
  1370. }
  1371. if (pDeviceStart->GetChild())
  1372. CreateSubtreeResourceList(pDeviceStart->GetChild(), ResType, LogConfType, AltLogConfType);
  1373. pDeviceStart = pDeviceStart->GetSibling();
  1374. }
  1375. }
  1376. // This function creates a resource tree
  1377. // INPUT:
  1378. // ppResRoot -- buffer to receive the tree root
  1379. //
  1380. BOOL
  1381. CResourceList::CreateResourceTree(
  1382. CResource** ppResRoot
  1383. )
  1384. {
  1385. ASSERT(ppResRoot);
  1386. *ppResRoot = NULL;
  1387. if (!m_listRes.IsEmpty())
  1388. {
  1389. POSITION pos = m_listRes.GetHeadPosition();
  1390. CResource* pResFirst;
  1391. pResFirst = m_listRes.GetNext(pos);
  1392. *ppResRoot = pResFirst;
  1393. while (NULL != pos)
  1394. {
  1395. CResource* pRes = m_listRes.GetNext(pos);
  1396. InsertResourceToTree(pRes, pResFirst, TRUE);
  1397. }
  1398. }
  1399. return TRUE;
  1400. }
  1401. BOOL
  1402. CResourceList::InsertResourceToTree(
  1403. CResource* pRes,
  1404. CResource* pResRoot,
  1405. BOOL ForcedInsert
  1406. )
  1407. {
  1408. CResource* pResLast;
  1409. while (pResRoot)
  1410. {
  1411. if (pRes->EnclosedBy(*pResRoot))
  1412. {
  1413. // this resource is either the pResRoot child or grand child
  1414. // figure out which one it is
  1415. if (!pResRoot->GetChild())
  1416. {
  1417. pResRoot->SetChild(pRes);
  1418. pRes->SetParent(pResRoot);
  1419. }
  1420. else if (!InsertResourceToTree(pRes, pResRoot->GetChild(), FALSE))
  1421. {
  1422. // the Resource is not a grand child of pResRoot.
  1423. // search for the last child of pResRoot
  1424. CResource* pResSibling;
  1425. pResSibling = pResRoot->GetChild();
  1426. while (pResSibling->GetSibling())
  1427. pResSibling = pResSibling->GetSibling();
  1428. pResSibling->SetSibling(pRes);
  1429. pRes->SetParent(pResRoot);
  1430. }
  1431. return TRUE;
  1432. }
  1433. pResLast = pResRoot;
  1434. pResRoot = pResRoot->GetSibling();
  1435. }
  1436. if (ForcedInsert)
  1437. {
  1438. // when we reach here, pResLast is the last child
  1439. pResLast->SetSibling(pRes);
  1440. pRes->SetParent(pResLast->GetParent());
  1441. return TRUE;
  1442. }
  1443. return FALSE;
  1444. }
  1445. CResourceList::~CResourceList()
  1446. {
  1447. if (!m_listRes.IsEmpty())
  1448. {
  1449. POSITION pos = m_listRes.GetHeadPosition();
  1450. while (NULL != pos)
  1451. {
  1452. delete m_listRes.GetNext(pos);
  1453. }
  1454. m_listRes.RemoveAll();
  1455. }
  1456. }
  1457. BOOL
  1458. CResourceList::GetFirst(
  1459. CResource** ppRes,
  1460. PVOID& Context
  1461. )
  1462. {
  1463. ASSERT(ppRes);
  1464. if (!m_listRes.IsEmpty())
  1465. {
  1466. POSITION pos = m_listRes.GetHeadPosition();
  1467. *ppRes = m_listRes.GetNext(pos);
  1468. Context = pos;
  1469. return TRUE;
  1470. }
  1471. Context = NULL;
  1472. *ppRes = NULL;
  1473. return FALSE;
  1474. }
  1475. BOOL
  1476. CResourceList::GetNext(
  1477. CResource** ppRes,
  1478. PVOID& Context
  1479. )
  1480. {
  1481. ASSERT(ppRes);
  1482. POSITION pos = (POSITION)Context;
  1483. if (NULL != pos)
  1484. {
  1485. *ppRes = m_listRes.GetNext(pos);
  1486. Context = pos;
  1487. return TRUE;
  1488. }
  1489. *ppRes = NULL;
  1490. return FALSE;
  1491. }
  1492. //
  1493. // This function inserts the given resource to class's resource list
  1494. // The resources are kept in accending sorted order
  1495. void
  1496. CResourceList::InsertResourceToList(
  1497. CResource* pRes
  1498. )
  1499. {
  1500. POSITION pos;
  1501. CResource* pSrc;
  1502. DWORDLONG dlBase, dlLen;
  1503. pRes->GetValue(&dlBase, &dlLen);
  1504. pos = m_listRes.GetHeadPosition();
  1505. while (NULL != pos)
  1506. {
  1507. POSITION posSave = pos;
  1508. pSrc = m_listRes.GetNext(pos);
  1509. if (*pRes <= *pSrc)
  1510. {
  1511. m_listRes.InsertBefore(posSave, pRes);
  1512. return;
  1513. }
  1514. }
  1515. m_listRes.AddTail(pRes);
  1516. }
  1517. inline
  1518. CItemIdentifier*
  1519. CResource::CreateIdentifier()
  1520. {
  1521. return new CResourceIdentifier(*this);
  1522. }