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.

1954 lines
53 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. traverse.c
  5. Abstract:
  6. This module contains the API routines that perform hardware tree
  7. traversal.
  8. CM_Locate_DevNode
  9. CM_Get_Parent
  10. CM_Get_Child
  11. CM_Get_Sibling
  12. CM_Get_Device_ID_Size
  13. CM_Get_Device_ID
  14. CM_Enumerate_Enumerators
  15. CM_Get_Device_ID_List
  16. CM_Get_Device_ID_List_Size
  17. CM_Get_Depth
  18. Author:
  19. Paula Tomlinson (paulat) 6-20-1995
  20. Environment:
  21. User mode only.
  22. Revision History:
  23. 6-Jun-1995 paulat
  24. Creation and initial implementation.
  25. --*/
  26. //
  27. // includes
  28. //
  29. #include "precomp.h"
  30. #pragma hdrstop
  31. #include "cfgi.h"
  32. CONFIGRET
  33. CM_Locate_DevNode_ExW(
  34. OUT PDEVINST pdnDevInst,
  35. IN DEVINSTID_W pDeviceID, OPTIONAL
  36. IN ULONG ulFlags,
  37. IN HMACHINE hMachine
  38. )
  39. /*++
  40. Routine Description:
  41. This routine retrieves the handle of the device instance that
  42. corresponds to a specified device identifier.
  43. Parameters:
  44. pdnDevInst Supplies the address of the variable that receives the
  45. handle of a device instance.
  46. pDeviceID Supplies the address of a null-terminated string specifying
  47. a device identifier. If this parameter is NULL, the API
  48. retrieves a handle to the device instance at the root of
  49. the hardware tree.
  50. ulFlags Supplies flags specifying options for locating the device
  51. instance. May be a combination of the following values:
  52. CM_LOCATE_DEVNODE_NORMAL - Locate only device instances
  53. that are currently alive from the ConfigMgr's point of
  54. view.
  55. CM_LOCATE_DEVNODE_PHANTOM - Allows a device instance handle
  56. to be returned for a device instance that is not
  57. currently alive, but that does exist in the registry.
  58. This may be used with other CM APIs that require a
  59. devnode handle, but for which there currently is none
  60. for a particular device (e.g., you want to set a device
  61. registry property for a device not currently present).
  62. This flag does not allow you to locate phantom devnodes
  63. created by using CM_Create_DevNode with the
  64. CM_CREATE_DEVNODE_PHANTOM flag (such device instances
  65. are only accessible by the caller who holds the devnode
  66. handle returned from that API).
  67. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  68. Return value:
  69. If the function succeeds, the return value is CR_SUCCESS.
  70. If the function fails, the return value is one of the following:
  71. CR_INVALID_DEVICE_ID,
  72. CR_INVALID_FLAG,
  73. CR_INVALID_POINTER,
  74. CR_NO_SUCH_DEVNODE,
  75. CR_REMOTE_COMM_FAILURE,
  76. CR_MACHINE_UNAVAILABLE,
  77. CR_FAILURE.
  78. --*/
  79. {
  80. CONFIGRET Status = CR_SUCCESS;
  81. WCHAR szFixedUpDeviceID[MAX_DEVICE_ID_LEN];
  82. PVOID hStringTable = NULL;
  83. handle_t hBinding = NULL;
  84. size_t DeviceIDLen = 0;
  85. try {
  86. //
  87. // validate input parameters
  88. //
  89. if (!ARGUMENT_PRESENT(pdnDevInst)) {
  90. Status = CR_INVALID_POINTER;
  91. goto Clean0;
  92. }
  93. if (INVALID_FLAGS(ulFlags, CM_LOCATE_DEVNODE_BITS)) {
  94. Status = CR_INVALID_FLAG;
  95. goto Clean0;
  96. }
  97. //
  98. // CM_LOCATE_DEVNODE_NOVALIDATION is not supported on NT
  99. //
  100. if (IS_FLAG_SET(ulFlags, CM_LOCATE_DEVNODE_NOVALIDATION)) {
  101. Status = CR_INVALID_FLAG;
  102. goto Clean0;
  103. }
  104. //
  105. // initialize output parameters
  106. //
  107. *pdnDevInst = 0;
  108. //
  109. // setup rpc binding handle and string table handle
  110. //
  111. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  112. Status = CR_FAILURE;
  113. goto Clean0;
  114. }
  115. //
  116. // if a device instance was specified, make sure it's not too long
  117. //
  118. if (ARGUMENT_PRESENT(pDeviceID)) {
  119. if (FAILED(StringCchLength(
  120. pDeviceID,
  121. MAX_DEVICE_ID_LEN,
  122. &DeviceIDLen))) {
  123. Status = CR_INVALID_DEVICE_ID;
  124. goto Clean0;
  125. }
  126. ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
  127. }
  128. //------------------------------------------------------------------
  129. // if the device instance is NULL or it's a zero-length string, then
  130. // retreive the root device instance
  131. //------------------------------------------------------------------
  132. if ((!ARGUMENT_PRESENT(pDeviceID)) || (DeviceIDLen == 0)) {
  133. //
  134. // No special privileges are required by the server
  135. //
  136. RpcTryExcept {
  137. //
  138. // call rpc service entry point
  139. //
  140. Status = PNP_GetRootDeviceInstance(
  141. hBinding, // rpc binding handle
  142. szFixedUpDeviceID, // return device instance string
  143. MAX_DEVICE_ID_LEN); // length of DeviceInstanceID
  144. }
  145. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  146. KdPrintEx((DPFLTR_PNPMGR_ID,
  147. DBGF_ERRORS,
  148. "PNP_GetRootDeviceInstance caused an exception (%d)\n",
  149. RpcExceptionCode()));
  150. Status = MapRpcExceptionToCR(RpcExceptionCode());
  151. }
  152. RpcEndExcept
  153. }
  154. //------------------------------------------------------------------
  155. // if the device instance was specified, validate the string
  156. //------------------------------------------------------------------
  157. else {
  158. //
  159. // first see if the format of the device id string is valid, this
  160. // can be done on the client side
  161. //
  162. if (!IsLegalDeviceId(pDeviceID)) {
  163. Status = CR_INVALID_DEVICE_ID;
  164. goto Clean0;
  165. }
  166. //
  167. // Next, fix up the device ID string for consistency (uppercase, etc)
  168. //
  169. CopyFixedUpDeviceId(szFixedUpDeviceID,
  170. pDeviceID,
  171. (DWORD)DeviceIDLen);
  172. //
  173. // finally, validate the presense of the device ID string, this must
  174. // be done by the server
  175. //
  176. //
  177. // No special privileges are required by the server
  178. //
  179. RpcTryExcept {
  180. //
  181. // call rpc service entry point
  182. //
  183. Status = PNP_ValidateDeviceInstance(
  184. hBinding, // rpc binding handle
  185. szFixedUpDeviceID, // device id
  186. ulFlags); // locate flag
  187. }
  188. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  189. KdPrintEx((DPFLTR_PNPMGR_ID,
  190. DBGF_ERRORS,
  191. "PNP_ValidateDeviceInstance caused an exception (%d)\n",
  192. RpcExceptionCode()));
  193. Status = MapRpcExceptionToCR(RpcExceptionCode());
  194. }
  195. RpcEndExcept
  196. }
  197. if (Status != CR_SUCCESS) {
  198. goto Clean0;
  199. }
  200. //------------------------------------------------------------------
  201. // In either case, if we're successful then we have a valid device
  202. // ID. Use the string table to assign a unique DevNode to this
  203. // device id (if it's already in the string table, it just retrieves
  204. // the existing unique value)
  205. //------------------------------------------------------------------
  206. ASSERT(*szFixedUpDeviceID && IsLegalDeviceId(szFixedUpDeviceID));
  207. *pdnDevInst = pSetupStringTableAddString(hStringTable,
  208. szFixedUpDeviceID,
  209. STRTAB_CASE_SENSITIVE);
  210. if (*pdnDevInst == (DEVINST)(-1)) {
  211. Status = CR_FAILURE;
  212. }
  213. Clean0:
  214. NOTHING;
  215. } except(EXCEPTION_EXECUTE_HANDLER) {
  216. Status = CR_FAILURE;
  217. }
  218. return Status;
  219. } // CM_Locate_DevNode_ExW
  220. CONFIGRET
  221. CM_Get_Parent_Ex(
  222. OUT PDEVINST pdnDevInst,
  223. IN DEVINST dnDevInst,
  224. IN ULONG ulFlags,
  225. IN HMACHINE hMachine
  226. )
  227. /*++
  228. Routine Description:
  229. This routine retrieves the handle of the parent of a device instance.
  230. Parameters:
  231. pdnDevInst Supplies the address of the variable that receives a
  232. handle to the parent device instance.
  233. dnDevInst Supplies the handle of the child device instance string.
  234. ulFlags Must be zero.
  235. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  236. Return value:
  237. If the function succeeds, the return value is CR_SUCCESS.
  238. If the function fails, the return value is one of the following:
  239. CR_INVALID_DEVNODE,
  240. CR_INVALID_FLAG,
  241. CR_INVALID_POINTER,
  242. CR_NO_SUCH_DEVNODE,
  243. CR_REMOTE_COMM_FAILURE,
  244. CR_MACHINE_UNAVAILABLE,
  245. CR_FAILURE.
  246. --*/
  247. {
  248. CONFIGRET Status = CR_SUCCESS;
  249. WCHAR szDeviceID[MAX_DEVICE_ID_LEN],
  250. pDeviceID [MAX_DEVICE_ID_LEN];
  251. ULONG ulSize = MAX_DEVICE_ID_LEN;
  252. PVOID hStringTable = NULL;
  253. handle_t hBinding = NULL;
  254. BOOL Success;
  255. try {
  256. //
  257. // validate input parameters
  258. //
  259. if (dnDevInst == 0) {
  260. Status = CR_INVALID_DEVINST;
  261. goto Clean0;
  262. }
  263. if (!ARGUMENT_PRESENT(pdnDevInst)) {
  264. Status = CR_INVALID_POINTER;
  265. goto Clean0;
  266. }
  267. if (INVALID_FLAGS(ulFlags, 0)) {
  268. Status = CR_INVALID_FLAG;
  269. goto Clean0;
  270. }
  271. //
  272. // initialize output parameters
  273. //
  274. *pdnDevInst = 0;
  275. //
  276. // setup rpc binding handle and string table handle
  277. //
  278. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  279. Status = CR_FAILURE;
  280. goto Clean0;
  281. }
  282. //
  283. // retreive device instance string that corresponds to dnDevInst
  284. //
  285. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulSize);
  286. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  287. Status = CR_INVALID_DEVINST; // "input" devinst doesn't exist
  288. goto Clean0;
  289. }
  290. ulSize = MAX_DEVICE_ID_LEN;
  291. //
  292. // No special privileges are required by the server
  293. //
  294. RpcTryExcept {
  295. //
  296. // call rpc service entry point
  297. //
  298. Status = PNP_GetRelatedDeviceInstance(
  299. hBinding, // rpc binding handle
  300. PNP_GET_PARENT_DEVICE_INSTANCE, // requested action
  301. pDeviceID, // base device instance
  302. szDeviceID, // returns parent device instance
  303. &ulSize,
  304. ulFlags); // not used
  305. }
  306. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  307. KdPrintEx((DPFLTR_PNPMGR_ID,
  308. DBGF_ERRORS,
  309. "PNP_GetRelatedDeviceInstance caused an exception (%d)\n",
  310. RpcExceptionCode()));
  311. Status = MapRpcExceptionToCR(RpcExceptionCode());
  312. }
  313. RpcEndExcept
  314. if (Status != CR_SUCCESS) {
  315. goto Clean0;
  316. }
  317. //
  318. // add the returned device id to the string table so I can get a
  319. // devnode id for it (if it's already in the string table, the
  320. // existing id will be returned)
  321. //
  322. CharUpper(szDeviceID);
  323. ASSERT(*szDeviceID && IsLegalDeviceId(szDeviceID));
  324. *pdnDevInst = pSetupStringTableAddString(hStringTable,
  325. szDeviceID,
  326. STRTAB_CASE_SENSITIVE);
  327. if (*pdnDevInst == (DEVINST)(-1)) {
  328. Status = CR_FAILURE;
  329. }
  330. Clean0:
  331. NOTHING;
  332. } except(EXCEPTION_EXECUTE_HANDLER) {
  333. Status = CR_FAILURE;
  334. }
  335. return Status;
  336. } // CM_Get_Parent_Ex
  337. CONFIGRET
  338. CM_Get_Child_Ex(
  339. OUT PDEVINST pdnDevInst,
  340. IN DEVINST dnDevInst,
  341. IN ULONG ulFlags,
  342. IN HMACHINE hMachine
  343. )
  344. /*++
  345. Routine Description:
  346. This routine retrieves the first child of a given device instance.
  347. Parameters:
  348. pdnDevInst Supplies the address of the variable that receives the
  349. handle of the device instance.
  350. dnDevInst Supplies the handle of the parent device instance.
  351. ulFlags Must be zero.
  352. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  353. Return value:
  354. If the function succeeds, the return value is CR_SUCCESS.
  355. If the function fails, the return value is one of the following:
  356. CR_INVALID_DEVNODE,
  357. CR_INVALID_FLAG,
  358. CR_INVALID_POINTER,
  359. CR_NO_SUCH_DEVNODE,
  360. CR_REMOTE_COMM_FAILURE,
  361. CR_MACHINE_UNAVAILABLE,
  362. CR_FAILURE.
  363. --*/
  364. {
  365. CONFIGRET Status = CR_SUCCESS;
  366. WCHAR szDeviceID[MAX_DEVICE_ID_LEN],
  367. pDeviceID [MAX_DEVICE_ID_LEN];
  368. ULONG ulSize = MAX_DEVICE_ID_LEN;
  369. PVOID hStringTable = NULL;
  370. handle_t hBinding = NULL;
  371. BOOL Success;
  372. try {
  373. //
  374. // validate input parameters
  375. //
  376. if (dnDevInst == 0) {
  377. Status = CR_INVALID_DEVINST;
  378. goto Clean0;
  379. }
  380. if (!ARGUMENT_PRESENT(pdnDevInst)) {
  381. Status = CR_INVALID_POINTER;
  382. goto Clean0;
  383. }
  384. if (INVALID_FLAGS(ulFlags, 0)) {
  385. Status = CR_INVALID_FLAG;
  386. goto Clean0;
  387. }
  388. //
  389. // initialize output parameters
  390. //
  391. *pdnDevInst = 0;
  392. //
  393. // setup rpc binding handle and string table handle
  394. //
  395. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  396. Status = CR_FAILURE;
  397. goto Clean0;
  398. }
  399. //
  400. // retreive device instance string that corresponds to dnDevInst
  401. //
  402. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulSize);
  403. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  404. Status = CR_INVALID_DEVINST; // "input" devinst doesn't exist
  405. goto Clean0;
  406. }
  407. ulSize = MAX_DEVICE_ID_LEN;
  408. //
  409. // No special privileges are required by the server
  410. //
  411. RpcTryExcept {
  412. //
  413. // call rpc service entry point
  414. //
  415. Status = PNP_GetRelatedDeviceInstance(
  416. hBinding, // rpc binding handle
  417. PNP_GET_CHILD_DEVICE_INSTANCE, // requested action
  418. pDeviceID, // base device instance
  419. szDeviceID, // child device instance
  420. &ulSize,
  421. ulFlags); // not used
  422. }
  423. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  424. KdPrintEx((DPFLTR_PNPMGR_ID,
  425. DBGF_ERRORS,
  426. "PNP_GetRelatedDeviceInstance caused an exception (%d)\n",
  427. RpcExceptionCode()));
  428. Status = MapRpcExceptionToCR(RpcExceptionCode());
  429. }
  430. RpcEndExcept
  431. if (Status != CR_SUCCESS) {
  432. goto Clean0;
  433. }
  434. //
  435. // add the returned device id to the string table so I can get a
  436. // devnode id for it (if it's already in the string table, the
  437. // existing id will be returned)
  438. //
  439. CharUpper(szDeviceID);
  440. ASSERT(*szDeviceID && IsLegalDeviceId(szDeviceID));
  441. *pdnDevInst = pSetupStringTableAddString(hStringTable,
  442. szDeviceID,
  443. STRTAB_CASE_SENSITIVE);
  444. if (*pdnDevInst == (DEVINST)(-1)) {
  445. Status = CR_FAILURE;
  446. }
  447. Clean0:
  448. NOTHING;
  449. } except(EXCEPTION_EXECUTE_HANDLER) {
  450. Status = CR_FAILURE;
  451. }
  452. return Status;
  453. } // CM_Get_Child_Ex
  454. CONFIGRET
  455. CM_Get_Sibling_Ex(
  456. OUT PDEVINST pdnDevInst,
  457. IN DEVINST dnDevInst,
  458. IN ULONG ulFlags,
  459. IN HMACHINE hMachine
  460. )
  461. /*++
  462. Routine Description:
  463. This routine retrieves the sibling of a device instance.
  464. This API can be called in a loop to retrieve all the siblings of a
  465. device instance. When the API returns CR_NO_SUCH_DEVNODE, there are no
  466. more siblings to enumerate. In order to enumerate all children of a
  467. device instance, this loop must start with the device instance retrieved
  468. by calling CM_Get_Child to get the first sibling.
  469. Parameters:
  470. pdnDevInst Supplies the address of the variable that receives a
  471. handle to the sibling device instance.
  472. dnDevInst Supplies the handle of a device instance.
  473. ulFlags Must be zero.
  474. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  475. Return value:
  476. If the function succeeds, the return value is CR_SUCCESS.
  477. If the function fails, the return value is one of the following:
  478. CR_INVALID_DEVNODE,
  479. CR_INVALID_FLAG,
  480. CR_INVALID_POINTER,
  481. CR_NO_SUCH_DEVNODE,
  482. CR_REMOTE_COMM_FAILURE,
  483. CR_MACHINE_UNAVAILABLE,
  484. CR_FAILURE.
  485. --*/
  486. {
  487. CONFIGRET Status = CR_SUCCESS;
  488. WCHAR szDeviceID[MAX_DEVICE_ID_LEN],
  489. pDeviceID [MAX_DEVICE_ID_LEN];
  490. ULONG ulSize = MAX_DEVICE_ID_LEN;
  491. PVOID hStringTable = NULL;
  492. handle_t hBinding = NULL;
  493. BOOL Success;
  494. try {
  495. //
  496. // validate input parameters
  497. //
  498. if (dnDevInst == 0) {
  499. Status = CR_INVALID_DEVINST;
  500. goto Clean0;
  501. }
  502. if (!ARGUMENT_PRESENT(pdnDevInst)) {
  503. Status = CR_INVALID_POINTER;
  504. goto Clean0;
  505. }
  506. if (INVALID_FLAGS(ulFlags, 0)) {
  507. Status = CR_INVALID_FLAG;
  508. goto Clean0;
  509. }
  510. //
  511. // initialize output parameters
  512. //
  513. *pdnDevInst = 0;
  514. //
  515. // setup rpc binding handle and string table handle
  516. //
  517. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  518. Status = CR_FAILURE;
  519. goto Clean0;
  520. }
  521. //
  522. // retreive device instance string that corresponds to dnDevInst
  523. //
  524. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulSize);
  525. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  526. Status = CR_INVALID_DEVINST; // "input" devinst doesn't exist
  527. goto Clean0;
  528. }
  529. ulSize = MAX_DEVICE_ID_LEN;
  530. //
  531. // No special privileges are required by the server
  532. //
  533. RpcTryExcept {
  534. //
  535. // call rpc service entry point
  536. //
  537. Status = PNP_GetRelatedDeviceInstance(
  538. hBinding, // rpc binding handle
  539. PNP_GET_SIBLING_DEVICE_INSTANCE, // requested action
  540. pDeviceID, // base device instance
  541. szDeviceID, // sibling device instance
  542. &ulSize,
  543. ulFlags); // not used
  544. }
  545. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  546. KdPrintEx((DPFLTR_PNPMGR_ID,
  547. DBGF_ERRORS,
  548. "PNP_GetRelatedDeviceInstance caused an exception (%d)\n",
  549. RpcExceptionCode()));
  550. Status = MapRpcExceptionToCR(RpcExceptionCode());
  551. }
  552. RpcEndExcept
  553. if (Status != CR_SUCCESS) {
  554. goto Clean0;
  555. }
  556. //
  557. // add the returned device id to the string table so I can get a
  558. // devnode id for it (if it's already in the string table, the
  559. // existing id will be returned)
  560. //
  561. CharUpper(szDeviceID);
  562. ASSERT(*szDeviceID && IsLegalDeviceId(szDeviceID));
  563. *pdnDevInst = pSetupStringTableAddString(hStringTable,
  564. szDeviceID,
  565. STRTAB_CASE_SENSITIVE);
  566. if (*pdnDevInst == (DEVINST)(-1)) {
  567. Status = CR_FAILURE;
  568. }
  569. Clean0:
  570. NOTHING;
  571. } except(EXCEPTION_EXECUTE_HANDLER) {
  572. Status = CR_FAILURE;
  573. }
  574. return Status;
  575. } // CM_Get_Sibling_Ex
  576. CONFIGRET
  577. CM_Get_Device_ID_Size_Ex(
  578. OUT PULONG pulLen,
  579. IN DEVINST dnDevInst,
  580. IN ULONG ulFlags,
  581. IN HMACHINE hMachine
  582. )
  583. /*++
  584. Routine Description:
  585. This routine retrieves the size of a device identifier from a
  586. device instance.
  587. Parameters:
  588. pulLen Supplies the address of the variable that receives the size
  589. in characters, not including the terminating NULL, of the
  590. device identifier. The API sets the variable to 0 if no
  591. identifier exists. The size is always less than or equal to
  592. MAX_DEVICE_ID_LEN.
  593. dnDevInst Supplies the handle of the device instance.
  594. ulFlags Must be zero.
  595. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  596. Return Value:
  597. If the function succeeds, the return value is CR_SUCCESS.
  598. If the function fails, the return value is one of the following:
  599. CR_INVALID_DEVNODE,
  600. CR_INVALID_FLAG,
  601. CR_INVALID_POINTER,
  602. CR_REMOTE_COMM_FAILURE,
  603. CR_MACHINE_UNAVAILABLE,
  604. CR_FAILURE.
  605. --*/
  606. {
  607. CONFIGRET Status = CR_SUCCESS;
  608. WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
  609. PVOID hStringTable = NULL;
  610. BOOL Success;
  611. DWORD ulLen;
  612. try {
  613. //
  614. // validate parameters
  615. //
  616. if (dnDevInst == 0) {
  617. Status = CR_INVALID_DEVINST;
  618. goto Clean0;
  619. }
  620. if (!ARGUMENT_PRESENT(pulLen)) {
  621. Status = CR_INVALID_POINTER;
  622. goto Clean0;
  623. }
  624. if (INVALID_FLAGS(ulFlags, 0)) {
  625. Status = CR_INVALID_FLAG;
  626. goto Clean0;
  627. }
  628. //
  629. // setup string table handle
  630. //
  631. if (!PnPGetGlobalHandles(hMachine, &hStringTable, NULL)) {
  632. Status = CR_FAILURE;
  633. goto Clean0;
  634. }
  635. //
  636. // retrieve the string form of the device id string
  637. // use private ulLen, since we know this is valid
  638. //
  639. ulLen = MAX_DEVICE_ID_LEN;
  640. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulLen);
  641. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  642. *pulLen = 0;
  643. Status = CR_INVALID_DEVINST;
  644. }
  645. //
  646. // discount the terminating NULL char,
  647. // included in the size reported by pSetupStringTableStringFromIdEx
  648. //
  649. *pulLen = ulLen - 1;
  650. Clean0:
  651. NOTHING;
  652. } except(EXCEPTION_EXECUTE_HANDLER) {
  653. Status = CR_FAILURE;
  654. }
  655. return Status;
  656. } // CM_Get_Device_ID_Size_Ex
  657. CONFIGRET
  658. CM_Get_Device_ID_ExW(
  659. IN DEVINST dnDevInst,
  660. OUT PWCHAR Buffer,
  661. IN ULONG BufferLen,
  662. IN ULONG ulFlags,
  663. IN HMACHINE hMachine
  664. )
  665. /*++
  666. Routine Description:
  667. This routine retrieves the device identifier for a device instance.
  668. Parameters:
  669. dnDevNode Supplies the handle of the device instance for which to
  670. retrieve the device identifier.
  671. Buffer Supplies the address of the buffer that receives the device
  672. identifier. If this buffer is larger than the device
  673. identifier, the API appends a null-terminating character to
  674. the data. If it is smaller than the device identifier, the API
  675. fills it with as much of the device identifier as will fit
  676. and returns CR_BUFFER_SMALL.
  677. BufferLen Supplies the size, in characters, of the buffer for the device
  678. identifier.
  679. ulFlags Must be zero.
  680. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  681. Return Value:
  682. If the function succeeds, the return value is CR_SUCCESS.
  683. If the function fails, the return value is one of the following:
  684. CR_BUFFER_SMALL,
  685. CR_INVALID_DEVNODE,
  686. CR_INVALID_FLAG,
  687. CR_INVALID_POINTER,
  688. CR_REMOTE_COMM_FAILURE,
  689. CR_MACHINE_UNAVAILABLE,
  690. CR_FAILURE.
  691. --*/
  692. {
  693. CONFIGRET Status = CR_SUCCESS;
  694. WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
  695. ULONG ulLength = MAX_DEVICE_ID_LEN;
  696. PVOID hStringTable = NULL;
  697. BOOL Success;
  698. size_t DeviceIDLen = 0;
  699. try {
  700. //
  701. // validate parameters
  702. //
  703. if (dnDevInst == 0) {
  704. Status = CR_INVALID_DEVINST;
  705. goto Clean0;
  706. }
  707. if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
  708. Status = CR_INVALID_POINTER;
  709. goto Clean0;
  710. }
  711. if (INVALID_FLAGS(ulFlags, 0)) {
  712. Status = CR_INVALID_FLAG;
  713. goto Clean0;
  714. }
  715. //
  716. // initialize output parameters
  717. //
  718. *Buffer = L'\0';
  719. //
  720. // setup string table handle
  721. //
  722. if (!PnPGetGlobalHandles(hMachine, &hStringTable, NULL)) {
  723. Status = CR_FAILURE;
  724. goto Clean0;
  725. }
  726. //
  727. // retrieve the string form of the device id string
  728. //
  729. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulLength);
  730. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  731. Status = CR_INVALID_DEVNODE;
  732. goto Clean0;
  733. }
  734. if (FAILED(StringCchLength(
  735. pDeviceID,
  736. MAX_DEVICE_ID_LEN,
  737. &DeviceIDLen))) {
  738. Status = CR_FAILURE;
  739. goto Clean0;
  740. }
  741. //
  742. // copy as much of the the device id string as possible to the user
  743. // buffer. include the NULL term char, if there is room.
  744. //
  745. CopyMemory(Buffer, pDeviceID,
  746. min((DeviceIDLen+1)*sizeof(WCHAR),BufferLen*sizeof(WCHAR)));
  747. //
  748. // if the length of device id string (without NULL termination) is
  749. // longer than the supplied buffer, report CR_BUFFER_SMALL.
  750. // if the Buffer is large enough to hold the string, without
  751. // NULL-termination, we'll report success, per specification.
  752. //
  753. if (DeviceIDLen > BufferLen) {
  754. Status = CR_BUFFER_SMALL;
  755. }
  756. Clean0:
  757. NOTHING;
  758. } except(EXCEPTION_EXECUTE_HANDLER) {
  759. Status = CR_FAILURE;
  760. }
  761. return Status;
  762. } // CM_Get_Device_ID_ExW
  763. CONFIGRET
  764. CM_Enumerate_Enumerators_ExW(
  765. IN ULONG ulEnumIndex,
  766. OUT PWCHAR Buffer,
  767. IN OUT PULONG pulLength,
  768. IN ULONG ulFlags,
  769. IN HMACHINE hMachine
  770. )
  771. /*++
  772. Routine Description:
  773. This routine enumerates the enumerator subkeys under the Enum branch
  774. (e.g., Root, PCI, etc.). These names should not be used to access the
  775. registry directly, but may be used as input to the CM_Get_Device_ID_List
  776. routine. To enumerate enumerator subkey names, an application should
  777. initially call the CM_Enumerate_Enumerators function with the ulEnumIndex
  778. parameter set to zero. The application should then increment the
  779. ulEnumIndex parameter and call CM_Enumerate_Enumerators until there are
  780. no more subkeys (until the function returns CR_NO_SUCH_VALUE).
  781. Parameters:
  782. ulEnumIndex Supplies the index of the enumerator subkey name to retrieve.
  783. Buffer Supplies the address of the character buffer that receives
  784. the enumerator subkey name whose index is specified by
  785. ulEnumIndex.
  786. pulLength Supplies the address of the variable that contains the length,
  787. in characters, of the Buffer. Upon return, this variable
  788. will contain the number of characters (including terminating
  789. NULL) written to Buffer (if the supplied buffer is't large
  790. enough, then the routine will fail with CR_BUFFER_SMALL, and
  791. this value will indicate how large the buffer needs to be in
  792. order to succeed).
  793. ulFlags Must be zero.
  794. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  795. Return Value:
  796. If the function succeeds, the return value is CR_SUCCESS.
  797. If the function fails, the return value is one of the following:
  798. CR_INVALID_FLAG,
  799. CR_INVALID_POINTER,
  800. CR_BUFFER_SMALL,
  801. CR_NO_SUCH_VALUE,
  802. CR_REGISTRY_ERROR,
  803. CR_REMOTE_COMM_FAILURE,
  804. CR_MACHINE_UNAVAILABLE,
  805. CR_FAILURE.
  806. --*/
  807. {
  808. CONFIGRET Status = CR_SUCCESS;
  809. handle_t hBinding = NULL;
  810. try {
  811. //
  812. // validate input parameters
  813. //
  814. if ((!ARGUMENT_PRESENT(Buffer)) ||
  815. (!ARGUMENT_PRESENT(pulLength))) {
  816. Status = CR_INVALID_POINTER;
  817. goto Clean0;
  818. }
  819. if (INVALID_FLAGS(ulFlags, 0)) {
  820. Status = CR_INVALID_FLAG;
  821. goto Clean0;
  822. }
  823. //
  824. // initialize output parameters
  825. //
  826. *Buffer = L'\0';
  827. //
  828. // setup rpc binding handle
  829. //
  830. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  831. Status = CR_FAILURE;
  832. goto Clean0;
  833. }
  834. //
  835. // No special privileges are required by the server
  836. //
  837. RpcTryExcept {
  838. //
  839. // call rpc service entry point
  840. //
  841. Status = PNP_EnumerateSubKeys(
  842. hBinding, // rpc binding handle
  843. PNP_ENUMERATOR_SUBKEYS, // subkeys of enum branch
  844. ulEnumIndex, // index of enumerator to enumerate
  845. Buffer, // will contain enumerator name
  846. *pulLength, // max length of Buffer in chars
  847. pulLength, // chars copied (or chars required)
  848. ulFlags); // currently unused
  849. }
  850. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  851. KdPrintEx((DPFLTR_PNPMGR_ID,
  852. DBGF_ERRORS,
  853. "PNP_EnumerateSubKeys caused an exception (%d)\n",
  854. RpcExceptionCode()));
  855. Status = MapRpcExceptionToCR(RpcExceptionCode());
  856. }
  857. RpcEndExcept
  858. Clean0:
  859. NOTHING;
  860. } except(EXCEPTION_EXECUTE_HANDLER) {
  861. Status = CR_FAILURE;
  862. }
  863. return Status;
  864. } // CM_Enumerate_Enumerators_ExW
  865. CONFIGRET
  866. CM_Get_Device_ID_List_ExW(
  867. IN PCWSTR pszFilter, OPTIONAL
  868. OUT PWCHAR Buffer,
  869. IN ULONG BufferLen,
  870. IN ULONG ulFlags,
  871. IN HMACHINE hMachine
  872. )
  873. /*++
  874. Routine Description:
  875. This routine retrieve a list of all device IDs (device instance names)
  876. stored in the system.
  877. Parameters:
  878. pszFilter This string filters the list of device IDs returned. Its
  879. interpretation is dependent on the ulFlags specified. If
  880. CM_GETDEVID_FILTER_ENUMERATORS is specified, then this
  881. value can be either the name of an enumerator or the name
  882. of an enumerator plus the device id. If
  883. CM_GETDEVID_FILTER_SERVICE is specified, then this value
  884. is a service name.
  885. Buffer Supplies the address of the character buffer that receives
  886. the device ID list. Each device ID is null-terminated, with
  887. an extra NULL at the end.
  888. BufferLen Supplies the size, in characters, of the Buffer. This size
  889. may be ascertained by calling CM_Get_Device_ID_List_Size.
  890. ulFlags Must be either CM_GETDEVID_FILTER_ENUMERATOR or
  891. CM_GETDEVID_FILTER_SERVICE. The flags value controls how
  892. the pszFilter string is used.
  893. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  894. Return Value:
  895. If the function succeeds, the return value is CR_SUCCESS.
  896. If the function fails, the return value is one of the following:
  897. CR_INVALID_FLAG,
  898. CR_INVALID_POINTER,
  899. CR_BUFFER_SMALL,
  900. CR_REGISTRY_ERROR,
  901. CR_REMOTE_COMM_FAILURE,
  902. CR_MACHINE_UNAVAILABLE,
  903. CR_FAILURE.
  904. --*/
  905. {
  906. CONFIGRET Status = CR_SUCCESS;
  907. handle_t hBinding = NULL;
  908. try {
  909. //
  910. // validate input parameters
  911. //
  912. if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
  913. Status = CR_INVALID_POINTER;
  914. goto Clean0;
  915. }
  916. if (INVALID_FLAGS(ulFlags, CM_GETIDLIST_FILTER_BITS)) {
  917. Status = CR_INVALID_FLAG;
  918. goto Clean0;
  919. }
  920. //
  921. // initialize output parameters
  922. //
  923. *Buffer = L'\0';
  924. //
  925. // setup rpc binding handle
  926. //
  927. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  928. Status = CR_FAILURE;
  929. goto Clean0;
  930. }
  931. //
  932. // No special privileges are required by the server
  933. //
  934. RpcTryExcept {
  935. //
  936. // call rpc service entry point
  937. //
  938. Status = PNP_GetDeviceList(
  939. hBinding, // RPC Binding Handle
  940. pszFilter, // filter string, optional
  941. Buffer, // will contain device list
  942. &BufferLen, // in/out size of Buffer
  943. ulFlags); // filter flag
  944. }
  945. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  946. KdPrintEx((DPFLTR_PNPMGR_ID,
  947. DBGF_ERRORS,
  948. "PNP_GetDeviceList caused an exception (%d)\n",
  949. RpcExceptionCode()));
  950. Status = MapRpcExceptionToCR(RpcExceptionCode());
  951. }
  952. RpcEndExcept
  953. Clean0:
  954. NOTHING;
  955. } except(EXCEPTION_EXECUTE_HANDLER) {
  956. Status = CR_FAILURE;
  957. }
  958. return Status;
  959. } // CM_Get_Device_ID_List_ExW
  960. CONFIGRET
  961. CM_Get_Device_ID_List_Size_ExW(
  962. OUT PULONG pulLen,
  963. IN PCWSTR pszFilter, OPTIONAL
  964. IN ULONG ulFlags,
  965. IN HMACHINE hMachine
  966. )
  967. /*++
  968. Routine Description:
  969. This routine retrieves the size, in characters, of a list of device
  970. identifiers. It may be used to supply the buffer size necessary for a
  971. call to CM_Get_Device_ID_List.
  972. Parameters:
  973. pulLen Supplies the address of the variable that receives the
  974. size, in characters, required to store a list of all device
  975. identifiers (possibly limited to those existing under the
  976. pszEnumerator subkey described below). The size reflects
  977. a list of null-terminated device identifiers, with an extra
  978. null at the end. For efficiency, this number represents an
  979. upper bound on the size required, and the actual list size
  980. may be slightly smaller.
  981. pszFilter This string filters the list of device IDs returned. Its
  982. interpretation is dependent on the ulFlags specified. If
  983. CM_GETDEVID_FILTER_ENUMERATORS is specified, then this
  984. value can be either the name of an enumerator or the name
  985. of an enumerator plus the device id. If
  986. CM_GETDEVID_FILTER_SERVICE is specified, then this value
  987. is a service name.
  988. ulFlags Must be either CM_GETDEVID_FILTER_ENUMERATOR or
  989. CM_GETDEVID_FILTER_SERVICE. The flags value controls how
  990. the pszFilter string is used.
  991. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  992. Return Value:
  993. If the function succeeds, the return value is CR_SUCCESS.
  994. If the function fails, the return value is one of the following:
  995. CR_INVALID_FLAG,
  996. CR_INVALID_POINTER,
  997. CR_REGISTRY_ERROR,
  998. CR_REMOTE_COMM_FAILURE,
  999. CR_MACHINE_UNAVAILABLE,
  1000. CR_FAILURE.
  1001. --*/
  1002. {
  1003. CONFIGRET Status = CR_SUCCESS;
  1004. handle_t hBinding = NULL;
  1005. try {
  1006. //
  1007. // validate input parameters
  1008. //
  1009. if (!ARGUMENT_PRESENT(pulLen)) {
  1010. Status = CR_INVALID_POINTER;
  1011. goto Clean0;
  1012. }
  1013. if (INVALID_FLAGS(ulFlags, CM_GETIDLIST_FILTER_BITS)) {
  1014. Status = CR_INVALID_FLAG;
  1015. goto Clean0;
  1016. }
  1017. //
  1018. // initialize output parameters
  1019. //
  1020. *pulLen = 0;
  1021. //
  1022. // setup rpc binding handle
  1023. //
  1024. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  1025. Status = CR_FAILURE;
  1026. goto Clean0;
  1027. }
  1028. //
  1029. // No special privileges are required by the server
  1030. //
  1031. RpcTryExcept {
  1032. //
  1033. // call rpc service entry point
  1034. //
  1035. Status = PNP_GetDeviceListSize(
  1036. hBinding, // rpc binding handle
  1037. pszFilter, // Enumerator subkey, optional
  1038. pulLen, // length of device list in chars
  1039. ulFlags); // filter flag
  1040. }
  1041. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1042. KdPrintEx((DPFLTR_PNPMGR_ID,
  1043. DBGF_ERRORS,
  1044. "PNP_GetDeviceListSize caused an exception (%d)\n",
  1045. RpcExceptionCode()));
  1046. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1047. }
  1048. RpcEndExcept
  1049. Clean0:
  1050. NOTHING;
  1051. } except(EXCEPTION_EXECUTE_HANDLER) {
  1052. Status = CR_FAILURE;
  1053. }
  1054. return Status;
  1055. } // CM_Get_Device_ID_List_SizeW
  1056. CONFIGRET
  1057. CM_Get_Depth_Ex(
  1058. OUT PULONG pulDepth,
  1059. IN DEVINST dnDevInst,
  1060. IN ULONG ulFlags,
  1061. IN HMACHINE hMachine
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine retrieves the depth of a device instance in the
  1066. hardware tree.
  1067. Parameters:
  1068. pulDepth Supplies the address of the variable that receives the
  1069. depth of the device instance. This value is 0 to designate
  1070. the root of the tree, 1 to designate a child of the root,
  1071. and so on.
  1072. dnDevNode Supplies the handle of a device instance.
  1073. ulFlags Must be zero.
  1074. Return Value:
  1075. If the function succeeds, the return value is CR_SUCCESS.
  1076. If the function fails, the return value is one of the following:
  1077. CR_INVALID_DEVNODE,
  1078. CR_INVALID_FLAG, or
  1079. CR_INVALID_POINTER.
  1080. --*/
  1081. {
  1082. CONFIGRET Status = CR_SUCCESS;
  1083. WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
  1084. PVOID hStringTable = NULL;
  1085. handle_t hBinding = NULL;
  1086. ULONG ulLen = MAX_DEVICE_ID_LEN;
  1087. BOOL Success;
  1088. try {
  1089. //
  1090. // validate parameters
  1091. //
  1092. if (dnDevInst == 0) {
  1093. Status = CR_INVALID_DEVINST;
  1094. goto Clean0;
  1095. }
  1096. if (!ARGUMENT_PRESENT(pulDepth)) {
  1097. Status = CR_INVALID_POINTER;
  1098. goto Clean0;
  1099. }
  1100. if (INVALID_FLAGS(ulFlags, 0)) {
  1101. Status = CR_INVALID_FLAG;
  1102. goto Clean0;
  1103. }
  1104. //
  1105. // setup rpc binding handle and string table handle
  1106. //
  1107. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  1108. Status = CR_FAILURE;
  1109. goto Clean0;
  1110. }
  1111. //
  1112. // retrieve the device instance ID string associated with the devinst
  1113. //
  1114. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulLen);
  1115. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  1116. Status = CR_INVALID_DEVINST;
  1117. goto Clean0;
  1118. }
  1119. //
  1120. // No special privileges are required by the server
  1121. //
  1122. RpcTryExcept {
  1123. //
  1124. // call rpc service entry point
  1125. //
  1126. Status = PNP_GetDepth(
  1127. hBinding, // rpc binding handle
  1128. pDeviceID, // device instance
  1129. pulDepth, // returns the depth
  1130. ulFlags); // not used
  1131. }
  1132. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1133. KdPrintEx((DPFLTR_PNPMGR_ID,
  1134. DBGF_ERRORS,
  1135. "PNP_GetDepth caused an exception (%d)\n",
  1136. RpcExceptionCode()));
  1137. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1138. }
  1139. RpcEndExcept
  1140. Clean0:
  1141. NOTHING;
  1142. } except(EXCEPTION_EXECUTE_HANDLER) {
  1143. Status = CR_FAILURE;
  1144. }
  1145. return Status;
  1146. } // CM_Get_Depth
  1147. //-------------------------------------------------------------------
  1148. // Local Stubs
  1149. //-------------------------------------------------------------------
  1150. CONFIGRET
  1151. CM_Locate_DevNodeW(
  1152. OUT PDEVINST pdnDevInst,
  1153. IN DEVINSTID_W pDeviceID, OPTIONAL
  1154. IN ULONG ulFlags
  1155. )
  1156. {
  1157. return CM_Locate_DevNode_ExW(pdnDevInst, pDeviceID, ulFlags, NULL);
  1158. }
  1159. CONFIGRET
  1160. CM_Locate_DevNodeA(
  1161. OUT PDEVINST pdnDevInst,
  1162. IN DEVINSTID_A pDeviceID, OPTIONAL
  1163. IN ULONG ulFlags
  1164. )
  1165. {
  1166. return CM_Locate_DevNode_ExA(pdnDevInst, pDeviceID, ulFlags, NULL);
  1167. }
  1168. CONFIGRET
  1169. CM_Get_Parent(
  1170. OUT PDEVINST pdnDevInst,
  1171. IN DEVINST dnDevInst,
  1172. IN ULONG ulFlags
  1173. )
  1174. {
  1175. return CM_Get_Parent_Ex(pdnDevInst, dnDevInst, ulFlags, NULL);
  1176. }
  1177. CONFIGRET
  1178. CM_Get_Child(
  1179. OUT PDEVINST pdnDevInst,
  1180. IN DEVINST dnDevInst,
  1181. IN ULONG ulFlags
  1182. )
  1183. {
  1184. return CM_Get_Child_Ex(pdnDevInst, dnDevInst, ulFlags, NULL);
  1185. }
  1186. CONFIGRET
  1187. CM_Get_Sibling(
  1188. OUT PDEVINST pdnDevInst,
  1189. IN DEVINST dnDevInst,
  1190. IN ULONG ulFlags
  1191. )
  1192. {
  1193. return CM_Get_Sibling_Ex(pdnDevInst, dnDevInst, ulFlags, NULL);
  1194. }
  1195. CONFIGRET
  1196. CM_Get_Device_ID_Size(
  1197. OUT PULONG pulLen,
  1198. IN DEVINST dnDevInst,
  1199. IN ULONG ulFlags
  1200. )
  1201. {
  1202. return CM_Get_Device_ID_Size_Ex(pulLen, dnDevInst, ulFlags, NULL);
  1203. }
  1204. CONFIGRET
  1205. CM_Get_Device_IDW(
  1206. IN DEVINST dnDevInst,
  1207. OUT PWCHAR Buffer,
  1208. IN ULONG BufferLen,
  1209. IN ULONG ulFlags
  1210. )
  1211. {
  1212. return CM_Get_Device_ID_ExW(dnDevInst, Buffer, BufferLen, ulFlags, NULL);
  1213. }
  1214. CONFIGRET
  1215. CM_Get_Device_IDA(
  1216. IN DEVINST dnDevInst,
  1217. OUT PCHAR Buffer,
  1218. IN ULONG BufferLen,
  1219. IN ULONG ulFlags
  1220. )
  1221. {
  1222. return CM_Get_Device_ID_ExA(dnDevInst, Buffer, BufferLen, ulFlags, NULL);
  1223. }
  1224. CONFIGRET
  1225. CM_Enumerate_EnumeratorsW(
  1226. IN ULONG ulEnumIndex,
  1227. OUT PWCHAR Buffer,
  1228. IN OUT PULONG pulLength,
  1229. IN ULONG ulFlags
  1230. )
  1231. {
  1232. return CM_Enumerate_Enumerators_ExW(ulEnumIndex, Buffer, pulLength,
  1233. ulFlags, NULL);
  1234. }
  1235. CONFIGRET
  1236. CM_Enumerate_EnumeratorsA(
  1237. IN ULONG ulEnumIndex,
  1238. OUT PCHAR Buffer,
  1239. IN OUT PULONG pulLength,
  1240. IN ULONG ulFlags
  1241. )
  1242. {
  1243. return CM_Enumerate_Enumerators_ExA(ulEnumIndex, Buffer, pulLength,
  1244. ulFlags, NULL);
  1245. }
  1246. CONFIGRET
  1247. CM_Get_Device_ID_ListW(
  1248. IN PCWSTR pszFilter, OPTIONAL
  1249. OUT PWCHAR Buffer,
  1250. IN ULONG BufferLen,
  1251. IN ULONG ulFlags
  1252. )
  1253. {
  1254. return CM_Get_Device_ID_List_ExW(pszFilter, Buffer, BufferLen,
  1255. ulFlags, NULL);
  1256. }
  1257. CONFIGRET
  1258. CM_Get_Device_ID_ListA(
  1259. IN PCSTR pszFilter, OPTIONAL
  1260. OUT PCHAR Buffer,
  1261. IN ULONG BufferLen,
  1262. IN ULONG ulFlags
  1263. )
  1264. {
  1265. return CM_Get_Device_ID_List_ExA(pszFilter, Buffer, BufferLen,
  1266. ulFlags, NULL);
  1267. }
  1268. CONFIGRET
  1269. CM_Get_Device_ID_List_SizeW(
  1270. OUT PULONG pulLen,
  1271. IN PCWSTR pszFilter, OPTIONAL
  1272. IN ULONG ulFlags
  1273. )
  1274. {
  1275. return CM_Get_Device_ID_List_Size_ExW(pulLen, pszFilter, ulFlags, NULL);
  1276. }
  1277. CONFIGRET
  1278. CM_Get_Device_ID_List_SizeA(
  1279. OUT PULONG pulLen,
  1280. IN PCSTR pszFilter, OPTIONAL
  1281. IN ULONG ulFlags
  1282. )
  1283. {
  1284. return CM_Get_Device_ID_List_Size_ExA(pulLen, pszFilter, ulFlags, NULL);
  1285. }
  1286. CONFIGRET
  1287. CM_Get_Depth(
  1288. OUT PULONG pulDepth,
  1289. IN DEVINST dnDevInst,
  1290. IN ULONG ulFlags
  1291. )
  1292. {
  1293. return CM_Get_Depth_Ex(pulDepth, dnDevInst, ulFlags, NULL);
  1294. }
  1295. //-------------------------------------------------------------------
  1296. // ANSI STUBS
  1297. //-------------------------------------------------------------------
  1298. CONFIGRET
  1299. CM_Locate_DevNode_ExA(
  1300. OUT PDEVINST pdnDevInst,
  1301. IN DEVINSTID_A pDeviceID, OPTIONAL
  1302. IN ULONG ulFlags,
  1303. IN HMACHINE hMachine
  1304. )
  1305. {
  1306. CONFIGRET Status = CR_SUCCESS;
  1307. if (!ARGUMENT_PRESENT(pDeviceID)) {
  1308. //
  1309. // If the DEVINSTID parameter is NULL, then no conversion is necessary,
  1310. // just call the wide version
  1311. //
  1312. Status = CM_Locate_DevNode_ExW(pdnDevInst,
  1313. NULL,
  1314. ulFlags,
  1315. hMachine);
  1316. } else {
  1317. //
  1318. // if a device id string was passed in, convert to UNICODE before
  1319. // passing on to the wide version
  1320. //
  1321. PWSTR pUniDeviceID = NULL;
  1322. if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) == NO_ERROR) {
  1323. Status = CM_Locate_DevNode_ExW(pdnDevInst,
  1324. pUniDeviceID,
  1325. ulFlags,
  1326. hMachine);
  1327. pSetupFree(pUniDeviceID);
  1328. } else {
  1329. Status = CR_INVALID_DEVICE_ID;
  1330. }
  1331. }
  1332. return Status;
  1333. } // CM_Locate_DevNode_ExA
  1334. CONFIGRET
  1335. CM_Get_Device_ID_ExA(
  1336. IN DEVINST dnDevInst,
  1337. OUT PCHAR Buffer,
  1338. IN ULONG BufferLen,
  1339. IN ULONG ulFlags,
  1340. IN HMACHINE hMachine
  1341. )
  1342. {
  1343. CONFIGRET Status = CR_SUCCESS;
  1344. WCHAR UniBuffer[MAX_DEVICE_ID_LEN];
  1345. ULONG ulAnsiBufferLen;
  1346. size_t UniBufferLen = 0;
  1347. //
  1348. // validate essential parameters only
  1349. //
  1350. if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
  1351. return CR_INVALID_POINTER;
  1352. }
  1353. //
  1354. // call the wide version, passing a unicode buffer as a parameter
  1355. //
  1356. Status = CM_Get_Device_ID_ExW(dnDevInst,
  1357. UniBuffer,
  1358. MAX_DEVICE_ID_LEN,
  1359. ulFlags,
  1360. hMachine);
  1361. //
  1362. // We should never return a DeviceId longer than MAX_DEVICE_ID_LEN.
  1363. //
  1364. ASSERT(Status != CR_BUFFER_SMALL);
  1365. if (Status == CR_SUCCESS) {
  1366. //
  1367. // if the call succeeded, convert the device id to ansi before returning
  1368. //
  1369. if (FAILED(StringCchLength(
  1370. UniBuffer,
  1371. MAX_DEVICE_ID_LEN,
  1372. &UniBufferLen))) {
  1373. return CR_FAILURE;
  1374. }
  1375. ASSERT(UniBufferLen < MAX_DEVICE_ID_LEN);
  1376. ulAnsiBufferLen = BufferLen;
  1377. Status =
  1378. PnPUnicodeToMultiByte(
  1379. UniBuffer,
  1380. (DWORD)((UniBufferLen + 1)*sizeof(WCHAR)),
  1381. Buffer,
  1382. &ulAnsiBufferLen);
  1383. }
  1384. return Status;
  1385. } // CM_Get_Device_ID_ExA
  1386. CONFIGRET
  1387. CM_Enumerate_Enumerators_ExA(
  1388. IN ULONG ulEnumIndex,
  1389. OUT PCHAR Buffer,
  1390. IN OUT PULONG pulLength,
  1391. IN ULONG ulFlags,
  1392. IN HMACHINE hMachine
  1393. )
  1394. {
  1395. CONFIGRET Status = CR_SUCCESS;
  1396. WCHAR UniBuffer[MAX_DEVICE_ID_LEN];
  1397. ULONG UniLen = MAX_DEVICE_ID_LEN;
  1398. //
  1399. // validate parameters
  1400. //
  1401. if ((!ARGUMENT_PRESENT(Buffer)) ||
  1402. (!ARGUMENT_PRESENT(pulLength))) {
  1403. return CR_INVALID_POINTER;
  1404. }
  1405. //
  1406. // call the wide version, passing a unicode buffer as a parameter
  1407. //
  1408. Status = CM_Enumerate_Enumerators_ExW(ulEnumIndex,
  1409. UniBuffer,
  1410. &UniLen,
  1411. ulFlags,
  1412. hMachine);
  1413. ASSERT(Status != CR_BUFFER_SMALL);
  1414. if (Status == CR_SUCCESS) {
  1415. //
  1416. // convert the unicode buffer to an ansi string and copy to the caller's
  1417. // buffer
  1418. //
  1419. Status =
  1420. PnPUnicodeToMultiByte(
  1421. UniBuffer,
  1422. UniLen*sizeof(WCHAR),
  1423. Buffer,
  1424. pulLength);
  1425. }
  1426. return Status;
  1427. } // CM_Enumerate_Enumerators_ExA
  1428. CONFIGRET
  1429. CM_Get_Device_ID_List_ExA(
  1430. IN PCSTR pszFilter, OPTIONAL
  1431. OUT PCHAR Buffer,
  1432. IN ULONG BufferLen,
  1433. IN ULONG ulFlags,
  1434. IN HMACHINE hMachine
  1435. )
  1436. {
  1437. CONFIGRET Status = CR_SUCCESS;
  1438. PWSTR pUniBuffer, pUniFilter = NULL;
  1439. ULONG ulAnsiBufferLen;
  1440. //
  1441. // validate input parameters
  1442. //
  1443. if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
  1444. return CR_INVALID_POINTER;
  1445. }
  1446. if (ARGUMENT_PRESENT(pszFilter)) {
  1447. //
  1448. // if a filter string was passed in, convert to UNICODE before
  1449. // passing on to the wide version
  1450. //
  1451. if (pSetupCaptureAndConvertAnsiArg(pszFilter, &pUniFilter) != NO_ERROR) {
  1452. return CR_INVALID_DATA;
  1453. }
  1454. ASSERT(pUniFilter != NULL);
  1455. }
  1456. //
  1457. // prepare a larger buffer to hold the unicode formatted
  1458. // multi_sz data returned by CM_Get_Device_ID_List.
  1459. //
  1460. pUniBuffer = pSetupMalloc(BufferLen*sizeof(WCHAR));
  1461. if (pUniBuffer == NULL) {
  1462. Status = CR_OUT_OF_MEMORY;
  1463. goto Clean0;
  1464. }
  1465. *pUniBuffer = L'\0';
  1466. //
  1467. // call the wide version
  1468. //
  1469. Status = CM_Get_Device_ID_List_ExW(pUniFilter,
  1470. pUniBuffer,
  1471. BufferLen, // size in chars
  1472. ulFlags,
  1473. hMachine);
  1474. if (Status == CR_SUCCESS) {
  1475. //
  1476. // if the call succeeded, must convert the multi_sz list to ansi before
  1477. // returning
  1478. //
  1479. ulAnsiBufferLen = BufferLen;
  1480. Status =
  1481. PnPUnicodeToMultiByte(
  1482. pUniBuffer,
  1483. BufferLen*sizeof(WCHAR),
  1484. Buffer,
  1485. &ulAnsiBufferLen);
  1486. }
  1487. pSetupFree(pUniBuffer);
  1488. Clean0:
  1489. if (pUniFilter) {
  1490. pSetupFree(pUniFilter);
  1491. }
  1492. return Status;
  1493. } // CM_Get_Device_ID_List_ExA
  1494. CONFIGRET
  1495. CM_Get_Device_ID_List_Size_ExA(
  1496. OUT PULONG pulLen,
  1497. IN PCSTR pszFilter, OPTIONAL
  1498. IN ULONG ulFlags,
  1499. IN HMACHINE hMachine
  1500. )
  1501. {
  1502. CONFIGRET Status = CR_SUCCESS;
  1503. if (!ARGUMENT_PRESENT(pszFilter)) {
  1504. //
  1505. // If the filter parameter is NULL, then no conversion is necessary,
  1506. // just call the wide version
  1507. //
  1508. Status = CM_Get_Device_ID_List_Size_ExW(pulLen,
  1509. NULL,
  1510. ulFlags,
  1511. hMachine);
  1512. } else {
  1513. //
  1514. // if a filter string was passed in, convert to UNICODE before
  1515. // passing on to the wide version
  1516. //
  1517. PWSTR pUniFilter = NULL;
  1518. if (pSetupCaptureAndConvertAnsiArg(pszFilter, &pUniFilter) == NO_ERROR) {
  1519. Status = CM_Get_Device_ID_List_Size_ExW(pulLen,
  1520. pUniFilter,
  1521. ulFlags,
  1522. hMachine);
  1523. pSetupFree(pUniFilter);
  1524. } else {
  1525. Status = CR_INVALID_DATA;
  1526. }
  1527. }
  1528. return Status;
  1529. } // CM_Get_Device_ID_List_Size_ExA