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.

1111 lines
31 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: devtree.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "HotPlug.h"
  11. //
  12. // Define and initialize all device class GUIDs.
  13. // (This must only be done once per module!)
  14. //
  15. #include <initguid.h>
  16. #include <devguid.h>
  17. //
  18. // Define and initialize a global variable, GUID_NULL
  19. // (from coguid.h)
  20. //
  21. DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  22. PDEVINST
  23. BuildDeviceRelationsList(
  24. PTCHAR DeviceId,
  25. HMACHINE hMachine,
  26. ULONG FilterFlag,
  27. PUSHORT pNumDevinst
  28. )
  29. {
  30. ULONG Len, NumDevinst, MaxDevinst;
  31. USHORT NumDevInst;
  32. CONFIGRET ConfigRet;
  33. PTCHAR DeviceIdRelations = NULL, CurrDevId;
  34. PDEVINST DevinstRelations = NULL;
  35. DevinstRelations = NULL;
  36. DeviceIdRelations = NULL;
  37. NumDevInst = 0;
  38. Len = 0;
  39. ConfigRet = CM_Get_Device_ID_List_Size_Ex(&Len,
  40. DeviceId,
  41. FilterFlag,
  42. hMachine
  43. );
  44. if (ConfigRet == CR_SUCCESS && Len) {
  45. DeviceIdRelations = (PTCHAR)LocalAlloc(LPTR, Len*sizeof(TCHAR));
  46. if (!DeviceIdRelations) {
  47. goto BDEarlyExit;
  48. }
  49. *DeviceIdRelations = TEXT('\0');
  50. if (DeviceIdRelations) {
  51. ConfigRet = CM_Get_Device_ID_List_Ex(DeviceId,
  52. DeviceIdRelations,
  53. Len,
  54. FilterFlag,
  55. hMachine
  56. );
  57. if (ConfigRet != CR_SUCCESS || !*DeviceIdRelations) {
  58. goto BDEarlyExit;
  59. }
  60. }
  61. }
  62. if (!Len) {
  63. goto BDEarlyExit;
  64. }
  65. //
  66. // Convert the deviceId list into a Devinst list. We make the gross
  67. // assumption that the Devinst list will NOT be bigger than the deviceId
  68. // list.
  69. //
  70. Len = (Len + sizeof(DEVINST) - 1) & ~(sizeof(DEVINST) - 1);
  71. MaxDevinst = Len / sizeof(DEVINST);
  72. DevinstRelations = (PDEVINST)LocalAlloc(LPTR, Len);
  73. if (!DevinstRelations) {
  74. goto BDEarlyExit;
  75. }
  76. for (CurrDevId = DeviceIdRelations; *CurrDevId; CurrDevId += lstrlen(CurrDevId) + 1) {
  77. ConfigRet = CM_Locate_DevNode_Ex(&DevinstRelations[NumDevInst],
  78. CurrDevId,
  79. CM_LOCATE_DEVNODE_NORMAL,
  80. hMachine
  81. );
  82. if (ConfigRet == CR_SUCCESS) {
  83. if (++NumDevInst >= MaxDevinst) {
  84. //
  85. // paranoia check, if our devinst size wasn't big enough
  86. // the id list is probably trashed. so just give up.
  87. //
  88. break;
  89. }
  90. }
  91. }
  92. BDEarlyExit:
  93. if (DeviceIdRelations) {
  94. LocalFree(DeviceIdRelations);
  95. }
  96. if (DevinstRelations) {
  97. if (NumDevInst) {
  98. PDEVINST DeviceInstance;
  99. Len = NumDevInst * sizeof(DEVINST);
  100. DeviceInstance = (PDEVINST)LocalReAlloc(DevinstRelations, Len, LMEM_FIXED);
  101. if (DeviceInstance) {
  102. DevinstRelations = DeviceInstance;
  103. }
  104. }
  105. else {
  106. LocalFree(DevinstRelations);
  107. DevinstRelations = NULL;
  108. }
  109. }
  110. *pNumDevinst = NumDevInst;
  111. return DevinstRelations;
  112. }
  113. LONG
  114. AddChildSiblings(
  115. PDEVICETREE DeviceTree,
  116. PDEVTREENODE ParentNode,
  117. DEVINST DeviceInstance,
  118. int TreeDepth,
  119. BOOL Recurse
  120. )
  121. {
  122. DWORD Len;
  123. CONFIGRET ConfigRet;
  124. DEVINST ChildDeviceInstance;
  125. PDEVTREENODE DeviceTreeNode;
  126. PLIST_ENTRY ChildSiblingList;
  127. TCHAR Buffer[MAX_PATH];
  128. DWORD NumRelations;
  129. PDEVINST pDevInst;
  130. ChildSiblingList = ParentNode ? &ParentNode->ChildSiblingList
  131. : &DeviceTree->ChildSiblingList;
  132. if (!ParentNode) {
  133. InitializeListHead(ChildSiblingList);
  134. }
  135. if (TreeDepth > DeviceTree->TreeDepth) {
  136. DeviceTree->TreeDepth = TreeDepth;
  137. }
  138. do {
  139. DeviceTreeNode = (PDEVTREENODE)LocalAlloc(LPTR, sizeof(DEVTREENODE));
  140. if (!DeviceTreeNode) {
  141. return ERROR_NOT_ENOUGH_MEMORY;
  142. }
  143. memset(DeviceTreeNode, 0, sizeof(DEVTREENODE));
  144. InsertTailList(ChildSiblingList, &DeviceTreeNode->SiblingEntry);
  145. DeviceTreeNode->ParentNode = ParentNode;
  146. //
  147. // fill in info about this device instance.
  148. //
  149. InitializeListHead(&DeviceTreeNode->ChildSiblingList);
  150. DeviceTreeNode->DevInst = DeviceInstance;
  151. DeviceTreeNode->TreeDepth = TreeDepth;
  152. //
  153. // Get ClassGUID, and class name.
  154. //
  155. Len = sizeof(Buffer);
  156. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DeviceInstance,
  157. CM_DRP_CLASSGUID,
  158. NULL,
  159. &Buffer,
  160. &Len,
  161. 0,
  162. DeviceTree->hMachine
  163. );
  164. if (ConfigRet == CR_SUCCESS) {
  165. pSetupGuidFromString(Buffer, &DeviceTreeNode->ClassGuid);
  166. }
  167. //
  168. // try fetching the class name from the Class GUID.
  169. // if that fails we will use the devnodes classname
  170. //
  171. *Buffer = TEXT('\0');
  172. Len = SIZECHARS(Buffer);
  173. ConfigRet = CM_Get_Class_Name_Ex(&DeviceTreeNode->ClassGuid,
  174. Buffer,
  175. &Len,
  176. 0,
  177. DeviceTree->hMachine
  178. );
  179. if (ConfigRet == CR_SUCCESS && *Buffer) {
  180. Len *= sizeof(TCHAR); // len includes term null.
  181. }
  182. else if (ConfigRet != CR_SUCCESS || !*Buffer) {
  183. *Buffer = TEXT('\0');
  184. Len = sizeof(Buffer);
  185. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(
  186. DeviceInstance,
  187. CM_DRP_CLASS,
  188. NULL,
  189. (PVOID)Buffer,
  190. &Len,
  191. 0,
  192. DeviceTree->hMachine
  193. );
  194. if (ConfigRet != CR_SUCCESS || !*Buffer) {
  195. Len = 0;
  196. }
  197. }
  198. if (Len) {
  199. DeviceTreeNode->ClassName = (PTCHAR)LocalAlloc(LPTR, Len);
  200. if (DeviceTreeNode->ClassName) {
  201. memcpy(DeviceTreeNode->ClassName, Buffer, Len);
  202. }
  203. }
  204. //
  205. // Drive list
  206. //
  207. DeviceTreeNode->DriveList = DevNodeToDriveLetter(DeviceInstance);
  208. //
  209. // FriendlyName
  210. //
  211. *Buffer = TEXT('\0');
  212. Len = sizeof(Buffer);
  213. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DeviceInstance,
  214. CM_DRP_FRIENDLYNAME,
  215. NULL,
  216. Buffer,
  217. &Len,
  218. 0,
  219. DeviceTree->hMachine
  220. );
  221. if (ConfigRet == CR_SUCCESS && *Buffer) {
  222. if (DeviceTreeNode->DriveList) {
  223. Len += lstrlen(DeviceTreeNode->DriveList) * sizeof(TCHAR);
  224. }
  225. DeviceTreeNode->FriendlyName = (PTCHAR)LocalAlloc(LPTR, Len);
  226. if (DeviceTreeNode->FriendlyName) {
  227. memcpy(DeviceTreeNode->FriendlyName, Buffer, Len);
  228. if (DeviceTreeNode->DriveList) {
  229. lstrcat(DeviceTreeNode->FriendlyName, DeviceTreeNode->DriveList);
  230. }
  231. }
  232. }
  233. else {
  234. DeviceTreeNode->FriendlyName = NULL;
  235. }
  236. //
  237. // DeviceDesc
  238. //
  239. *Buffer = TEXT('\0');
  240. Len = sizeof(Buffer);
  241. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(
  242. DeviceInstance,
  243. CM_DRP_DEVICEDESC,
  244. NULL,
  245. (PVOID)Buffer,
  246. &Len,
  247. 0,
  248. DeviceTree->hMachine
  249. );
  250. if (ConfigRet == CR_SUCCESS && *Buffer) {
  251. if (DeviceTreeNode->DriveList) {
  252. Len += lstrlen(DeviceTreeNode->DriveList) * sizeof(TCHAR);
  253. }
  254. DeviceTreeNode->DeviceDesc = (PTCHAR)LocalAlloc(LPTR, Len);
  255. if (DeviceTreeNode->DeviceDesc) {
  256. memcpy(DeviceTreeNode->DeviceDesc, Buffer, Len);
  257. if (DeviceTreeNode->DriveList) {
  258. lstrcat(DeviceTreeNode->DeviceDesc, DeviceTreeNode->DriveList);
  259. }
  260. }
  261. }
  262. else {
  263. DeviceTreeNode->DeviceDesc = NULL;
  264. }
  265. //
  266. // Device capabilities
  267. //
  268. Len = sizeof(DeviceTreeNode->Capabilities);
  269. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(
  270. DeviceInstance,
  271. CM_DRP_CAPABILITIES,
  272. NULL,
  273. (PVOID)&DeviceTreeNode->Capabilities,
  274. &Len,
  275. 0,
  276. DeviceTree->hMachine
  277. );
  278. if (ConfigRet != CR_SUCCESS) {
  279. DeviceTreeNode->Capabilities = 0;
  280. }
  281. //
  282. // Status and Problem number
  283. //
  284. ConfigRet = CM_Get_DevNode_Status_Ex(&DeviceTreeNode->DevNodeStatus,
  285. &DeviceTreeNode->Problem,
  286. DeviceInstance,
  287. 0,
  288. DeviceTree->hMachine
  289. );
  290. if (ConfigRet != CR_SUCCESS) {
  291. DeviceTreeNode->DevNodeStatus = 0;
  292. DeviceTreeNode->Problem = 0;
  293. }
  294. //
  295. // We need to do the following special case. If a device is not started and
  296. // it doesn't have a problem and it is a RAW device then give it a problem
  297. // CM_PROB_FAILED_START.
  298. //
  299. if (!(DeviceTreeNode->DevNodeStatus & DN_STARTED) &&
  300. !(DeviceTreeNode->DevNodeStatus & DN_HAS_PROBLEM) &&
  301. (DeviceTreeNode->Capabilities & CM_DEVCAP_RAWDEVICEOK)) {
  302. DeviceTreeNode->Problem = CM_PROB_FAILED_START;
  303. }
  304. //
  305. // LocationInformation
  306. //
  307. DeviceTreeNode->Location = BuildLocationInformation(DeviceInstance,
  308. DeviceTree->hMachine
  309. );
  310. //
  311. // Get InstanceId
  312. //
  313. *Buffer = TEXT('\0');
  314. Len = sizeof(Buffer);
  315. ConfigRet = CM_Get_Device_ID_ExW(DeviceInstance,
  316. Buffer,
  317. Len/sizeof(TCHAR),
  318. 0,
  319. DeviceTree->hMachine
  320. );
  321. if (ConfigRet == CR_SUCCESS && *Buffer) {
  322. Len = lstrlen(Buffer) * sizeof(TCHAR) + sizeof(TCHAR);
  323. DeviceTreeNode->InstanceId = (PTCHAR)LocalAlloc(LPTR, Len);
  324. if (DeviceTreeNode->InstanceId) {
  325. memcpy(DeviceTreeNode->InstanceId, Buffer, Len);
  326. }
  327. }
  328. else {
  329. DeviceTreeNode->InstanceId = NULL;
  330. }
  331. //
  332. // Fetch removal and eject relations
  333. //
  334. if (ConfigRet == CR_SUCCESS) {
  335. DeviceTreeNode->EjectRelations = BuildDeviceRelationsList(
  336. Buffer,
  337. DeviceTree->hMachine,
  338. CM_GETIDLIST_FILTER_EJECTRELATIONS,
  339. &DeviceTreeNode->NumEjectRelations
  340. );
  341. DeviceTreeNode->RemovalRelations = BuildDeviceRelationsList(
  342. Buffer,
  343. DeviceTree->hMachine,
  344. CM_GETIDLIST_FILTER_REMOVALRELATIONS,
  345. &DeviceTreeNode->NumRemovalRelations
  346. );
  347. }
  348. //
  349. // Only get children and siblings if the Recurse value was TRUE
  350. // otherwise we will just build a DeviceTreeNode structure for
  351. // the individual devnode that was passed in.
  352. //
  353. // Also, only add rejection and removal relations when Recurse is TRUE,
  354. // otherwise we get messed up if two devices have removal or ejection
  355. // relations to each other.
  356. //
  357. if (Recurse) {
  358. LPTSTR tempDriveList;
  359. DeviceTreeNode->bCopy = FALSE;
  360. //
  361. // Add Ejection relation drive letters
  362. //
  363. NumRelations = DeviceTreeNode->NumEjectRelations;
  364. pDevInst = DeviceTreeNode->EjectRelations;
  365. while (NumRelations--) {
  366. if (tempDriveList = DevNodeToDriveLetter(*pDevInst)) {
  367. AddChildSiblings(DeviceTree,
  368. DeviceTreeNode,
  369. *pDevInst,
  370. TreeDepth+1,
  371. FALSE
  372. );
  373. LocalFree(tempDriveList);
  374. }
  375. pDevInst++;
  376. }
  377. //
  378. // Add Removal relation drive letters
  379. //
  380. NumRelations = DeviceTreeNode->NumRemovalRelations;
  381. pDevInst = DeviceTreeNode->RemovalRelations;
  382. while (NumRelations--) {
  383. if (tempDriveList = DevNodeToDriveLetter(*pDevInst)) {
  384. AddChildSiblings(DeviceTree,
  385. DeviceTreeNode,
  386. *pDevInst,
  387. TreeDepth+1,
  388. FALSE
  389. );
  390. LocalFree(tempDriveList);
  391. }
  392. pDevInst++;
  393. }
  394. //
  395. // If this devinst has children, then recurse to fill in its
  396. // child sibling list.
  397. //
  398. ConfigRet = CM_Get_Child_Ex(&ChildDeviceInstance,
  399. DeviceInstance,
  400. 0,
  401. DeviceTree->hMachine
  402. );
  403. if (ConfigRet == CR_SUCCESS) {
  404. AddChildSiblings(DeviceTree,
  405. DeviceTreeNode,
  406. ChildDeviceInstance,
  407. TreeDepth+1,
  408. TRUE
  409. );
  410. }
  411. //
  412. // Next sibling ...
  413. //
  414. ConfigRet = CM_Get_Sibling_Ex(&DeviceInstance,
  415. DeviceInstance,
  416. 0,
  417. DeviceTree->hMachine
  418. );
  419. } else {
  420. //
  421. // If Recurse is FALSE then we are making a Copy of an already existing DeviceTreeNode.
  422. // We do this when a HotPlug Device has a relation that will get removed when it gets
  423. // removed. We need to set the bCopy flag because in certain cases the HotPlug device's
  424. // relation is also a HotPlug device. If we don't mark that it is a copy then it will
  425. // get added to the list of removeable devices twice.
  426. //
  427. DeviceTreeNode->bCopy = TRUE;
  428. }
  429. } while (Recurse && (ConfigRet == CR_SUCCESS));
  430. return ERROR_SUCCESS;
  431. }
  432. void
  433. RemoveChildSiblings(
  434. PDEVICETREE DeviceTree,
  435. PLIST_ENTRY ChildSiblingList
  436. )
  437. {
  438. PLIST_ENTRY Next;
  439. TV_INSERTSTRUCT tvi;
  440. PDEVTREENODE DeviceTreeNode;
  441. Next = ChildSiblingList->Flink;
  442. while (Next != ChildSiblingList) {
  443. DeviceTreeNode = CONTAINING_RECORD(Next, DEVTREENODE, SiblingEntry);
  444. //
  445. // recurse to free this nodes ChildSiblingList
  446. //
  447. if (!IsListEmpty(&DeviceTreeNode->ChildSiblingList)) {
  448. RemoveChildSiblings(DeviceTree,
  449. &DeviceTreeNode->ChildSiblingList
  450. );
  451. }
  452. //
  453. // free up this node and move on to the next sibling.
  454. //
  455. Next = Next->Flink;
  456. RemoveEntryList(&DeviceTreeNode->SiblingEntry);
  457. if (DeviceTreeNode->ClassName) {
  458. LocalFree(DeviceTreeNode->ClassName);
  459. }
  460. if (DeviceTreeNode->FriendlyName) {
  461. LocalFree(DeviceTreeNode->FriendlyName);
  462. }
  463. if (DeviceTreeNode->DeviceDesc) {
  464. LocalFree(DeviceTreeNode->DeviceDesc);
  465. }
  466. if (DeviceTreeNode->DriveList) {
  467. LocalFree(DeviceTreeNode->DriveList);
  468. }
  469. if (DeviceTreeNode->Location) {
  470. LocalFree(DeviceTreeNode->Location);
  471. }
  472. if (DeviceTreeNode->InstanceId) {
  473. LocalFree(DeviceTreeNode->InstanceId);
  474. }
  475. if (DeviceTreeNode->EjectRelations) {
  476. LocalFree(DeviceTreeNode->EjectRelations);
  477. }
  478. if (DeviceTreeNode->RemovalRelations) {
  479. LocalFree(DeviceTreeNode->RemovalRelations);
  480. }
  481. if (DeviceTree->SelectedTreeNode == DeviceTreeNode) {
  482. DeviceTree->SelectedTreeNode = NULL;
  483. }
  484. memset(DeviceTreeNode, 0, sizeof(DeviceTreeNode));
  485. LocalFree(DeviceTreeNode);
  486. }
  487. return;
  488. }
  489. /*
  490. * Retrives the UI Device Name from the DeviceTreeNode.
  491. * It is chosen from the following device registry fields
  492. * (in order of preference):
  493. * - FriendlyName
  494. * - DeviceDescription
  495. * - ClassName
  496. * - Location
  497. *
  498. * if none of the above is available uses "Unknown"
  499. *
  500. */
  501. PTCHAR
  502. FetchDeviceName(
  503. PDEVTREENODE DeviceTreeNode
  504. )
  505. {
  506. if (DeviceTreeNode->FriendlyName) {
  507. return DeviceTreeNode->FriendlyName;
  508. }
  509. if (DeviceTreeNode->DeviceDesc) {
  510. return DeviceTreeNode->DeviceDesc;
  511. }
  512. if (DeviceTreeNode->ClassName &&
  513. !IsEqualGUID(DeviceTreeNode->ClassGuid, GUID_NULL) &&
  514. !IsEqualGUID(DeviceTreeNode->ClassGuid, GUID_DEVCLASS_UNKNOWN))
  515. {
  516. return DeviceTreeNode->ClassName;
  517. }
  518. //
  519. // darn everything failed
  520. //
  521. return NULL;
  522. }
  523. BOOL
  524. DisplayChildSiblings(
  525. PDEVICETREE DeviceTree,
  526. PLIST_ENTRY ChildSiblingList,
  527. HTREEITEM hParentTreeItem,
  528. BOOL HotPlugParent
  529. )
  530. {
  531. PLIST_ENTRY Next;
  532. CONFIGRET ConfigRet;
  533. PDEVTREENODE DeviceTreeNode;
  534. TV_INSERTSTRUCT tvi;
  535. BOOL ChildDisplayed = FALSE;
  536. Next = ChildSiblingList->Flink;
  537. while (Next != ChildSiblingList) {
  538. DeviceTreeNode = CONTAINING_RECORD(Next, DEVTREENODE, SiblingEntry);
  539. //
  540. // - If this device has a hotplug parent and we are in the complex view then
  541. // add this device to the tree.
  542. // - If this device is a hotplug device and it is not a bCopy then add this device
  543. // to the tree. A bCopy device is one where we create another DeviceTreeNode structure
  544. // for a device that is a relation of a hotplug device. The problem is that this relation
  545. // itself could be a hotplug device and we don't want to show to copies of it in the UI.
  546. //
  547. if (!DeviceTree->HotPlugTree ||
  548. (HotPlugParent && DeviceTree->ComplexView) ||
  549. (!DeviceTreeNode->bCopy && IsHotPlugDevice(DeviceTreeNode->DevInst, DeviceTree->hMachine)))
  550. {
  551. tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE ;
  552. if (SetupDiGetClassImageIndex(&DeviceTree->ClassImageList,
  553. &DeviceTreeNode->ClassGuid,
  554. &tvi.item.iImage
  555. ))
  556. {
  557. tvi.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  558. }
  559. tvi.hParent = hParentTreeItem;
  560. tvi.hInsertAfter = TVI_LAST;
  561. tvi.item.iSelectedImage = tvi.item.iImage;
  562. tvi.item.pszText = FetchDeviceName(DeviceTreeNode);
  563. if (!tvi.item.pszText) {
  564. tvi.item.pszText = szUnknown;
  565. }
  566. tvi.item.lParam = (LPARAM)DeviceTreeNode;
  567. tvi.item.stateMask = TVIS_OVERLAYMASK;
  568. if (DeviceTreeNode->Problem == CM_PROB_DISABLED) {
  569. tvi.item.state = INDEXTOOVERLAYMASK(IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
  570. } else if (DeviceTreeNode->Problem) {
  571. tvi.item.state = INDEXTOOVERLAYMASK(IDI_PROBLEM_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
  572. } else {
  573. tvi.item.state = INDEXTOOVERLAYMASK(0);
  574. }
  575. DeviceTreeNode->hTreeItem = TreeView_InsertItem(DeviceTree->hwndTree, &tvi);
  576. ChildDisplayed = TRUE;
  577. } else {
  578. DeviceTreeNode->hTreeItem = NULL;
  579. }
  580. //
  581. // recurse to display this nodes ChildSiblingList
  582. //
  583. if (!IsListEmpty(&DeviceTreeNode->ChildSiblingList)) {
  584. if (DisplayChildSiblings(DeviceTree,
  585. &DeviceTreeNode->ChildSiblingList,
  586. DeviceTree->ComplexView ? DeviceTreeNode->hTreeItem
  587. : hParentTreeItem,
  588. DeviceTreeNode->hTreeItem != NULL
  589. ))
  590. {
  591. ChildDisplayed = TRUE;
  592. //
  593. // if we are at the root expand the list of child items.
  594. //
  595. if (DeviceTreeNode->hTreeItem && DeviceTree->ComplexView) {
  596. TreeView_Expand(DeviceTree->hwndTree,
  597. DeviceTreeNode->hTreeItem,
  598. TVE_EXPAND
  599. );
  600. }
  601. }
  602. }
  603. //
  604. // and on to the next sibling.
  605. //
  606. Next = Next->Flink;
  607. }
  608. return ChildDisplayed;
  609. }
  610. void
  611. AddChildRemoval(
  612. PDEVICETREE DeviceTree,
  613. PLIST_ENTRY ChildSiblingList
  614. )
  615. {
  616. PLIST_ENTRY Next;
  617. PDEVTREENODE DeviceTreeNode;
  618. PDEVTREENODE FirstDeviceTreeNode;
  619. if (IsListEmpty(ChildSiblingList)) {
  620. return;
  621. }
  622. FirstDeviceTreeNode = DeviceTree->ChildRemovalList;
  623. Next = ChildSiblingList->Flink;
  624. while (Next != ChildSiblingList) {
  625. DeviceTreeNode = CONTAINING_RECORD(Next, DEVTREENODE, SiblingEntry);
  626. DeviceTreeNode->NextChildRemoval = FirstDeviceTreeNode->NextChildRemoval;
  627. FirstDeviceTreeNode->NextChildRemoval = DeviceTreeNode;
  628. InvalidateTreeItemRect(DeviceTree->hwndTree, DeviceTreeNode->hTreeItem);
  629. //
  630. // recurse to Add this node's Childs
  631. //
  632. AddChildRemoval(DeviceTree, &DeviceTreeNode->ChildSiblingList);
  633. //
  634. // and on to the next sibling.
  635. //
  636. Next = Next->Flink;
  637. }
  638. return;
  639. }
  640. void
  641. ClearRemovalList(
  642. PDEVICETREE DeviceTree
  643. )
  644. {
  645. PDEVTREENODE Next;
  646. PDEVTREENODE DeviceTreeNode;
  647. DeviceTreeNode = DeviceTree->ChildRemovalList;
  648. if (!DeviceTreeNode) {
  649. return;
  650. }
  651. do {
  652. Next = DeviceTreeNode->NextChildRemoval;
  653. DeviceTreeNode->NextChildRemoval = NULL;
  654. //
  655. // force redraw of this item to reset the colors
  656. //
  657. InvalidateTreeItemRect(DeviceTree->hwndTree, DeviceTreeNode->hTreeItem);
  658. DeviceTreeNode = Next;
  659. } while (DeviceTreeNode != DeviceTree->ChildRemovalList);
  660. DeviceTree->ChildRemovalList = NULL;
  661. }
  662. PDEVTREENODE
  663. DevTreeNodeByInstanceId(
  664. PTCHAR InstanceId,
  665. PLIST_ENTRY ChildSiblingList
  666. )
  667. {
  668. PLIST_ENTRY Next;
  669. PDEVTREENODE DeviceTreeNode;
  670. if (!InstanceId) {
  671. return NULL;
  672. }
  673. Next = ChildSiblingList->Flink;
  674. while (Next != ChildSiblingList) {
  675. DeviceTreeNode = CONTAINING_RECORD(Next, DEVTREENODE, SiblingEntry);
  676. if (DeviceTreeNode->InstanceId &&
  677. !lstrcmp(DeviceTreeNode->InstanceId, InstanceId))
  678. {
  679. return DeviceTreeNode;
  680. }
  681. //
  682. // recurse to display this nodes ChildSiblingList
  683. //
  684. if (!IsListEmpty(&DeviceTreeNode->ChildSiblingList)) {
  685. DeviceTreeNode = DevTreeNodeByInstanceId(InstanceId,
  686. &DeviceTreeNode->ChildSiblingList
  687. );
  688. if (DeviceTreeNode) {
  689. return DeviceTreeNode;
  690. }
  691. }
  692. //
  693. // and on to the next sibling.
  694. //
  695. Next = Next->Flink;
  696. }
  697. return NULL;
  698. }
  699. PDEVTREENODE
  700. DevTreeNodeByDevInst(
  701. DEVINST DevInst,
  702. PLIST_ENTRY ChildSiblingList
  703. )
  704. {
  705. PLIST_ENTRY Next;
  706. PDEVTREENODE DeviceTreeNode;
  707. if (!DevInst) {
  708. return NULL;
  709. }
  710. Next = ChildSiblingList->Flink;
  711. while (Next != ChildSiblingList) {
  712. DeviceTreeNode = CONTAINING_RECORD(Next, DEVTREENODE, SiblingEntry);
  713. //
  714. // We currently assume that we can compare DEVINST from separate
  715. // "CM_Locate_Devnode" invocations, since a DEVINST is not a real
  716. // handle, but a pointer to a globalstring table.
  717. //
  718. if (DevInst == DeviceTreeNode->DevInst) {
  719. return DeviceTreeNode;
  720. }
  721. //
  722. // recurse to display this nodes ChildSiblingList
  723. //
  724. if (!IsListEmpty(&DeviceTreeNode->ChildSiblingList)) {
  725. DeviceTreeNode = DevTreeNodeByDevInst(DevInst,
  726. &DeviceTreeNode->ChildSiblingList
  727. );
  728. if (DeviceTreeNode) {
  729. return DeviceTreeNode;
  730. }
  731. }
  732. //
  733. // and on to the next sibling.
  734. //
  735. Next = Next->Flink;
  736. }
  737. return NULL;
  738. }
  739. PDEVTREENODE
  740. TopLevelRemovalNode(
  741. PDEVICETREE DeviceTree,
  742. PDEVTREENODE DeviceTreeNode
  743. )
  744. {
  745. PDEVTREENODE ParentNode = DeviceTreeNode;
  746. while (ParentNode) {
  747. DeviceTreeNode = ParentNode;
  748. if (IsHotPlugDevice(ParentNode->DevInst, DeviceTree->hMachine)) {
  749. return ParentNode;
  750. }
  751. ParentNode = ParentNode->ParentNode;
  752. }
  753. return DeviceTreeNode;
  754. }
  755. void
  756. AddEjectToRemoval(
  757. PDEVICETREE DeviceTree
  758. )
  759. {
  760. PDEVTREENODE RelationTreeNode;
  761. PDEVTREENODE DeviceTreeNode;
  762. PDEVINST pDevInst;
  763. USHORT NumRelations;
  764. //
  765. // For each DeviceTreeNode in the removal list
  766. // If it has ejection or removal relations, add it to the removal list.
  767. //
  768. DeviceTreeNode = DeviceTree->ChildRemovalList;
  769. if (!DeviceTreeNode) {
  770. return;
  771. }
  772. do {
  773. //
  774. // Ejection Relations
  775. //
  776. NumRelations = DeviceTreeNode->NumEjectRelations;
  777. pDevInst = DeviceTreeNode->EjectRelations;
  778. while (NumRelations--) {
  779. RelationTreeNode = DevTreeNodeByDevInst(*pDevInst++,
  780. &DeviceTree->ChildSiblingList
  781. );
  782. //
  783. // If we can't get a DeviceTreeNode for this device, or it is already
  784. // in the list of devices that will be removed (it's NextChildRemoval)
  785. // is non-NULL then we won't add this device to the list that will be removed.
  786. //
  787. // If this is a drive letter devnode then we have also already added it to
  788. // the list so we can skip it.
  789. //
  790. if (!RelationTreeNode ||
  791. RelationTreeNode->NextChildRemoval ||
  792. RelationTreeNode->DriveList) {
  793. continue;
  794. }
  795. //
  796. // Insert the new devtreenode
  797. //
  798. RelationTreeNode->NextChildRemoval = DeviceTreeNode->NextChildRemoval;
  799. DeviceTreeNode->NextChildRemoval = RelationTreeNode;
  800. }
  801. //
  802. // Removal Relations
  803. //
  804. NumRelations = DeviceTreeNode->NumRemovalRelations;
  805. pDevInst = DeviceTreeNode->RemovalRelations;
  806. while (NumRelations--) {
  807. RelationTreeNode = DevTreeNodeByDevInst(*pDevInst++,
  808. &DeviceTree->ChildSiblingList
  809. );
  810. //
  811. // If we can't get a DeviceTreeNode for this device, or it is already
  812. // in the list of devices that will be removed (it's NextChildRemoval)
  813. // is non-NULL then we won't add this device to the list that will be removed.
  814. //
  815. // If this is a drive letter devnode then we have also already added it to
  816. // the list so we can skip it.
  817. //
  818. if (!RelationTreeNode ||
  819. RelationTreeNode->NextChildRemoval ||
  820. RelationTreeNode->DriveList) {
  821. continue;
  822. }
  823. //
  824. // Insert the new devtreenode
  825. //
  826. RelationTreeNode->NextChildRemoval = DeviceTreeNode->NextChildRemoval;
  827. DeviceTreeNode->NextChildRemoval = RelationTreeNode;
  828. }
  829. //
  830. // And on to the next node.
  831. //
  832. DeviceTreeNode = DeviceTreeNode->NextChildRemoval;
  833. } while (DeviceTreeNode != DeviceTree->ChildRemovalList);
  834. }