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.

1003 lines
25 KiB

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