Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1861 lines
49 KiB

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