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.

2081 lines
54 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. rtravers.c
  5. Abstract:
  6. This module contains the server-side hardware tree traversal APIs.
  7. PNP_ValidateDeviceInstance
  8. PNP_GetRootDeviceInstance
  9. PNP_GetRelatedDeviceInstance
  10. PNP_EnumerateSubKeys
  11. PNP_GetDeviceList
  12. PNP_GetDeviceListSize
  13. Author:
  14. Paula Tomlinson (paulat) 6-19-1995
  15. Environment:
  16. User-mode only.
  17. Revision History:
  18. 19-June-1995 paulat
  19. Creation and initial implementation.
  20. --*/
  21. //
  22. // includes
  23. //
  24. #include "precomp.h"
  25. #include "umpnpi.h"
  26. #include "umpnpdat.h"
  27. //
  28. // private prototypes
  29. //
  30. CONFIGRET
  31. GetInstanceListSize(
  32. IN LPCWSTR pszDevice,
  33. OUT PULONG pulLength
  34. );
  35. CONFIGRET
  36. GetInstanceList(
  37. IN LPCWSTR pszDevice,
  38. IN OUT LPWSTR *pBuffer,
  39. IN OUT PULONG pulLength
  40. );
  41. CONFIGRET
  42. GetDeviceInstanceListSize(
  43. IN LPCWSTR pszEnumerator,
  44. OUT PULONG pulLength
  45. );
  46. CONFIGRET
  47. GetDeviceInstanceList(
  48. IN LPCWSTR pszEnumerator,
  49. IN OUT LPWSTR *pBuffer,
  50. IN OUT PULONG pulLength
  51. );
  52. PNP_QUERY_RELATION
  53. QueryOperationCode(
  54. ULONG ulFlags
  55. );
  56. //
  57. // global data
  58. //
  59. extern HKEY ghEnumKey; // Key to HKLM\CCC\System\Enum - DO NOT MODIFY
  60. extern HKEY ghServicesKey; // Key to HKLM\CCC\System\Services - DO NOT MODIFY
  61. extern HKEY ghClassKey; // Key to HKLM\CCC\System\Class - NO NOT MODIFY
  62. CONFIGRET
  63. PNP_ValidateDeviceInstance(
  64. IN handle_t hBinding,
  65. IN LPWSTR pDeviceID,
  66. IN ULONG ulFlags
  67. )
  68. /*++
  69. Routine Description:
  70. This the server-side of an RPC remote call. This routine verifies whether
  71. the specificed device instance is a valid device instance.
  72. Arguments:
  73. hBinding Not used.
  74. DeviceInstance Null-terminated string that contains a device instance
  75. to be validated.
  76. ulFlags One of the CM_LOCATE_DEVNODE_* flags.
  77. Return Value:
  78. If the specified device instance is valid, it returns CR_SUCCESS,
  79. otherwise it returns CR_ error code.
  80. --*/
  81. {
  82. CONFIGRET Status = CR_SUCCESS;
  83. LONG RegStatus = ERROR_SUCCESS;
  84. HKEY hKey = NULL;
  85. ULONG ulSize, ulValue, ulStatus = 0, ulProblem = 0;
  86. UNREFERENCED_PARAMETER(hBinding);
  87. //
  88. // assume that the device instance string was checked for proper form
  89. // before being added to the registry Enum tree
  90. //
  91. try {
  92. //
  93. // validate parameters
  94. //
  95. if (INVALID_FLAGS(ulFlags, CM_LOCATE_DEVNODE_BITS)) {
  96. Status = CR_INVALID_FLAG;
  97. goto Clean0;
  98. }
  99. if (!IsLegalDeviceId(pDeviceID)) {
  100. Status = CR_INVALID_DEVNODE;
  101. goto Clean0;
  102. }
  103. //
  104. // open a key to the specified device id
  105. //
  106. if (RegOpenKeyEx(ghEnumKey, pDeviceID, 0, KEY_READ,
  107. &hKey) != ERROR_SUCCESS) {
  108. Status = CR_NO_SUCH_DEVINST;
  109. goto Clean0;
  110. }
  111. //
  112. // Will specify for now that a moved devinst cannot be located (we
  113. // could allow this if we wanted to).
  114. //
  115. if (IsDeviceMoved(pDeviceID, hKey)) {
  116. Status = CR_NO_SUCH_DEVINST;
  117. goto Clean0;
  118. }
  119. //
  120. // if we're locating a phantom devnode, it just has to exist
  121. // in the registry (the above check) and not already be a
  122. // phantom (private) devnode
  123. //
  124. if (ulFlags & CM_LOCATE_DEVNODE_PHANTOM) {
  125. //
  126. // verify that it's not a private phantom
  127. //
  128. ulSize = sizeof(ULONG);
  129. RegStatus = RegQueryValueEx(hKey, pszRegValuePhantom, NULL, NULL,
  130. (LPBYTE)&ulValue, &ulSize);
  131. if ((RegStatus == ERROR_SUCCESS) && ulValue) {
  132. Status = CR_NO_SUCH_DEVINST;
  133. goto Clean0;
  134. }
  135. } else if (ulFlags & CM_LOCATE_DEVNODE_CANCELREMOVE) {
  136. //
  137. // In the CANCEL-REMOVE case, if the devnode has been removed,
  138. // (made volatile) then convert it back to nonvoatile so it
  139. // can be installed again without disappearing on the next
  140. // boot. If it's not removed, then just verify that it is
  141. // present.
  142. //
  143. //
  144. // verify that the device id is actually present
  145. //
  146. if (!IsDeviceIdPresent(pDeviceID)) {
  147. Status = CR_NO_SUCH_DEVINST;
  148. goto Clean0;
  149. }
  150. //
  151. // Is this a device that is being removed on the next reboot?
  152. //
  153. if (GetDeviceStatus(pDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) {
  154. if (ulStatus & DN_WILL_BE_REMOVED) {
  155. ULONG ulProfile = 0, ulCount = 0;
  156. WCHAR RegStr[MAX_CM_PATH];
  157. //
  158. // This device will be removed on the next reboot,
  159. // convert to nonvolatile.
  160. //
  161. KdPrintEx((DPFLTR_PNPMGR_ID,
  162. DBGF_REGISTRY,
  163. "UMPNPMGR: PNP_ValidateDeviceInstance make key %ws non-volatile\n",
  164. pDeviceID));
  165. Status = MakeKeyNonVolatile(pszRegPathEnum, pDeviceID);
  166. if (Status != CR_SUCCESS) {
  167. goto Clean0;
  168. }
  169. //
  170. // Now make any keys that were "supposed" to be volatile
  171. // back to volatile again!
  172. //
  173. wsprintf(RegStr, TEXT("%s\\%s"),
  174. pszRegPathEnum,
  175. pDeviceID);
  176. KdPrintEx((DPFLTR_PNPMGR_ID,
  177. DBGF_REGISTRY,
  178. "UMPNPMGR: PNP_ValidateDeviceInstance make key %ws\\%ws volatile\n",
  179. RegStr,
  180. pszRegKeyDeviceControl));
  181. MakeKeyVolatile(RegStr, pszRegKeyDeviceControl);
  182. //
  183. // Also, convert any profile specific keys to nonvolatile
  184. //
  185. Status = GetProfileCount(&ulCount);
  186. if (Status != CR_SUCCESS) {
  187. goto Clean0;
  188. }
  189. for (ulProfile = 1; ulProfile <= ulCount; ulProfile++) {
  190. wsprintf(RegStr, TEXT("%s\\%04u\\%s"),
  191. pszRegPathHwProfiles,
  192. ulProfile,
  193. pszRegPathEnum);
  194. //
  195. // Ignore the status for profile-specific keys since they may
  196. // not exist.
  197. //
  198. KdPrintEx((DPFLTR_PNPMGR_ID,
  199. DBGF_REGISTRY,
  200. "UMPNPMGR: PNP_ValidateDeviceInstance make key %ws non-volatile\n",
  201. pDeviceID));
  202. MakeKeyNonVolatile(RegStr, pDeviceID);
  203. }
  204. //
  205. // clear the DN_WILL_BE_REMOVED flag
  206. //
  207. ClearDeviceStatus(pDeviceID, DN_WILL_BE_REMOVED, 0);
  208. }
  209. }
  210. }
  211. //
  212. // in the normal (non-phantom case), verify that the device id is
  213. // actually present
  214. //
  215. else {
  216. //
  217. // verify that the device id is actually present
  218. //
  219. if (!IsDeviceIdPresent(pDeviceID)) {
  220. Status = CR_NO_SUCH_DEVINST;
  221. goto Clean0;
  222. }
  223. }
  224. Clean0:
  225. NOTHING;
  226. } except(EXCEPTION_EXECUTE_HANDLER) {
  227. Status = CR_FAILURE;
  228. }
  229. if (hKey != NULL) {
  230. RegCloseKey(hKey);
  231. }
  232. return Status;
  233. } // PNP_ValidateDeviceInstance
  234. CONFIGRET
  235. PNP_GetRootDeviceInstance(
  236. IN handle_t hBinding,
  237. OUT LPWSTR pDeviceID,
  238. IN ULONG ulLength
  239. )
  240. /*++
  241. Routine Description:
  242. This the server-side of an RPC remote call. This routine returns the
  243. root device instance for the hardware tree.
  244. Arguments:
  245. hBinding Not used.
  246. pDeviceID Pointer to a buffer that will hold the root device
  247. instance ID string.
  248. ulLength Size of pDeviceID buffer in characters.
  249. Return Value:
  250. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  251. a CR_* error code.
  252. --*/
  253. {
  254. CONFIGRET Status = CR_SUCCESS;
  255. HKEY hKey = NULL;
  256. UNREFERENCED_PARAMETER(hBinding);
  257. try {
  258. //
  259. // first validate that the root device instance exists
  260. //
  261. if (RegOpenKeyEx(ghEnumKey, pszRegRootEnumerator, 0, KEY_QUERY_VALUE,
  262. &hKey) != ERROR_SUCCESS) {
  263. //
  264. // root doesn't exist, create root devinst
  265. //
  266. if (!CreateDeviceIDRegKey(ghEnumKey, pszRegRootEnumerator)) {
  267. Status = CR_REGISTRY_ERROR;
  268. goto Clean0;
  269. }
  270. }
  271. //
  272. // return the root device instance id
  273. //
  274. if (ulLength < (ULONG)lstrlen(pszRegRootEnumerator)+1) {
  275. Status = CR_BUFFER_SMALL;
  276. goto Clean0;
  277. }
  278. lstrcpy(pDeviceID, pszRegRootEnumerator);
  279. Clean0:
  280. NOTHING;
  281. } except(EXCEPTION_EXECUTE_HANDLER) {
  282. Status = CR_FAILURE;
  283. }
  284. if (hKey != NULL) {
  285. RegCloseKey(hKey);
  286. }
  287. return Status;
  288. } // PNP_GetRootDeviceInstance
  289. CONFIGRET
  290. PNP_GetRelatedDeviceInstance(
  291. IN handle_t hBinding,
  292. IN ULONG ulRelationship,
  293. IN LPWSTR pDeviceID,
  294. OUT LPWSTR pRelatedDeviceID,
  295. IN OUT PULONG pulLength,
  296. IN ULONG ulFlags
  297. )
  298. /*++
  299. Routine Description:
  300. This the server-side of an RPC remote call. This routine returns a
  301. device instance that is related to the specified device instance.
  302. Arguments:
  303. hBinding Not used.
  304. ulRelationship Specifies the relationship of the device instance to
  305. be retrieved (can be PNP_GET_PARENT_DEVICE_INSTANCE,
  306. PNP_GET_CHILD_DEVICE_INSTANCE, or
  307. PNP_GET_SIBLING_DEVICE_INSTANCE).
  308. pDeviceID Pointer to a buffer that contains the base device
  309. instance string.
  310. pRelatedDeviceID Pointer to a buffer that will receive the related
  311. device instance string.
  312. pulLength Length (in characters) of the RelatedDeviceInstance
  313. buffer.
  314. ulFlags Not used, must be zero.
  315. Return Value:
  316. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  317. a CR_* error code.
  318. --*/
  319. {
  320. PLUGPLAY_CONTROL_RELATED_DEVICE_DATA ControlData;
  321. CONFIGRET Status = CR_SUCCESS;
  322. NTSTATUS ntStatus;
  323. UNREFERENCED_PARAMETER(hBinding);
  324. try {
  325. //
  326. // validate patameters
  327. //
  328. if (INVALID_FLAGS(ulFlags, 0)) {
  329. Status = CR_INVALID_FLAG;
  330. goto Clean0;
  331. }
  332. if ((!ARGUMENT_PRESENT(pulLength)) ||
  333. (!ARGUMENT_PRESENT(pRelatedDeviceID) && (*pulLength != 0))) {
  334. Status = CR_INVALID_POINTER;
  335. goto Clean0;
  336. }
  337. if (*pulLength > 0) {
  338. *pRelatedDeviceID = L'\0';
  339. }
  340. if (!IsLegalDeviceId(pDeviceID)) {
  341. Status = CR_INVALID_DEVNODE;
  342. if (*pulLength > 0) {
  343. *pulLength = 1;
  344. }
  345. goto Clean0;
  346. }
  347. //
  348. // initialize control data block
  349. //
  350. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
  351. //
  352. // special case behavior for certain devices and relationships
  353. //
  354. switch (ulRelationship) {
  355. case PNP_GET_PARENT_DEVICE_INSTANCE:
  356. if (IsRootDeviceID(pDeviceID)) {
  357. //
  358. // This is the root (which has no parent by definition)
  359. //
  360. Status = CR_NO_SUCH_DEVINST;
  361. } else if (IsDevicePhantom(pDeviceID)) {
  362. //
  363. // Check if this is a phantom. Phantom devices don't have
  364. // a kernel-mode device node allocated yet, but during manual
  365. // install, the process calls for retrieving the parent. So we
  366. // just fake it out by returning the root in this case. For all
  367. // other cases, we only return the parent that the kernel-mode
  368. // device node indicates.
  369. //
  370. if ((ULONG)(lstrlen(pszRegRootEnumerator) + 1) > *pulLength) {
  371. lstrcpyn(pRelatedDeviceID, pszRegRootEnumerator,*pulLength);
  372. Status = CR_BUFFER_SMALL;
  373. } else {
  374. lstrcpy(pRelatedDeviceID, pszRegRootEnumerator);
  375. }
  376. *pulLength = lstrlen(pszRegRootEnumerator) + 1;
  377. goto Clean0;
  378. }
  379. ControlData.Relation = PNP_RELATION_PARENT;
  380. break;
  381. case PNP_GET_CHILD_DEVICE_INSTANCE:
  382. ControlData.Relation = PNP_RELATION_CHILD;
  383. break;
  384. case PNP_GET_SIBLING_DEVICE_INSTANCE:
  385. //
  386. // first verify it isn't the root (which has no siblings by definition)
  387. //
  388. if (IsRootDeviceID(pDeviceID)) {
  389. Status = CR_NO_SUCH_DEVINST;
  390. }
  391. ControlData.Relation = PNP_RELATION_SIBLING;
  392. break;
  393. default:
  394. Status = CR_FAILURE;
  395. }
  396. if (Status == CR_SUCCESS) {
  397. //
  398. // Try to locate the relation from the kernel-mode in-memory
  399. // devnode tree.
  400. //
  401. RtlInitUnicodeString(&ControlData.TargetDeviceInstance, pDeviceID);
  402. ControlData.RelatedDeviceInstance = pRelatedDeviceID;
  403. ControlData.RelatedDeviceInstanceLength = *pulLength;
  404. ntStatus = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
  405. &ControlData,
  406. sizeof(ControlData));
  407. if (NT_SUCCESS(ntStatus)) {
  408. *pulLength = ControlData.RelatedDeviceInstanceLength + 1;
  409. } else {
  410. Status = MapNtStatusToCmError(ntStatus);
  411. }
  412. } else if (*pulLength > 0) {
  413. *pulLength = 1;
  414. }
  415. Clean0:
  416. NOTHING;
  417. } except(EXCEPTION_EXECUTE_HANDLER) {
  418. Status = CR_FAILURE;
  419. }
  420. return Status;
  421. } // PNP_GetRelatedDeviceInstance
  422. CONFIGRET
  423. PNP_EnumerateSubKeys(
  424. IN handle_t hBinding,
  425. IN ULONG ulBranch,
  426. IN ULONG ulIndex,
  427. OUT PWSTR Buffer,
  428. IN ULONG ulLength,
  429. OUT PULONG pulRequiredLen,
  430. IN ULONG ulFlags
  431. )
  432. /*++
  433. Routine Description:
  434. This is the RPC server entry point for the CM_Enumerate_Enumerators and
  435. CM_Enumerate_Classes. It provides generic subkey enumeration based on
  436. the specified registry branch.
  437. Arguments:
  438. hBinding Not used.
  439. ulBranch Specifies which keys to enumerate.
  440. ulIndex Index of the subkey key to retrieve.
  441. Buffer Supplies the address of the buffer that receives the
  442. subkey name.
  443. ulLength Specifies the max size of the Buffer in characters.
  444. pulRequired On output it contains the number of characters actually
  445. copied to Buffer if it was successful, or the number of
  446. characters required if the buffer was too small.
  447. ulFlags Not used, must be zero.
  448. Return Value:
  449. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  450. a CR_* error code.
  451. --*/
  452. {
  453. CONFIGRET Status = CR_SUCCESS;
  454. LONG RegStatus = ERROR_SUCCESS;
  455. HKEY hKey = NULL;
  456. UNREFERENCED_PARAMETER(hBinding);
  457. try {
  458. //
  459. // validate parameters
  460. //
  461. if (INVALID_FLAGS(ulFlags, 0)) {
  462. Status = CR_INVALID_FLAG;
  463. goto Clean0;
  464. }
  465. if ((!ARGUMENT_PRESENT(pulRequiredLen)) ||
  466. (!ARGUMENT_PRESENT(Buffer) && (ulLength != 0))) {
  467. Status = CR_INVALID_POINTER;
  468. goto Clean0;
  469. }
  470. if (ulLength > 0) {
  471. *Buffer = L'\0';
  472. }
  473. if (ulBranch == PNP_CLASS_SUBKEYS) {
  474. //
  475. // Use the global base CLASS registry key
  476. //
  477. hKey = ghClassKey;
  478. }
  479. else if (ulBranch == PNP_ENUMERATOR_SUBKEYS) {
  480. //
  481. // Use the global base ENUM registry key
  482. //
  483. hKey = ghEnumKey;
  484. }
  485. else {
  486. Status = CR_FAILURE;
  487. goto Clean0;
  488. }
  489. //
  490. // enumerate a subkey based on the passed in index value
  491. //
  492. *pulRequiredLen = ulLength;
  493. RegStatus = RegEnumKeyEx(hKey, ulIndex, Buffer, pulRequiredLen,
  494. NULL, NULL, NULL, NULL);
  495. *pulRequiredLen += 1; // returned count doesn't include null terminator
  496. if (RegStatus == ERROR_MORE_DATA) {
  497. //
  498. // This is a special case, the RegEnumKeyEx routine doesn't return
  499. // the number of characters required to hold this string (just how
  500. // many characters were copied to the buffer (how many fit). I have
  501. // to use a different means to return that info back to the caller.
  502. //
  503. ULONG ulMaxLen = 0;
  504. PWSTR p = NULL;
  505. if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, &ulMaxLen,
  506. NULL, NULL, NULL, NULL, NULL,
  507. NULL) == ERROR_SUCCESS) {
  508. ulMaxLen += 1; // returned count doesn't include null terminator
  509. p = HeapAlloc(ghPnPHeap, 0, ulMaxLen * sizeof(WCHAR));
  510. if (p == NULL) {
  511. Status = CR_OUT_OF_MEMORY;
  512. goto Clean0;
  513. }
  514. if (RegEnumKeyEx(hKey, ulIndex, p, &ulMaxLen, NULL, NULL, NULL,
  515. NULL) == ERROR_SUCCESS) {
  516. *pulRequiredLen = ulMaxLen + 1;
  517. }
  518. HeapFree(ghPnPHeap, 0, p);
  519. }
  520. Status = CR_BUFFER_SMALL;
  521. goto Clean0;
  522. }
  523. else if (RegStatus == ERROR_NO_MORE_ITEMS) {
  524. *pulRequiredLen = 0;
  525. Status = CR_NO_SUCH_VALUE;
  526. goto Clean0;
  527. }
  528. else if (RegStatus != ERROR_SUCCESS) {
  529. *pulRequiredLen = 0;
  530. Status = CR_REGISTRY_ERROR;
  531. goto Clean0;
  532. }
  533. Clean0:
  534. NOTHING;
  535. } except(EXCEPTION_EXECUTE_HANDLER) {
  536. Status = CR_FAILURE;
  537. }
  538. return Status;
  539. } // PNP_EnumerateSubKeys
  540. CONFIGRET
  541. PNP_GetDeviceList(
  542. IN handle_t hBinding,
  543. IN LPCWSTR pszFilter,
  544. OUT LPWSTR Buffer,
  545. IN OUT PULONG pulLength,
  546. IN ULONG ulFlags
  547. )
  548. /*++
  549. Routine Description:
  550. This the server-side of an RPC remote call. This routine returns a
  551. list of device instances.
  552. Arguments:
  553. hBinding Not used.
  554. pszFilter Optional parameter, controls which device ids are
  555. returned.
  556. Buffer Pointer to a buffer that will contain the multi_sz list
  557. of device instance strings.
  558. pulLength Size in characters of Buffer on input, size (in chars)
  559. transferred on output
  560. ulFlags Flag specifying which devices ids to return.
  561. Return Value:
  562. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  563. a CR_* error code.
  564. --*/
  565. {
  566. CONFIGRET Status = CR_SUCCESS;
  567. LONG RegStatus = ERROR_SUCCESS;
  568. ULONG ulBufferLen=0, ulSize=0, ulIndex=0, ulLen=0;
  569. WCHAR RegStr[MAX_CM_PATH];
  570. WCHAR szEnumerator[MAX_DEVICE_ID_LEN],
  571. szDevice[MAX_DEVICE_ID_LEN],
  572. szInstance[MAX_DEVICE_ID_LEN];
  573. LPWSTR ptr = NULL;
  574. NTSTATUS ntStatus = STATUS_SUCCESS;
  575. PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA ControlData;
  576. UNREFERENCED_PARAMETER(hBinding);
  577. try {
  578. //
  579. // validate parameters
  580. //
  581. if (INVALID_FLAGS(ulFlags, CM_GETIDLIST_FILTER_BITS)) {
  582. Status = CR_INVALID_FLAG;
  583. goto Clean0;
  584. }
  585. if ((!ARGUMENT_PRESENT(pulLength)) ||
  586. (!ARGUMENT_PRESENT(Buffer) && (*pulLength != 0))) {
  587. Status = CR_INVALID_POINTER;
  588. goto Clean0;
  589. }
  590. if (*pulLength > 0) {
  591. *Buffer = L'\0';
  592. }
  593. //-----------------------------------------------------------
  594. // Query Device Relations filter - go through kernel-mode
  595. //-----------------------------------------------------------
  596. if ((ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS) ||
  597. (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS) ||
  598. (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS) ||
  599. (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)) {
  600. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
  601. RtlInitUnicodeString(&ControlData.DeviceInstance, pszFilter);
  602. ControlData.Operation = QueryOperationCode(ulFlags);
  603. ControlData.BufferLength = *pulLength;
  604. ControlData.Buffer = Buffer;
  605. ntStatus = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
  606. &ControlData,
  607. sizeof(ControlData));
  608. if (NT_SUCCESS(ntStatus)) {
  609. *pulLength = ControlData.BufferLength;
  610. } else if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  611. *pulLength = 0;
  612. Status = MapNtStatusToCmError(ntStatus);
  613. }
  614. goto Clean0;
  615. }
  616. //---------------------------------------------------
  617. // Service filter
  618. //---------------------------------------------------
  619. else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE) {
  620. if (!ARGUMENT_PRESENT(pszFilter)) {
  621. //
  622. // the filter string is required for this flag
  623. //
  624. Status = CR_INVALID_POINTER;
  625. goto Clean0;
  626. }
  627. Status = GetServiceDeviceList(pszFilter, Buffer, pulLength, ulFlags);
  628. goto Clean0;
  629. }
  630. //---------------------------------------------------
  631. // Enumerator filter
  632. //---------------------------------------------------
  633. else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR) {
  634. if (!ARGUMENT_PRESENT(pszFilter)) {
  635. //
  636. // the filter string is required for this flag
  637. //
  638. Status = CR_INVALID_POINTER;
  639. goto Clean0;
  640. }
  641. SplitDeviceInstanceString(
  642. pszFilter, szEnumerator, szDevice, szInstance);
  643. //
  644. // if both the enumerator and device were specified, retrieve
  645. // the device instances for this device
  646. //
  647. if (*szEnumerator != L'\0' && *szDevice != L'\0') {
  648. ptr = Buffer;
  649. Status = GetInstanceList(pszFilter, &ptr, pulLength);
  650. }
  651. //
  652. // if just the enumerator was specified, retrieve all the device
  653. // instances under this enumerator
  654. //
  655. else {
  656. ptr = Buffer;
  657. Status = GetDeviceInstanceList(pszFilter, &ptr, pulLength);
  658. }
  659. }
  660. //------------------------------------------------
  661. // No filtering
  662. //-----------------------------------------------
  663. else {
  664. //
  665. // return device instances for all enumerators (by enumerating
  666. // the enumerators)
  667. //
  668. // Open a key to the Enum branch
  669. //
  670. ulSize = ulBufferLen = *pulLength; // total Buffer size
  671. *pulLength = 0; // nothing copied yet
  672. ptr = Buffer; // tail of the buffer
  673. ulIndex = 0;
  674. //
  675. // Enumerate all the enumerators
  676. //
  677. while (RegStatus == ERROR_SUCCESS) {
  678. ulLen = MAX_DEVICE_ID_LEN; // size in chars
  679. RegStatus = RegEnumKeyEx(ghEnumKey, ulIndex, RegStr, &ulLen,
  680. NULL, NULL, NULL, NULL);
  681. ulIndex++;
  682. if (RegStatus == ERROR_SUCCESS) {
  683. Status = GetDeviceInstanceList(RegStr, &ptr, &ulSize);
  684. if (Status != CR_SUCCESS) {
  685. *pulLength = 0;
  686. goto Clean0;
  687. }
  688. *pulLength += ulSize - 1; // length copied so far
  689. ulSize = ulBufferLen - *pulLength; // buffer length left
  690. }
  691. }
  692. *pulLength += 1; // now count the double-null
  693. }
  694. Clean0:
  695. NOTHING;
  696. } except(EXCEPTION_EXECUTE_HANDLER) {
  697. Status = CR_SUCCESS;
  698. }
  699. return Status;
  700. } // PNP_GetDeviceList
  701. CONFIGRET
  702. PNP_GetDeviceListSize(
  703. IN handle_t hBinding,
  704. IN LPCWSTR pszFilter,
  705. OUT PULONG pulLen,
  706. IN ULONG ulFlags
  707. )
  708. /*++
  709. Routine Description:
  710. This the server-side of an RPC remote call. This routine returns the
  711. size of a list of device instances.
  712. Arguments:
  713. hBinding Not used.
  714. pszEnumerator Optional parameter, if specified the size will only
  715. include device instances of this enumerator.
  716. pulLen Returns the worst case estimate of the size of a
  717. device instance list.
  718. ulFlags Flag specifying which devices ids to return.
  719. Return Value:
  720. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  721. a CR_* error code.
  722. --*/
  723. {
  724. CONFIGRET Status = CR_SUCCESS;
  725. ULONG ulSize = 0, ulIndex = 0;
  726. WCHAR RegStr[MAX_CM_PATH];
  727. ULONG RegStatus = ERROR_SUCCESS;
  728. WCHAR szEnumerator[MAX_DEVICE_ID_LEN],
  729. szDevice[MAX_DEVICE_ID_LEN],
  730. szInstance[MAX_DEVICE_ID_LEN];
  731. NTSTATUS ntStatus = STATUS_SUCCESS;
  732. PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA ControlData;
  733. UNREFERENCED_PARAMETER(hBinding);
  734. try {
  735. //
  736. // validate parameters
  737. //
  738. if (INVALID_FLAGS(ulFlags, CM_GETIDLIST_FILTER_BITS)) {
  739. Status = CR_INVALID_FLAG;
  740. goto Clean0;
  741. }
  742. if (!ARGUMENT_PRESENT(pulLen)) {
  743. Status = CR_INVALID_POINTER;
  744. goto Clean0;
  745. }
  746. //
  747. // initialize output length param
  748. //
  749. *pulLen = 0;
  750. //-----------------------------------------------------------
  751. // Query Device Relations filter - go through kernel-mode
  752. //-----------------------------------------------------------
  753. if ((ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS) ||
  754. (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS) ||
  755. (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS) ||
  756. (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)) {
  757. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
  758. RtlInitUnicodeString(&ControlData.DeviceInstance, pszFilter);
  759. ControlData.Operation = QueryOperationCode(ulFlags);
  760. ControlData.BufferLength = 0;
  761. ControlData.Buffer = NULL;
  762. ntStatus = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
  763. &ControlData,
  764. sizeof(ControlData));
  765. if (NT_SUCCESS(ntStatus)) {
  766. //
  767. // Note - we get here because kernel mode special cases
  768. // Buffer==NULL and is careful not to return
  769. // STATUS_BUFFER_TOO_SMALL.
  770. //
  771. *pulLen = ControlData.BufferLength;
  772. } else {
  773. //
  774. // ADRIAO ISSUE 02/06/2001 - We aren't returning the proper code
  775. // here. We should fix this in XP+1,
  776. // once we have time to verify no one
  777. // will get an app compat break.
  778. //
  779. //Status = MapNtStatusToCmError(ntStatus);
  780. Status = CR_SUCCESS;
  781. }
  782. goto Clean0;
  783. }
  784. //---------------------------------------------------
  785. // Service filter
  786. //---------------------------------------------------
  787. else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE) {
  788. if (!ARGUMENT_PRESENT(pszFilter)) {
  789. //
  790. // the filter string is required for this flag
  791. //
  792. Status = CR_INVALID_POINTER;
  793. goto Clean0;
  794. }
  795. Status = GetServiceDeviceListSize(pszFilter, pulLen);
  796. goto Clean0;
  797. }
  798. //---------------------------------------------------
  799. // Enumerator filter
  800. //---------------------------------------------------
  801. else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR) {
  802. if (!ARGUMENT_PRESENT(pszFilter)) {
  803. //
  804. // the filter string is required for this flag
  805. //
  806. Status = CR_INVALID_POINTER;
  807. goto Clean0;
  808. }
  809. SplitDeviceInstanceString(
  810. pszFilter, szEnumerator, szDevice, szInstance);
  811. //
  812. // if both the enumerator and device were specified, retrieve
  813. // the device instance list size for this device only
  814. //
  815. if (*szEnumerator != L'\0' && *szDevice != L'\0') {
  816. Status = GetInstanceListSize(pszFilter, pulLen);
  817. }
  818. //
  819. // if just the enumerator was specified, retrieve the size of
  820. // all the device instances under this enumerator
  821. //
  822. else {
  823. Status = GetDeviceInstanceListSize(pszFilter, pulLen);
  824. }
  825. }
  826. //---------------------------------------------------
  827. // No filtering
  828. //---------------------------------------------------
  829. else {
  830. //
  831. // no enumerator was specified, return device instance size
  832. // for all enumerators (by enumerating the enumerators)
  833. //
  834. ulIndex = 0;
  835. while (RegStatus == ERROR_SUCCESS) {
  836. ulSize = MAX_DEVICE_ID_LEN; // size in chars
  837. RegStatus = RegEnumKeyEx(ghEnumKey, ulIndex, RegStr, &ulSize,
  838. NULL, NULL, NULL, NULL);
  839. ulIndex++;
  840. if (RegStatus == ERROR_SUCCESS) {
  841. Status = GetDeviceInstanceListSize(RegStr, &ulSize);
  842. if (Status != CR_SUCCESS) {
  843. goto Clean0;
  844. }
  845. *pulLen += ulSize;
  846. }
  847. }
  848. }
  849. *pulLen += 1; // add extra char for double null term
  850. Clean0:
  851. NOTHING;
  852. } except(EXCEPTION_EXECUTE_HANDLER) {
  853. Status = CR_FAILURE;
  854. }
  855. return Status;
  856. } // PNP_GetDeviceListSize
  857. CONFIGRET
  858. PNP_GetDepth(
  859. IN handle_t hBinding,
  860. IN LPCWSTR pszDeviceID,
  861. OUT PULONG pulDepth,
  862. IN ULONG ulFlags
  863. )
  864. /*++
  865. Routine Description:
  866. This the server-side of an RPC remote call. This routine returns the
  867. depth of a device instance.
  868. Arguments:
  869. hBinding Not used.
  870. pszDeviceID Device instance to find the depth of.
  871. pulDepth Returns the depth of pszDeviceID.
  872. ulFlags Not used, must be zero.
  873. Return Value:
  874. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  875. a CR_* error code.
  876. --*/
  877. {
  878. CONFIGRET Status = CR_SUCCESS;
  879. NTSTATUS ntStatus = STATUS_SUCCESS;
  880. PLUGPLAY_CONTROL_DEPTH_DATA ControlData;
  881. UNREFERENCED_PARAMETER(hBinding);
  882. try {
  883. //
  884. // validate parameters
  885. //
  886. if (INVALID_FLAGS(ulFlags, 0)) {
  887. Status = CR_INVALID_FLAG;
  888. goto Clean0;
  889. }
  890. if (!ARGUMENT_PRESENT(pulDepth)) {
  891. Status = CR_INVALID_POINTER;
  892. goto Clean0;
  893. }
  894. //
  895. // initialize output depth param
  896. //
  897. *pulDepth = 0;
  898. if (!IsLegalDeviceId(pszDeviceID)) {
  899. Status = CR_INVALID_DEVNODE;
  900. goto Clean0;
  901. }
  902. //
  903. // Retrieve the device depth via kernel-mode.
  904. //
  905. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
  906. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  907. ControlData.DeviceDepth = 0;
  908. ntStatus = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
  909. &ControlData,
  910. sizeof(ControlData));
  911. if (!NT_SUCCESS(ntStatus)) {
  912. Status = MapNtStatusToCmError(ntStatus);
  913. } else {
  914. *pulDepth = ControlData.DeviceDepth;
  915. }
  916. Clean0:
  917. NOTHING;
  918. } except(EXCEPTION_EXECUTE_HANDLER) {
  919. Status = CR_FAILURE;
  920. }
  921. return Status;
  922. } // PNP_GetDepth
  923. //-------------------------------------------------------------------
  924. // Private functions
  925. //-------------------------------------------------------------------
  926. CONFIGRET
  927. GetServiceDeviceListSize(
  928. IN LPCWSTR pszService,
  929. OUT PULONG pulLength
  930. )
  931. /*++
  932. Routine Description:
  933. This routine returns the a list of device instances for the specificed
  934. enumerator.
  935. Arguments:
  936. pszService service whose device instances are to be listed
  937. pulLength On output, specifies the size in characters required to hold
  938. the device instance list.
  939. Return Value:
  940. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  941. a CR_* error code.
  942. --*/
  943. {
  944. CONFIGRET Status = CR_SUCCESS;
  945. ULONG ulType = 0, ulCount = 0, ulMaxValueData = 0, ulSize = 0;
  946. HKEY hKey = NULL, hEnumKey = NULL;
  947. try {
  948. //
  949. // validate parameters
  950. //
  951. if ((!ARGUMENT_PRESENT(pszService)) ||
  952. (!ARGUMENT_PRESENT(pulLength))) {
  953. Status = CR_INVALID_POINTER;
  954. }
  955. //
  956. // Open a key to the service branch
  957. //
  958. if (RegOpenKeyEx(ghServicesKey, pszService, 0, KEY_READ,
  959. &hKey) != ERROR_SUCCESS) {
  960. Status = CR_REGISTRY_ERROR;
  961. goto Clean0;
  962. }
  963. //
  964. // check if the service is specialy marked as type
  965. // PlugPlayServiceSoftware, in which case I will not
  966. // generate any madeup device ids and fail the call.
  967. //
  968. ulSize = sizeof(ulType);
  969. if (RegQueryValueEx(hKey, pszRegValuePlugPlayServiceType, NULL, NULL,
  970. (LPBYTE)&ulType, &ulSize) == ERROR_SUCCESS) {
  971. if (ulType == PlugPlayServiceSoftware) {
  972. Status = CR_NO_SUCH_VALUE;
  973. *pulLength = 0;
  974. goto Clean0;
  975. }
  976. }
  977. //
  978. // open the Enum key
  979. //
  980. if (RegOpenKeyEx(hKey, pszRegKeyEnum, 0, KEY_READ,
  981. &hEnumKey) != ERROR_SUCCESS) {
  982. //
  983. // Enum key doesn't exist so one will be generated, estimate
  984. // worst case device id size for the single generated device id
  985. //
  986. *pulLength = MAX_DEVICE_ID_LEN;
  987. goto Clean0;
  988. }
  989. //
  990. // retrieve the count of device instances controlled by this service
  991. //
  992. ulSize = sizeof(ulCount);
  993. if (RegQueryValueEx(hEnumKey, pszRegValueCount, NULL, NULL,
  994. (LPBYTE)&ulCount, &ulSize) != ERROR_SUCCESS) {
  995. ulCount = 1; // if empty, I'll generate one
  996. }
  997. if (ulCount == 0) {
  998. ulCount++; // if empty, I'll generate one
  999. }
  1000. if (RegQueryInfoKey(hEnumKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  1001. NULL, &ulMaxValueData, NULL, NULL) != ERROR_SUCCESS) {
  1002. *pulLength = ulCount * MAX_DEVICE_ID_LEN;
  1003. goto Clean0;
  1004. }
  1005. //
  1006. // worst case estimate is multiply number of device instances time
  1007. // length of the longest one + 2 null terminators
  1008. //
  1009. *pulLength = ulCount * (ulMaxValueData+1)/sizeof(WCHAR) + 2;
  1010. Clean0:
  1011. NOTHING;
  1012. } except (EXCEPTION_EXECUTE_HANDLER) {
  1013. Status = CR_FAILURE;
  1014. }
  1015. if (hEnumKey != NULL) {
  1016. RegCloseKey(hEnumKey);
  1017. }
  1018. if (hKey != NULL) {
  1019. RegCloseKey(hKey);
  1020. }
  1021. return Status;
  1022. } // GetServiceDeviceListSize
  1023. CONFIGRET
  1024. GetServiceDeviceList(
  1025. IN LPCWSTR pszService,
  1026. OUT LPWSTR pBuffer,
  1027. IN OUT PULONG pulLength,
  1028. IN ULONG ulFlags
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. This routine returns the a list of device instances for the specificed
  1033. enumerator.
  1034. Arguments:
  1035. pszService Service whose device instances are to be listed
  1036. pBuffer Pointer to a buffer that will hold the list in multi-sz
  1037. format
  1038. pulLength On input, specifies the size in characters of Buffer, on
  1039. Output, specifies the size in characters actually copied
  1040. to the buffer.
  1041. ulFlags Specifies CM_GETIDLIST_* flags supplied to
  1042. PNP_GetDeviceList (CM_GETIDLIST_FILTER_SERVICE
  1043. must be specified). This routine only checks for the
  1044. presence of the CM_GETIDLIST_DONOTGENERATE flag.
  1045. Return Value:
  1046. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  1047. a CR_* error code.
  1048. --*/
  1049. {
  1050. CONFIGRET Status = CR_SUCCESS;
  1051. LONG RegStatus = ERROR_SUCCESS;
  1052. WCHAR RegStr[MAX_CM_PATH], szDeviceID[MAX_DEVICE_ID_LEN+1];
  1053. ULONG ulType=0, ulBufferLen=0, ulSize=0, ulCount=0, i=0;
  1054. HKEY hKey = NULL, hEnumKey = NULL;
  1055. PLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA ControlData;
  1056. NTSTATUS NtStatus = STATUS_SUCCESS;
  1057. BOOL ServiceIsPlugPlay = FALSE;
  1058. ASSERT(ulFlags & CM_GETIDLIST_FILTER_SERVICE);
  1059. try {
  1060. //
  1061. // validate parameters
  1062. //
  1063. if ((!ARGUMENT_PRESENT(pszService)) ||
  1064. (!ARGUMENT_PRESENT(pulLength)) ||
  1065. (!ARGUMENT_PRESENT(pBuffer) && (*pulLength != 0))) {
  1066. Status = CR_INVALID_POINTER;
  1067. goto Clean0;
  1068. }
  1069. //
  1070. // the buffer must be at least large enough for a NULL multi-sz list
  1071. //
  1072. if (*pulLength == 0) {
  1073. Status = CR_BUFFER_SMALL;
  1074. goto Clean0;
  1075. }
  1076. *pBuffer = L'\0';
  1077. ulBufferLen = *pulLength;
  1078. //
  1079. // Open a key to the service branch
  1080. //
  1081. if (RegOpenKeyEx(ghServicesKey, pszService, 0, KEY_READ,
  1082. &hKey) != ERROR_SUCCESS) {
  1083. *pulLength = 0;
  1084. Status = CR_REGISTRY_ERROR;
  1085. goto Clean0;
  1086. }
  1087. //
  1088. // check if the service is specialy marked as type
  1089. // PlugPlayServiceSoftware, in which case I will not
  1090. // generate any madeup device ids and fail the call.
  1091. //
  1092. ulSize = sizeof(ulType);
  1093. if (RegQueryValueEx(hKey, pszRegValuePlugPlayServiceType, NULL, NULL,
  1094. (LPBYTE)&ulType, &ulSize) == ERROR_SUCCESS) {
  1095. if (ulType == PlugPlayServiceSoftware) {
  1096. //
  1097. // for PlugPlayServiceSoftware value, fail the call
  1098. //
  1099. *pulLength = 0;
  1100. Status = CR_NO_SUCH_VALUE;
  1101. goto Clean0;
  1102. }
  1103. ServiceIsPlugPlay = TRUE;
  1104. }
  1105. //
  1106. // open the Enum key
  1107. //
  1108. RegStatus = RegOpenKeyEx(hKey, pszRegKeyEnum, 0, KEY_READ,
  1109. &hEnumKey);
  1110. if (RegStatus == ERROR_SUCCESS) {
  1111. //
  1112. // retrieve count of device instances controlled by this service
  1113. //
  1114. ulSize = sizeof(ulCount);
  1115. if (RegQueryValueEx(hEnumKey, pszRegValueCount, NULL, NULL,
  1116. (LPBYTE)&ulCount, &ulSize) != ERROR_SUCCESS) {
  1117. ulCount = 0;
  1118. }
  1119. }
  1120. //
  1121. // if there are no device instances, create a default one
  1122. //
  1123. if (RegStatus != ERROR_SUCCESS || ulCount == 0) {
  1124. if (ulFlags & CM_GETIDLIST_DONOTGENERATE) {
  1125. //
  1126. // If I'm calling this routine privately, don't generate
  1127. // a new device instance, just give me an empty list
  1128. //
  1129. *pBuffer = L'\0';
  1130. *pulLength = 0;
  1131. goto Clean0;
  1132. }
  1133. if (ServiceIsPlugPlay) {
  1134. //
  1135. // Also, if plugplayservice type set, don't generate a
  1136. // new device instance, just return success with an empty list
  1137. //
  1138. *pBuffer = L'\0';
  1139. *pulLength = 0;
  1140. goto Clean0;
  1141. }
  1142. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA));
  1143. RtlInitUnicodeString(&ControlData.ServiceName, pszService);
  1144. ControlData.DeviceInstance = pBuffer;
  1145. ControlData.DeviceInstanceLength = *pulLength - 1;
  1146. NtStatus = NtPlugPlayControl(PlugPlayControlGenerateLegacyDevice,
  1147. &ControlData,
  1148. sizeof(ControlData));
  1149. if (NtStatus == STATUS_SUCCESS) {
  1150. *pulLength = ControlData.DeviceInstanceLength;
  1151. pBuffer[*pulLength] = L'\0'; // 1st NUL terminator
  1152. (*pulLength)++; // +1 for 1st NUL terminator
  1153. pBuffer[*pulLength] = L'\0'; // double NUL terminate
  1154. (*pulLength)++; // +1 for 2nd NUL terminator
  1155. } else {
  1156. *pBuffer = L'\0';
  1157. *pulLength = 0;
  1158. Status = CR_FAILURE;
  1159. }
  1160. goto Clean0;
  1161. }
  1162. //
  1163. // retrieve each device instance
  1164. //
  1165. for (i = 0; i < ulCount; i++) {
  1166. wsprintf(RegStr, TEXT("%d"), i);
  1167. ulSize = MAX_DEVICE_ID_LEN * sizeof(WCHAR);
  1168. RegStatus = RegQueryValueEx(hEnumKey, RegStr, NULL, NULL,
  1169. (LPBYTE)szDeviceID, &ulSize);
  1170. if (RegStatus != ERROR_SUCCESS) {
  1171. Status = CR_REGISTRY_ERROR;
  1172. goto Clean0;
  1173. }
  1174. //
  1175. // this string is not always null-terminated when I read it from the
  1176. // registry, even though it's REG_SZ.
  1177. //
  1178. ulSize /= sizeof(WCHAR);
  1179. if (szDeviceID[ulSize-1] != L'\0') {
  1180. szDeviceID[ulSize] = L'\0';
  1181. }
  1182. ulSize = ulBufferLen * sizeof(WCHAR); // total buffer size in bytes
  1183. if (!MultiSzAppendW(pBuffer, &ulSize, szDeviceID)) {
  1184. Status = CR_BUFFER_SMALL;
  1185. *pulLength = 0;
  1186. goto Clean0;
  1187. }
  1188. *pulLength = ulSize/sizeof(WCHAR); // chars to transfer
  1189. }
  1190. Clean0:
  1191. NOTHING;
  1192. } except (EXCEPTION_EXECUTE_HANDLER) {
  1193. Status = CR_FAILURE;
  1194. }
  1195. if (hEnumKey != NULL) {
  1196. RegCloseKey(hEnumKey);
  1197. }
  1198. if (hKey != NULL) {
  1199. RegCloseKey(hKey);
  1200. }
  1201. return Status;
  1202. } // GetServiceDeviceList
  1203. CONFIGRET
  1204. GetInstanceListSize(
  1205. IN LPCWSTR pszDevice,
  1206. OUT PULONG pulLength
  1207. )
  1208. /*++
  1209. Routine Description:
  1210. This routine returns the a list of device instances for the specificed
  1211. enumerator.
  1212. Arguments:
  1213. pszDevice device whose instances are to be listed
  1214. pulLength On output, specifies the size in characters required to hold
  1215. the device istance list.
  1216. Return Value:
  1217. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  1218. a CR_* error code.
  1219. --*/
  1220. {
  1221. CONFIGRET Status = CR_SUCCESS;
  1222. ULONG ulCount = 0, ulMaxKeyLen = 0;
  1223. HKEY hKey = NULL;
  1224. try {
  1225. //
  1226. // validate parameters
  1227. //
  1228. if ((!ARGUMENT_PRESENT(pszDevice)) ||
  1229. (!ARGUMENT_PRESENT(pulLength))) {
  1230. Status = CR_INVALID_POINTER;
  1231. goto Clean0;
  1232. }
  1233. //
  1234. // Open a key to the device instance
  1235. //
  1236. if (RegOpenKeyEx(ghEnumKey, pszDevice, 0, KEY_READ,
  1237. &hKey) != ERROR_SUCCESS) {
  1238. Status = CR_REGISTRY_ERROR;
  1239. goto Clean0;
  1240. }
  1241. //
  1242. // how many instance keys are under this device?
  1243. //
  1244. if (RegQueryInfoKey(hKey, NULL, NULL, NULL, &ulCount, &ulMaxKeyLen,
  1245. NULL, NULL, NULL, NULL, NULL, NULL)
  1246. != ERROR_SUCCESS) {
  1247. ulCount = 0;
  1248. ulMaxKeyLen = 0;
  1249. }
  1250. //
  1251. // do worst case estimate:
  1252. // length of the <enumerator>\<root> string +
  1253. // 1 char for the back slash before the instance +
  1254. // the length of the longest instance key + null term +
  1255. // multiplied by the number of instances under this device.
  1256. //
  1257. *pulLength = ulCount * (lstrlen(pszDevice) + ulMaxKeyLen + 2) + 1;
  1258. Clean0:
  1259. NOTHING;
  1260. } except (EXCEPTION_EXECUTE_HANDLER) {
  1261. Status = CR_FAILURE;
  1262. }
  1263. if (hKey != NULL) {
  1264. RegCloseKey(hKey);
  1265. }
  1266. return Status;
  1267. } // GetInstanceListSize
  1268. CONFIGRET
  1269. GetInstanceList(
  1270. IN LPCWSTR pszDevice,
  1271. IN OUT LPWSTR *pBuffer,
  1272. IN OUT PULONG pulLength
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. This routine returns the a list of device instances for the specificed
  1277. enumerator.
  1278. Arguments:
  1279. hEnumKey Handle to open Enum registry key
  1280. pszDevice device whose instances are to be listed
  1281. pBuffer On input, this points to place where the next element
  1282. should be copied (the buffer tail), on output, it also
  1283. points to the end of the buffer.
  1284. pulLength On input, specifies the size in characters of Buffer, on
  1285. Output, specifies how many characters actually copied to
  1286. the buffer. Includes an extra byte for the double-null term.
  1287. Return Value:
  1288. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  1289. a CR_* error code.
  1290. --*/
  1291. {
  1292. CONFIGRET Status = CR_SUCCESS;
  1293. LONG RegStatus = ERROR_SUCCESS;
  1294. WCHAR RegStr[MAX_CM_PATH], szInstance[MAX_DEVICE_ID_LEN];
  1295. ULONG ulBufferLen=0, ulSize=0, ulIndex=0, ulLen=0;
  1296. HKEY hKey = NULL;
  1297. try {
  1298. //
  1299. // validate parameters
  1300. //
  1301. if ((!ARGUMENT_PRESENT(pszDevice)) ||
  1302. (!ARGUMENT_PRESENT(*pBuffer)) ||
  1303. (!ARGUMENT_PRESENT(pulLength))) {
  1304. Status = CR_INVALID_POINTER;
  1305. goto Clean0;
  1306. }
  1307. //
  1308. // Open a key for this Enumerator\Device branch
  1309. //
  1310. if (RegOpenKeyEx(ghEnumKey, pszDevice, 0, KEY_ENUMERATE_SUB_KEYS,
  1311. &hKey) != ERROR_SUCCESS) {
  1312. Status = CR_REGISTRY_ERROR;
  1313. goto Clean0;
  1314. }
  1315. ulBufferLen = *pulLength; // total size of pBuffer
  1316. *pulLength = 0; // no data copied yet
  1317. ulIndex = 0;
  1318. //
  1319. // enumerate the instance keys
  1320. //
  1321. while (RegStatus == ERROR_SUCCESS) {
  1322. ulLen = MAX_DEVICE_ID_LEN; // size in chars
  1323. RegStatus = RegEnumKeyEx(hKey, ulIndex, szInstance, &ulLen,
  1324. NULL, NULL, NULL, NULL);
  1325. ulIndex++;
  1326. if (RegStatus == ERROR_SUCCESS) {
  1327. wsprintf(RegStr, TEXT("%s\\%s"),
  1328. pszDevice,
  1329. szInstance);
  1330. if (IsValidDeviceID(RegStr, NULL, 0)) {
  1331. ulSize = lstrlen(RegStr) + 1; // size of new element
  1332. *pulLength += ulSize; // size copied so far
  1333. if (*pulLength + 1 > ulBufferLen) {
  1334. *pulLength = 0;
  1335. Status = CR_BUFFER_SMALL;
  1336. goto Clean0;
  1337. }
  1338. lstrcpy(*pBuffer, RegStr); // copy the element
  1339. *pBuffer += ulSize; // move to tail of buffer
  1340. }
  1341. }
  1342. }
  1343. **pBuffer = 0x0; // double-null terminate it
  1344. *pulLength += 1; // include room for double-null terminator
  1345. Clean0:
  1346. NOTHING;
  1347. } except (EXCEPTION_EXECUTE_HANDLER) {
  1348. Status = CR_FAILURE;
  1349. }
  1350. if (hKey != NULL) {
  1351. RegCloseKey(hKey);
  1352. }
  1353. return Status;
  1354. } // GetInstanceList
  1355. CONFIGRET
  1356. GetDeviceInstanceListSize(
  1357. IN LPCWSTR pszEnumerator,
  1358. OUT PULONG pulLength
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. This routine returns the a list of device instances for the specificed
  1363. enumerator.
  1364. Arguments:
  1365. pszEnumerator Enumerator whose device instances are to be listed
  1366. pulLength On output, specifies how many characters required to hold
  1367. the device instance list.
  1368. Return Value:
  1369. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  1370. a CR_* error code.
  1371. --*/
  1372. {
  1373. CONFIGRET Status = CR_SUCCESS;
  1374. LONG RegStatus = ERROR_SUCCESS;
  1375. ULONG ulSize = 0, ulIndex = 0;
  1376. WCHAR RegStr[MAX_CM_PATH], szDevice[MAX_DEVICE_ID_LEN];
  1377. HKEY hKey = NULL;
  1378. try {
  1379. //
  1380. // validate parameters
  1381. //
  1382. if ((!ARGUMENT_PRESENT(pszEnumerator)) ||
  1383. (!ARGUMENT_PRESENT(pulLength))) {
  1384. Status = CR_INVALID_POINTER;
  1385. goto Clean0;
  1386. }
  1387. //
  1388. // initialize output length param
  1389. //
  1390. *pulLength = 0;
  1391. //
  1392. // Open a key for this Enumerator branch
  1393. //
  1394. if (RegOpenKeyEx(ghEnumKey, pszEnumerator, 0, KEY_ENUMERATE_SUB_KEYS,
  1395. &hKey) != ERROR_SUCCESS) {
  1396. Status = CR_REGISTRY_ERROR;
  1397. goto Clean0;
  1398. }
  1399. //
  1400. // Enumerate the device keys
  1401. //
  1402. ulIndex = 0;
  1403. while (RegStatus == ERROR_SUCCESS) {
  1404. ulSize = MAX_DEVICE_ID_LEN; // size in chars
  1405. RegStatus = RegEnumKeyEx(hKey, ulIndex, szDevice, &ulSize,
  1406. NULL, NULL, NULL, NULL);
  1407. ulIndex++;
  1408. if (RegStatus == ERROR_SUCCESS) {
  1409. //
  1410. // Retreive the size of the instance list for this device
  1411. //
  1412. wsprintf(RegStr, TEXT("%s\\%s"),
  1413. pszEnumerator,
  1414. szDevice);
  1415. if ((Status = GetInstanceListSize(RegStr, &ulSize)) != CR_SUCCESS) {
  1416. *pulLength = 0;
  1417. goto Clean0;
  1418. }
  1419. *pulLength += ulSize;
  1420. }
  1421. }
  1422. Clean0:
  1423. NOTHING;
  1424. } except (EXCEPTION_EXECUTE_HANDLER) {
  1425. Status = CR_FAILURE;
  1426. }
  1427. if (hKey != NULL) {
  1428. RegCloseKey(hKey);
  1429. }
  1430. return Status;
  1431. } // GetDeviceInstanceListSize
  1432. CONFIGRET
  1433. GetDeviceInstanceList(
  1434. IN LPCWSTR pszEnumerator,
  1435. IN OUT LPWSTR *pBuffer,
  1436. IN OUT PULONG pulLength
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. This routine returns the a list of device instances for the specificed
  1441. enumerator.
  1442. Arguments:
  1443. hEnumKey Handle of open Enum (parent) registry key
  1444. pszEnumerator Enumerator whose device instances are to be listed
  1445. pBuffer On input, this points to place where the next element
  1446. should be copied (the buffer tail), on output, it also
  1447. points to the end of the buffer.
  1448. pulLength On input, specifies the size in characters of Buffer, on
  1449. Output, specifies how many characters actuall copied to
  1450. the buffer. Includes an extra byte for the double-null
  1451. term.
  1452. Return Value:
  1453. If the function succeeds, it returns CR_SUCCESS, otherwise it returns
  1454. a CR_* error code.
  1455. --*/
  1456. {
  1457. CONFIGRET Status = CR_SUCCESS;
  1458. LONG RegStatus = ERROR_SUCCESS;
  1459. ULONG ulBufferLen=0, ulSize=0, ulIndex=0, ulLen=0;
  1460. WCHAR RegStr[MAX_CM_PATH], szDevice[MAX_DEVICE_ID_LEN];
  1461. HKEY hKey = NULL;
  1462. try {
  1463. //
  1464. // validate parameters
  1465. //
  1466. if ((!ARGUMENT_PRESENT(pszEnumerator)) ||
  1467. (!ARGUMENT_PRESENT(*pBuffer)) ||
  1468. (!ARGUMENT_PRESENT(pulLength))) {
  1469. Status = CR_INVALID_POINTER;
  1470. goto Clean0;
  1471. }
  1472. //
  1473. // Open a key for this Enumerator branch
  1474. //
  1475. if (RegOpenKeyEx(ghEnumKey, pszEnumerator, 0, KEY_ENUMERATE_SUB_KEYS,
  1476. &hKey) != ERROR_SUCCESS) {
  1477. Status = CR_REGISTRY_ERROR;
  1478. goto Clean0;
  1479. }
  1480. ulIndex = 0;
  1481. ulSize = ulBufferLen = *pulLength; // total size of pBuffer
  1482. *pulLength = 0;
  1483. //
  1484. // Enumerate the device keys
  1485. //
  1486. while (RegStatus == ERROR_SUCCESS) {
  1487. ulLen = MAX_DEVICE_ID_LEN; // size in chars
  1488. RegStatus = RegEnumKeyEx(hKey, ulIndex, szDevice, &ulLen,
  1489. NULL, NULL, NULL, NULL);
  1490. ulIndex++;
  1491. if (RegStatus == ERROR_SUCCESS) {
  1492. //
  1493. // Enumerate the Instance keys
  1494. //
  1495. wsprintf(RegStr, TEXT("%s\\%s"),
  1496. pszEnumerator,
  1497. szDevice);
  1498. Status = GetInstanceList(RegStr, pBuffer, &ulSize);
  1499. if (Status != CR_SUCCESS) {
  1500. *pulLength = 0;
  1501. goto Clean0;
  1502. }
  1503. *pulLength += ulSize - 1; // data copied so far
  1504. ulSize = ulBufferLen - *pulLength; // buffer size left over
  1505. }
  1506. }
  1507. *pulLength += 1; // now add room for second null term
  1508. Clean0:
  1509. NOTHING;
  1510. } except (EXCEPTION_EXECUTE_HANDLER) {
  1511. Status = CR_FAILURE;
  1512. }
  1513. if (hKey != NULL) {
  1514. RegCloseKey(hKey);
  1515. }
  1516. return Status;
  1517. } // GetDeviceInstanceList
  1518. PNP_QUERY_RELATION
  1519. QueryOperationCode(
  1520. ULONG ulFlags
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. This routine converts the CM_GETIDLIST_FILTER_Xxx query relation type
  1525. flags into the corresponding enum value that NtPlugPlayControl understands.
  1526. Arguments:
  1527. ulFlags CM API CM_GETIDLIST_FILTER_Xxx value
  1528. Return Value:
  1529. One of the enum PNP_QUERY_RELATION values.
  1530. --*/
  1531. {
  1532. switch (ulFlags) {
  1533. case CM_GETIDLIST_FILTER_EJECTRELATIONS:
  1534. return PnpQueryEjectRelations;
  1535. case CM_GETIDLIST_FILTER_REMOVALRELATIONS:
  1536. return PnpQueryRemovalRelations;
  1537. case CM_GETIDLIST_FILTER_POWERRELATIONS:
  1538. return PnpQueryPowerRelations;
  1539. case CM_GETIDLIST_FILTER_BUSRELATIONS:
  1540. return PnpQueryBusRelations;
  1541. default:
  1542. return (ULONG)-1;
  1543. }
  1544. } // QueryOperationCode