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.

961 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation
  6. //
  7. // File: devicecol.cpp
  8. //
  9. // Description: This file handles device collections for the hotplug applet.
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "hotplug.h"
  13. BOOL
  14. DeviceCollectionPrepImageList(
  15. IN PDEVICE_COLLECTION DeviceCollection
  16. );
  17. VOID
  18. DeviceCollectionSwapFakeDockForRealDock(
  19. IN PDEVICE_COLLECTION DeviceCollection,
  20. IN PTSTR InstancePath,
  21. IN OUT DEVNODE *DeviceNode
  22. );
  23. BOOL
  24. DeviceCollectionBuildFromPipe(
  25. IN HANDLE ReadPipe,
  26. IN COLLECTION_TYPE CollectionType,
  27. OUT PDEVICE_COLLECTION DeviceCollection
  28. )
  29. {
  30. PTSTR deviceIds;
  31. PTSTR instancePath;
  32. BOOL bDockDeviceInList;
  33. PDEVICE_COLLECTION_ENTRY deviceEntry;
  34. DEVNODE deviceNode;
  35. DWORD capabilities, configFlags, cbSize;
  36. ULONG bytesReadFromPipe;
  37. ULONG numDevices, deviceIdsLength;
  38. BOOL success;
  39. CONFIGRET configRet;
  40. TCHAR classGuidString[MAX_GUID_STRING_LEN];
  41. GUID classGuid;
  42. //
  43. // Preinit.
  44. //
  45. success = FALSE;
  46. deviceIds = NULL;
  47. deviceIdsLength = 0;
  48. bDockDeviceInList = FALSE;
  49. numDevices = 0;
  50. DeviceCollection->NumDevices = 0;
  51. DeviceCollection->DockInList = FALSE;
  52. DeviceCollection->ClassImageList.cbSize = 0;
  53. InitializeListHead(&DeviceCollection->DeviceListHead);
  54. //
  55. // Our callers shouldn't have to handle an internal failure in any of this.
  56. //
  57. __try {
  58. //
  59. // Read the first ULONG from the pipe, this is the length of all the
  60. // Device Ids.
  61. //
  62. if (!ReadFile(ReadPipe,
  63. (LPVOID)&deviceIdsLength,
  64. sizeof(ULONG),
  65. &bytesReadFromPipe,
  66. NULL) ||
  67. (deviceIdsLength == 0)) {
  68. goto clean0;
  69. }
  70. //
  71. // Allocate space to hold the DeviceIds
  72. //
  73. deviceIds = (PTSTR)LocalAlloc(LPTR, deviceIdsLength);
  74. if (!deviceIds) {
  75. goto clean0;
  76. }
  77. //
  78. // Read all of the DeviceIds from the pipe at once
  79. //
  80. if (!ReadFile(ReadPipe,
  81. (LPVOID)deviceIds,
  82. deviceIdsLength,
  83. &bytesReadFromPipe,
  84. NULL)) {
  85. goto clean0;
  86. }
  87. //
  88. // Enumerate through the multi-sz list of Device Ids.
  89. //
  90. for (instancePath = deviceIds;
  91. *instancePath;
  92. instancePath += lstrlen(instancePath) + 1) {
  93. deviceEntry = (PDEVICE_COLLECTION_ENTRY)LocalAlloc(
  94. LPTR,
  95. sizeof(DEVICE_COLLECTION_ENTRY)
  96. );
  97. if (!deviceEntry) {
  98. goto clean0;
  99. }
  100. //
  101. // If we are building a blocked driver list, just put the driver
  102. // GUID in the DeviceInstanceId field and continue to the next.
  103. //
  104. if (CollectionType == CT_BLOCKED_DRIVER_NOTIFICATION) {
  105. numDevices++;
  106. if (SUCCEEDED(StringCchCopy(deviceEntry->DeviceInstanceId,
  107. SIZECHARS(deviceEntry->DeviceInstanceId),
  108. instancePath)) &&
  109. (pSetupGuidFromString(instancePath, &(deviceEntry->ClassGuid)) == ERROR_SUCCESS)) {
  110. InsertTailList(
  111. &DeviceCollection->DeviceListHead,
  112. &deviceEntry->Link
  113. );
  114. } else {
  115. //
  116. // Something went wrong, so free the DEVICE_COLLECTION_ENTRY
  117. // node.
  118. //
  119. LocalFree(deviceEntry);
  120. deviceEntry = NULL;
  121. }
  122. } else {
  123. capabilities = 0;
  124. classGuid = GUID_NULL;
  125. if (CM_Locate_DevNode(&deviceNode,
  126. instancePath,
  127. (CollectionType == CT_CHILD_WITH_INVALID_ID_NOTIFICATION)
  128. ? 0
  129. : CM_LOCATE_DEVNODE_PHANTOM) == CR_SUCCESS) {
  130. cbSize = sizeof(DWORD);
  131. configRet = CM_Get_DevNode_Registry_Property_Ex(
  132. deviceNode,
  133. CM_DRP_CAPABILITIES,
  134. NULL,
  135. (PVOID)&capabilities,
  136. &cbSize,
  137. 0,
  138. NULL
  139. );
  140. if ((configRet == CR_SUCCESS) &&
  141. (capabilities & CM_DEVCAP_DOCKDEVICE)) {
  142. DeviceCollectionSwapFakeDockForRealDock(
  143. DeviceCollection,
  144. instancePath,
  145. &deviceNode
  146. );
  147. bDockDeviceInList = TRUE;
  148. }
  149. if (CollectionType == CT_SURPRISE_REMOVAL_WARNING) {
  150. //
  151. // For surprise removal, we are careful to ignore any devices
  152. // with the Suppress-Surprise flag set.
  153. //
  154. cbSize = sizeof(DWORD);
  155. configRet = CM_Get_DevNode_Registry_Property_Ex(
  156. deviceNode,
  157. CM_DRP_CONFIGFLAGS,
  158. NULL,
  159. (PVOID)&configFlags,
  160. &cbSize,
  161. 0,
  162. NULL
  163. );
  164. if ((configRet == CR_SUCCESS) &&
  165. (configFlags & CONFIGFLAG_SUPPRESS_SURPRISE)) {
  166. continue;
  167. }
  168. }
  169. //
  170. // Get the class GUID string for the device
  171. //
  172. cbSize = sizeof(classGuidString);
  173. if ((CM_Get_DevNode_Registry_Property(deviceNode,
  174. CM_DRP_CLASSGUID,
  175. NULL,
  176. (PVOID)classGuidString,
  177. &cbSize,
  178. 0) != CR_SUCCESS) ||
  179. (pSetupGuidFromString(classGuidString, &classGuid) != ERROR_SUCCESS)) {
  180. classGuid = GUID_NULL;
  181. }
  182. }
  183. numDevices++;
  184. StringCchCopy(deviceEntry->DeviceInstanceId,
  185. SIZECHARS(deviceEntry->DeviceInstanceId),
  186. instancePath);
  187. deviceEntry->DeviceFriendlyName = BuildFriendlyName(deviceNode);
  188. deviceEntry->Capabilities = capabilities;
  189. deviceEntry->ClassGuid = classGuid;
  190. InsertTailList(
  191. &DeviceCollection->DeviceListHead,
  192. &deviceEntry->Link
  193. );
  194. }
  195. }
  196. DeviceCollection->NumDevices = numDevices;
  197. DeviceCollection->DockInList = bDockDeviceInList;
  198. DeviceCollectionPrepImageList(DeviceCollection);
  199. success = TRUE;
  200. clean0:
  201. ;
  202. } __except(EXCEPTION_EXECUTE_HANDLER) {
  203. ASSERT(success == FALSE);
  204. ASSERT(0);
  205. }
  206. if (deviceIds) {
  207. LocalFree(deviceIds);
  208. }
  209. if (!success) {
  210. DeviceCollectionDestroy(DeviceCollection);
  211. }
  212. return success;
  213. }
  214. VOID
  215. DeviceCollectionDestroy(
  216. IN PDEVICE_COLLECTION DeviceCollection
  217. )
  218. {
  219. PDEVICE_COLLECTION_ENTRY deviceEntry;
  220. PLIST_ENTRY listEntry;
  221. while(!IsListEmpty(&DeviceCollection->DeviceListHead)) {
  222. listEntry = RemoveHeadList(&DeviceCollection->DeviceListHead);
  223. deviceEntry = CONTAINING_RECORD(listEntry,
  224. DEVICE_COLLECTION_ENTRY,
  225. Link);
  226. if (deviceEntry->DeviceFriendlyName) {
  227. LocalFree(deviceEntry->DeviceFriendlyName);
  228. }
  229. LocalFree(deviceEntry);
  230. }
  231. if (DeviceCollection->ClassImageList.cbSize) {
  232. SetupDiDestroyClassImageList(&DeviceCollection->ClassImageList);
  233. DeviceCollection->ClassImageList.cbSize = 0;
  234. }
  235. DeviceCollection->NumDevices = 0;
  236. }
  237. BOOL
  238. DeviceCollectionPrepImageList(
  239. IN PDEVICE_COLLECTION DeviceCollection
  240. )
  241. {
  242. if (DeviceCollection->ClassImageList.cbSize != 0) {
  243. //
  244. // We already have an image list, no need to reacquire.
  245. //
  246. return TRUE;
  247. }
  248. DeviceCollection->ClassImageList.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
  249. if (SetupDiGetClassImageList(&DeviceCollection->ClassImageList)) {
  250. //
  251. // Got it.
  252. //
  253. return TRUE;
  254. }
  255. //
  256. // Error path, put size back so we don't accidentally free garbage.
  257. //
  258. DeviceCollection->ClassImageList.cbSize = 0;
  259. return FALSE;
  260. }
  261. VOID
  262. DeviceCollectionPopulateListView(
  263. IN PDEVICE_COLLECTION DeviceCollection,
  264. IN HWND ListHandle
  265. )
  266. {
  267. LV_ITEM lviItem;
  268. LV_COLUMN lvcCol;
  269. PDEVICE_COLLECTION_ENTRY deviceEntry;
  270. PLIST_ENTRY listEntry;
  271. ULONG lvIndex;
  272. BOOL haveImageList = FALSE;
  273. //
  274. // Select in the correct image list.
  275. //
  276. if (DeviceCollectionPrepImageList(DeviceCollection)) {
  277. ListView_SetImageList(
  278. ListHandle,
  279. DeviceCollection->ClassImageList.ImageList,
  280. LVSIL_SMALL
  281. );
  282. haveImageList = TRUE;
  283. }
  284. //
  285. // Insert a column for the class list
  286. //
  287. lvcCol.mask = LVCF_FMT | LVCF_WIDTH;
  288. lvcCol.fmt = LVCFMT_LEFT;
  289. lvcCol.iSubItem = 0;
  290. ListView_InsertColumn(ListHandle, 0, (LV_COLUMN FAR *)&lvcCol);
  291. //
  292. // Walk the devinst list and add each of them to the listbox.
  293. //
  294. lvIndex = 0;
  295. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  296. listEntry != &DeviceCollection->DeviceListHead;
  297. listEntry = listEntry->Flink) {
  298. deviceEntry = CONTAINING_RECORD(listEntry,
  299. DEVICE_COLLECTION_ENTRY,
  300. Link);
  301. lviItem.mask = LVIF_TEXT;
  302. lviItem.iItem = lvIndex;
  303. lviItem.iSubItem = 0;
  304. //
  305. // In the worst possible scenario, we will give the user the instance
  306. // path. This is by design because we put other things into the list
  307. // sometimes.
  308. //
  309. lviItem.pszText = deviceEntry->DeviceInstanceId;
  310. if (deviceEntry->DeviceFriendlyName) {
  311. lviItem.pszText = deviceEntry->DeviceFriendlyName;
  312. }
  313. if (haveImageList) {
  314. if (SetupDiGetClassImageIndex(
  315. &DeviceCollection->ClassImageList,
  316. &deviceEntry->ClassGuid,
  317. &lviItem.iImage)
  318. ) {
  319. lviItem.mask |= LVIF_IMAGE;
  320. }
  321. }
  322. lvIndex = ListView_InsertItem(ListHandle, &lviItem);
  323. lvIndex++;
  324. }
  325. }
  326. BOOL
  327. DeviceCollectionGetDockDeviceIndex(
  328. IN PDEVICE_COLLECTION DeviceCollection,
  329. OUT ULONG *DockDeviceIndex
  330. )
  331. {
  332. PDEVICE_COLLECTION_ENTRY deviceEntry;
  333. PLIST_ENTRY listEntry;
  334. ULONG index;
  335. index = 0;
  336. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  337. listEntry != &DeviceCollection->DeviceListHead;
  338. listEntry = listEntry->Flink) {
  339. deviceEntry = CONTAINING_RECORD(listEntry,
  340. DEVICE_COLLECTION_ENTRY,
  341. Link);
  342. if (!(deviceEntry->Capabilities & CM_DEVCAP_DOCKDEVICE)) {
  343. index++;
  344. continue;
  345. }
  346. *DockDeviceIndex = index;
  347. return TRUE;
  348. }
  349. *DockDeviceIndex = 0;
  350. return FALSE;
  351. }
  352. BOOL
  353. DeviceCollectionFormatDeviceText(
  354. IN PDEVICE_COLLECTION DeviceCollection,
  355. IN ULONG Index,
  356. IN PTSTR FormatString,
  357. IN ULONG BufferCharSize,
  358. OUT PTSTR BufferText
  359. )
  360. {
  361. PDEVICE_COLLECTION_ENTRY deviceEntry;
  362. PTCHAR friendlyName;
  363. ULONG curIndex;
  364. PLIST_ENTRY listEntry;
  365. curIndex = 0;
  366. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  367. listEntry != &DeviceCollection->DeviceListHead;
  368. listEntry = listEntry->Flink) {
  369. if (curIndex == Index) {
  370. break;
  371. }
  372. curIndex++;
  373. }
  374. if (listEntry == &DeviceCollection->DeviceListHead) {
  375. //
  376. // We walked the entire list and didn't locate our device. Fail now.
  377. //
  378. if (BufferCharSize) {
  379. *BufferText = TEXT('\0');
  380. }
  381. return FALSE;
  382. }
  383. deviceEntry = CONTAINING_RECORD(listEntry,
  384. DEVICE_COLLECTION_ENTRY,
  385. Link);
  386. //
  387. // In the worst possible scenario, we will give the user the instance
  388. // path. This is by design because we put other things into the list
  389. // sometimes.
  390. //
  391. friendlyName = deviceEntry->DeviceInstanceId;
  392. if (deviceEntry->DeviceFriendlyName) {
  393. friendlyName = deviceEntry->DeviceFriendlyName;
  394. }
  395. StringCchPrintf(BufferText, BufferCharSize, FormatString, friendlyName);
  396. return TRUE;
  397. }
  398. BOOL
  399. DeviceCollectionFormatServiceText(
  400. IN PDEVICE_COLLECTION DeviceCollection,
  401. IN ULONG Index,
  402. IN PTSTR FormatString,
  403. IN ULONG BufferCharSize,
  404. OUT PTSTR BufferText
  405. )
  406. {
  407. PDEVICE_COLLECTION_ENTRY deviceEntry;
  408. PTCHAR serviceName;
  409. TCHAR szFriendlyName[MAX_SERVICE_NAME_LEN];
  410. SC_HANDLE hSCManager;
  411. DWORD dwSize;
  412. ULONG curIndex;
  413. PLIST_ENTRY listEntry;
  414. //
  415. // Walk the list to the entry specified by the index.
  416. //
  417. curIndex = 0;
  418. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  419. listEntry != &DeviceCollection->DeviceListHead;
  420. listEntry = listEntry->Flink) {
  421. if (curIndex == Index) {
  422. break;
  423. }
  424. curIndex++;
  425. }
  426. if (listEntry == &DeviceCollection->DeviceListHead) {
  427. //
  428. // We walked the entire list and didn't locate our service. Fail now.
  429. //
  430. if (BufferCharSize) {
  431. *BufferText = TEXT('\0');
  432. }
  433. return FALSE;
  434. }
  435. deviceEntry = CONTAINING_RECORD(listEntry,
  436. DEVICE_COLLECTION_ENTRY,
  437. Link);
  438. //
  439. // Our caller knows this collection entry is really a service (either a
  440. // windows service, or a kernel driver), so the DeviceInstanceId is really
  441. // the Service name. Query the SCM for its friendlier DisplayName property.
  442. //
  443. serviceName = deviceEntry->DeviceInstanceId;
  444. *szFriendlyName = TEXT('\0');
  445. if (serviceName) {
  446. //
  447. // Open the Service Control Manager
  448. //
  449. hSCManager = OpenSCManager(
  450. NULL, // local machine
  451. SERVICES_ACTIVE_DATABASE, // SCM database name
  452. GENERIC_READ // access type
  453. );
  454. if (hSCManager) {
  455. //
  456. // Query the SCM for this service's DisplayName. Note we use a
  457. // constant buffer of MAX_SERVICE_NAME_LENGTH chars, which should
  458. // always be large enough because that's what the SCM limits
  459. // DisplayNames to. If GetServiceDisplayName fails, we will receive
  460. // an empty string, which we'll handle below.
  461. //
  462. dwSize = MAX_SERVICE_NAME_LEN;
  463. GetServiceDisplayName(
  464. hSCManager, // handle to SCM database
  465. serviceName, // service name
  466. szFriendlyName, // display name
  467. &dwSize // size of display name buffer (in chars)
  468. );
  469. CloseServiceHandle(hSCManager);
  470. }
  471. //
  472. // We couldn't retrieve a friendly name for the service, so just use the
  473. // name we were given.
  474. //
  475. if (!*szFriendlyName) {
  476. StringCchCopy(szFriendlyName,
  477. SIZECHARS(szFriendlyName),
  478. serviceName);
  479. }
  480. }
  481. StringCchPrintf(BufferText, BufferCharSize, FormatString, szFriendlyName);
  482. return TRUE;
  483. }
  484. PTSTR
  485. DeviceCollectionGetDeviceInstancePath(
  486. IN PDEVICE_COLLECTION DeviceCollection,
  487. IN ULONG Index
  488. )
  489. {
  490. PDEVICE_COLLECTION_ENTRY deviceEntry;
  491. ULONG curIndex;
  492. PLIST_ENTRY listEntry;
  493. curIndex = 0;
  494. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  495. listEntry != &DeviceCollection->DeviceListHead;
  496. listEntry = listEntry->Flink) {
  497. if (curIndex == Index) {
  498. break;
  499. }
  500. curIndex++;
  501. }
  502. if (listEntry == &DeviceCollection->DeviceListHead) {
  503. //
  504. // We walked the entire list and didn't locate our device. Fail now.
  505. //
  506. return NULL;
  507. }
  508. deviceEntry = CONTAINING_RECORD(listEntry,
  509. DEVICE_COLLECTION_ENTRY,
  510. Link);
  511. return deviceEntry->DeviceInstanceId;
  512. }
  513. PTSTR
  514. DeviceCollectionGetDeviceFriendlyName(
  515. IN PDEVICE_COLLECTION DeviceCollection,
  516. IN ULONG Index
  517. )
  518. {
  519. PDEVICE_COLLECTION_ENTRY deviceEntry;
  520. ULONG curIndex;
  521. PLIST_ENTRY listEntry;
  522. curIndex = 0;
  523. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  524. listEntry != &DeviceCollection->DeviceListHead;
  525. listEntry = listEntry->Flink) {
  526. if (curIndex == Index) {
  527. break;
  528. }
  529. curIndex++;
  530. }
  531. if (listEntry == &DeviceCollection->DeviceListHead) {
  532. //
  533. // We walked the entire list and didn't locate our device. Fail now.
  534. //
  535. return NULL;
  536. }
  537. deviceEntry = CONTAINING_RECORD(listEntry,
  538. DEVICE_COLLECTION_ENTRY,
  539. Link);
  540. return deviceEntry->DeviceFriendlyName;
  541. }
  542. BOOL
  543. DeviceCollectionGetGuid(
  544. IN PDEVICE_COLLECTION DeviceCollection,
  545. IN OUT LPGUID Guid,
  546. IN ULONG Index
  547. )
  548. {
  549. PDEVICE_COLLECTION_ENTRY deviceEntry;
  550. ULONG curIndex;
  551. PLIST_ENTRY listEntry;
  552. curIndex = 0;
  553. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  554. listEntry != &DeviceCollection->DeviceListHead;
  555. listEntry = listEntry->Flink) {
  556. if (curIndex == Index) {
  557. break;
  558. }
  559. curIndex++;
  560. }
  561. if (listEntry == &DeviceCollection->DeviceListHead) {
  562. //
  563. // We walked the entire list and didn't locate our device. Fail now.
  564. //
  565. return FALSE;
  566. }
  567. deviceEntry = CONTAINING_RECORD(listEntry,
  568. DEVICE_COLLECTION_ENTRY,
  569. Link);
  570. memcpy(Guid, &(deviceEntry->ClassGuid), sizeof(GUID));
  571. return TRUE;
  572. }
  573. VOID
  574. DeviceCollectionSwapFakeDockForRealDock(
  575. IN PDEVICE_COLLECTION DeviceCollection,
  576. IN PTSTR InstancePath,
  577. IN OUT DEVNODE *DeviceNode
  578. )
  579. {
  580. DEVNODE fakeDock, realDock;
  581. ULONG cchSize;
  582. CONFIGRET configRet;
  583. PTSTR deviceIdRelations, realDockId, nextEjectionId, hardwareIds, curEntry;
  584. //
  585. // Preinit
  586. //
  587. fakeDock = *DeviceNode;
  588. deviceIdRelations = NULL;
  589. hardwareIds = NULL;
  590. cchSize = 0;
  591. configRet = CM_Get_Device_ID_List_Size_Ex(
  592. &cchSize,
  593. InstancePath,
  594. CM_GETIDLIST_FILTER_EJECTRELATIONS,
  595. NULL
  596. );
  597. if ((configRet != CR_SUCCESS) || (!cchSize)) {
  598. goto Exit;
  599. }
  600. deviceIdRelations = (PTSTR)LocalAlloc(LPTR, cchSize*sizeof(TCHAR));
  601. if (!deviceIdRelations) {
  602. goto Exit;
  603. }
  604. *deviceIdRelations = TEXT('\0');
  605. configRet = CM_Get_Device_ID_List_Ex(
  606. InstancePath,
  607. deviceIdRelations,
  608. cchSize,
  609. CM_GETIDLIST_FILTER_EJECTRELATIONS,
  610. NULL
  611. );
  612. if (configRet != CR_SUCCESS) {
  613. goto Exit;
  614. }
  615. if (!(*deviceIdRelations)) {
  616. //
  617. // No ejection relations, bail.
  618. //
  619. goto Exit;
  620. }
  621. //
  622. // The last relation should be the real dock. Get it.
  623. //
  624. nextEjectionId = deviceIdRelations;
  625. do {
  626. realDockId = nextEjectionId;
  627. nextEjectionId += lstrlen(nextEjectionId)+1;
  628. } while ( *nextEjectionId );
  629. configRet = CM_Locate_DevNode(
  630. &realDock,
  631. realDockId,
  632. CM_LOCATE_DEVNODE_PHANTOM
  633. );
  634. if (configRet != CR_SUCCESS) {
  635. goto Exit;
  636. }
  637. LocalFree(deviceIdRelations);
  638. deviceIdRelations = NULL;
  639. //
  640. // One last check - we need to check the hardware ID's and compatible ID's.
  641. // We will only do this if we spot a *PNP0C15 amongst them.
  642. //
  643. cchSize = 0;
  644. configRet = CM_Get_DevNode_Registry_Property_Ex(
  645. realDock,
  646. CM_DRP_HARDWAREID,
  647. NULL,
  648. NULL,
  649. &cchSize,
  650. 0,
  651. NULL
  652. );
  653. if (configRet != CR_SUCCESS) {
  654. goto Exit;
  655. }
  656. hardwareIds = (PTSTR)LocalAlloc(LPTR, cchSize*sizeof(TCHAR));
  657. if (!hardwareIds) {
  658. goto Exit;
  659. }
  660. configRet = CM_Get_DevNode_Registry_Property_Ex(
  661. realDock,
  662. CM_DRP_HARDWAREID,
  663. NULL,
  664. hardwareIds,
  665. &cchSize,
  666. 0,
  667. NULL
  668. );
  669. if (configRet == CR_SUCCESS) {
  670. for(curEntry = hardwareIds;
  671. *curEntry;
  672. curEntry += lstrlen(curEntry)+1) {
  673. if (!_wcsicmp(curEntry, TEXT("*PNP0C15"))) {
  674. //
  675. // We found an entry - we can successful "rebrand" this dock
  676. // for the user.
  677. //
  678. *DeviceNode = realDock;
  679. LocalFree(hardwareIds);
  680. return;
  681. }
  682. }
  683. }
  684. LocalFree(hardwareIds);
  685. hardwareIds = NULL;
  686. //
  687. // Now try the compatible ID's. This is where we really expect to find the
  688. // real dock.
  689. //
  690. cchSize = 0;
  691. configRet = CM_Get_DevNode_Registry_Property_Ex(
  692. realDock,
  693. CM_DRP_COMPATIBLEIDS,
  694. NULL,
  695. NULL,
  696. &cchSize,
  697. 0,
  698. NULL
  699. );
  700. if (configRet != CR_SUCCESS) {
  701. goto Exit;
  702. }
  703. hardwareIds = (PTSTR)LocalAlloc(LPTR, cchSize*sizeof(TCHAR));
  704. if (!hardwareIds) {
  705. goto Exit;
  706. }
  707. configRet = CM_Get_DevNode_Registry_Property_Ex(
  708. realDock,
  709. CM_DRP_COMPATIBLEIDS,
  710. NULL,
  711. hardwareIds,
  712. &cchSize,
  713. 0,
  714. NULL
  715. );
  716. if (configRet == CR_SUCCESS) {
  717. for(curEntry = hardwareIds;
  718. *curEntry;
  719. curEntry += lstrlen(curEntry)+1) {
  720. if (!_wcsicmp(curEntry, TEXT("*PNP0C15"))) {
  721. //
  722. // We found an entry - we can successful "rebrand" this dock
  723. // for the user.
  724. //
  725. *DeviceNode = realDock;
  726. LocalFree(hardwareIds);
  727. return;
  728. }
  729. }
  730. }
  731. Exit:
  732. if (deviceIdRelations) {
  733. LocalFree(deviceIdRelations);
  734. }
  735. if (hardwareIds) {
  736. LocalFree(hardwareIds);
  737. }
  738. }
  739. BOOL
  740. DeviceCollectionCheckIfAllRemoved(
  741. IN PDEVICE_COLLECTION DeviceCollection
  742. )
  743. {
  744. PDEVICE_COLLECTION_ENTRY deviceEntry;
  745. PLIST_ENTRY listEntry;
  746. DEVNODE deviceNode;
  747. for(listEntry = DeviceCollection->DeviceListHead.Flink;
  748. listEntry != &DeviceCollection->DeviceListHead;
  749. listEntry = listEntry->Flink) {
  750. deviceEntry = CONTAINING_RECORD(listEntry,
  751. DEVICE_COLLECTION_ENTRY,
  752. Link);
  753. //
  754. // If we can locate this device normally then it is a 'live'
  755. // device, so return FALSE.
  756. //
  757. if (CM_Locate_DevNode(&deviceNode,
  758. deviceEntry->DeviceInstanceId,
  759. 0) == CR_SUCCESS) {
  760. return FALSE;
  761. }
  762. }
  763. //
  764. // We were able to locate all the devices in this device collection.
  765. //
  766. return TRUE;
  767. }