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.

1015 lines
29 KiB

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