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.

2273 lines
63 KiB

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