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.

4907 lines
146 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. regprop.c
  5. Abstract:
  6. This module contains the API routines that reg and set registry
  7. properties and operates on classes.
  8. CM_Get_DevNode_Registry_Property
  9. CM_Set_DevNode_Registry_Property
  10. CM_Get_Class_Registry_Property
  11. CM_Set_Class_Registry_Property
  12. CM_Open_DevNode_Key
  13. CM_Delete_DevNode_Key
  14. CM_Open_Class_Key
  15. CM_Enumerate_Classes
  16. CM_Get_Class_Name
  17. CM_Get_Class_Key_Name
  18. CM_Delete_Class_Key
  19. CM_Get_Device_Interface_Alias
  20. CM_Get_Device_Interface_List
  21. CM_Get_Device_Interface_List_Size
  22. CM_Register_Device_Interface
  23. CM_Unregister_Device_Interface
  24. Author:
  25. Paula Tomlinson (paulat) 6-22-1995
  26. Environment:
  27. User mode only.
  28. Revision History:
  29. 22-Jun-1995 paulat
  30. Creation and initial implementation.
  31. --*/
  32. //
  33. // includes
  34. //
  35. #include "precomp.h"
  36. #include "cfgi.h"
  37. #include "setupapi.h"
  38. #include "spapip.h"
  39. #include "cmdat.h"
  40. //
  41. // Private prototypes
  42. //
  43. ULONG
  44. GetPropertyDataType(
  45. IN ULONG ulProperty
  46. );
  47. //
  48. // use these from SetupAPI
  49. //
  50. PSECURITY_DESCRIPTOR
  51. pSetupConvertTextToSD(
  52. IN PCWSTR SDS,
  53. OUT PULONG SecDescSize
  54. );
  55. PWSTR
  56. pSetupConvertSDToText(
  57. IN PSECURITY_DESCRIPTOR SD,
  58. OUT PULONG pSDSSize
  59. );
  60. //
  61. // global data
  62. //
  63. extern PVOID hLocalBindingHandle; // NOT MODIFIED BY THESE PROCEDURES
  64. CONFIGRET
  65. CM_Get_DevNode_Registry_Property_ExW(
  66. IN DEVINST dnDevInst,
  67. IN ULONG ulProperty,
  68. OUT PULONG pulRegDataType OPTIONAL,
  69. OUT PVOID Buffer OPTIONAL,
  70. IN OUT PULONG pulLength,
  71. IN ULONG ulFlags,
  72. IN HMACHINE hMachine
  73. )
  74. /*++
  75. Routine Description:
  76. This routine retrieves the specified value from the device instance's
  77. registry storage key.
  78. Parameters:
  79. dnDevInst Supplies the handle of the device instance for which a
  80. property is to be retrieved.
  81. ulProperty Supplies an ordinal specifying the property to be retrieved.
  82. (CM_DRP_*)
  83. pulRegDataType Optionally, supplies the address of a variable that
  84. will receive the registry data type for this property
  85. (i.e., the REG_* constants).
  86. Buffer Supplies the address of the buffer that receives the
  87. registry data. Can be NULL when simply retrieving data size.
  88. pulLength Supplies the address of the variable that contains the size,
  89. in bytes, of the buffer. The API replaces the initial size
  90. with the number of bytes of registry data copied to the buffer.
  91. If the variable is initially zero, the API replaces it with
  92. the buffer size needed to receive all the registry data. In
  93. this case, the Buffer parameter is ignored.
  94. ulFlags Must be zero.
  95. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  96. Return Value:
  97. If the function succeeds, the return value is CR_SUCCESS.
  98. If the function fails, the return value is one of the following:
  99. CR_INVALID_DEVINST,
  100. CR_NO_SUCH_REGISTRY_KEY,
  101. CR_INVALID_FLAG,
  102. CR_INVALID_POINTER,
  103. CR_NO_SUCH_VALUE,
  104. CR_REGISTRY_ERROR, or
  105. CR_BUFFER_SMALL.
  106. --*/
  107. {
  108. CONFIGRET Status = CR_SUCCESS;
  109. WCHAR pDeviceID[MAX_DEVICE_ID_LEN];
  110. ULONG ulSizeID = MAX_DEVICE_ID_LEN;
  111. ULONG ulTempDataType=0, ulTransferLen=0;
  112. ULONG ulGetProperty = ulProperty;
  113. BYTE NullBuffer=0;
  114. handle_t hBinding = NULL;
  115. PVOID hStringTable = NULL;
  116. BOOL Success;
  117. try {
  118. //
  119. // validate parameters
  120. //
  121. if (dnDevInst == 0) {
  122. Status = CR_INVALID_DEVINST;
  123. goto Clean0;
  124. }
  125. if (!ARGUMENT_PRESENT(pulLength)) {
  126. Status = CR_INVALID_POINTER;
  127. goto Clean0;
  128. }
  129. if ((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
  130. Status = CR_INVALID_POINTER;
  131. goto Clean0;
  132. }
  133. if (INVALID_FLAGS(ulFlags, 0)) {
  134. Status = CR_INVALID_FLAG;
  135. goto Clean0;
  136. }
  137. if (ulProperty < CM_DRP_MIN || ulProperty > CM_DRP_MAX) {
  138. Status = CR_INVALID_PROPERTY;
  139. goto Clean0;
  140. }
  141. if (ulProperty == CM_DRP_SECURITY_SDS) {
  142. //
  143. // translates operation
  144. //
  145. LPVOID tmpBuffer = NULL;
  146. ULONG tmpBufferSize = 0;
  147. ULONG datatype;
  148. LPWSTR sds = NULL;
  149. ulTempDataType = REG_SZ;
  150. try {
  151. Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
  152. CM_DRP_SECURITY,
  153. &datatype,
  154. NULL,
  155. &tmpBufferSize,
  156. ulFlags,
  157. hMachine);
  158. if (Status != CR_SUCCESS && Status != CR_BUFFER_SMALL) {
  159. leave;
  160. }
  161. tmpBuffer = pSetupMalloc(tmpBufferSize);
  162. if (tmpBuffer == NULL) {
  163. Status = CR_OUT_OF_MEMORY;
  164. leave;
  165. }
  166. Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
  167. CM_DRP_SECURITY,
  168. &datatype,
  169. tmpBuffer,
  170. &tmpBufferSize,
  171. ulFlags,
  172. hMachine);
  173. if (Status != CR_SUCCESS) {
  174. leave;
  175. }
  176. //
  177. // now translate
  178. //
  179. sds = pSetupConvertSDToText((PSECURITY_DESCRIPTOR)tmpBuffer,NULL);
  180. if (sds == NULL) {
  181. Status = CR_FAILURE;
  182. leave;
  183. }
  184. ulTransferLen = (lstrlen(sds)+1) * sizeof(WCHAR); // required size
  185. if (*pulLength == 0 || Buffer == NULL || *pulLength < ulTransferLen) {
  186. //
  187. // buffer too small, or buffer size wanted
  188. // required buffer size
  189. //
  190. Status = CR_BUFFER_SMALL;
  191. *pulLength = ulTransferLen;
  192. ulTransferLen = 0;
  193. } else {
  194. //
  195. // copy data
  196. //
  197. memcpy(Buffer,sds,ulTransferLen);
  198. *pulLength = ulTransferLen;
  199. }
  200. } except(EXCEPTION_EXECUTE_HANDLER) {
  201. Status = CR_FAILURE;
  202. }
  203. if (tmpBuffer != NULL) {
  204. pSetupFree(tmpBuffer);
  205. }
  206. if (sds != NULL) {
  207. //
  208. // must use LocalFree
  209. //
  210. LocalFree(sds);
  211. }
  212. if (Status != CR_SUCCESS) {
  213. goto Clean0;
  214. }
  215. } else {
  216. //
  217. // setup rpc binding handle and string table handle
  218. //
  219. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  220. Status = CR_FAILURE;
  221. goto Clean0;
  222. }
  223. //
  224. // retrieve the string form of the device id string
  225. //
  226. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulSizeID);
  227. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  228. Status = CR_INVALID_DEVINST;
  229. goto Clean0;
  230. }
  231. //
  232. // NOTE: The ulTransferLen variable is just used to control
  233. // how much data is marshalled via rpc between address spaces.
  234. // ulTransferLen should be set on entry to the size of the Buffer.
  235. // The last parameter should also be the size of the Buffer on entry
  236. // and on exit contains either the amount transferred (if a transfer
  237. // occured) or the amount required, this value should be passed back
  238. // in the callers pulLength parameter.
  239. //
  240. ulTransferLen = *pulLength;
  241. if (Buffer == NULL) {
  242. Buffer = &NullBuffer;
  243. }
  244. RpcTryExcept {
  245. //
  246. // call rpc service entry point
  247. //
  248. Status = PNP_GetDeviceRegProp(
  249. hBinding, // rpc binding handle
  250. pDeviceID, // string representation of device instance
  251. ulGetProperty, // id for the property
  252. &ulTempDataType, // receives registry data type
  253. Buffer, // receives registry data
  254. &ulTransferLen, // input/output buffer size
  255. pulLength, // bytes copied (or bytes required)
  256. ulFlags); // not used
  257. }
  258. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  259. KdPrintEx((DPFLTR_PNPMGR_ID,
  260. DBGF_ERRORS,
  261. "PNP_GetDeviceRegProp caused an exception (%d)\n",
  262. RpcExceptionCode()));
  263. Status = MapRpcExceptionToCR(RpcExceptionCode());
  264. }
  265. RpcEndExcept
  266. }
  267. if (pulRegDataType != NULL) {
  268. //
  269. // I pass a temp variable to the rpc stubs since they require the
  270. // output param to always be valid, then if user did pass in a valid
  271. // pointer to receive the info, do the assignment now
  272. //
  273. *pulRegDataType = ulTempDataType;
  274. }
  275. Clean0:
  276. NOTHING;
  277. } except(EXCEPTION_EXECUTE_HANDLER) {
  278. Status = CR_FAILURE;
  279. }
  280. return Status;
  281. } // CM_Get_DevNode_Registry_Property_ExW
  282. CONFIGRET
  283. CM_Set_DevNode_Registry_Property_ExW(
  284. IN DEVINST dnDevInst,
  285. IN ULONG ulProperty,
  286. IN PCVOID Buffer OPTIONAL,
  287. IN OUT ULONG ulLength,
  288. IN ULONG ulFlags,
  289. IN HMACHINE hMachine
  290. )
  291. /*++
  292. Routine Description:
  293. This routine sets the specified value in the device instance's registry
  294. storage key.
  295. Parameters:
  296. dnDevInst Supplies the handle of the device instance for which a
  297. property is to be retrieved.
  298. ulProperty Supplies an ordinal specifying the property to be set.
  299. (CM_DRP_*)
  300. Buffer Supplies the address of the buffer that contains the
  301. registry data. This data must be of the proper type
  302. for that property.
  303. ulLength Supplies the number of bytes of registry data to write.
  304. ulFlags Must be zero.
  305. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  306. Return Value:
  307. If the function succeeds, the return value is CR_SUCCESS.
  308. If the function fails, the return value is one of the following:
  309. CR_INVALID_DEVNODE,
  310. CR_NO_SUCH_REGISTRY_KEY,
  311. CR_INVALID_FLAG,
  312. CR_INVALID_POINTER,
  313. CR_NO_SUCH_VALUE,
  314. CR_REGISTRY_ERROR,
  315. CR_OUT_OF_MEMORY,
  316. CR_INVALID_DATA, or
  317. CR_BUFFER_SMALL.
  318. --*/
  319. {
  320. CONFIGRET Status = CR_SUCCESS;
  321. WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
  322. ULONG ulRegDataType = 0, ulLen = MAX_DEVICE_ID_LEN;
  323. BYTE NullBuffer = 0x0;
  324. handle_t hBinding = NULL;
  325. PVOID hStringTable = NULL;
  326. BOOL Success;
  327. PVOID Buffer2 = NULL;
  328. PVOID Buffer3 = NULL;
  329. try {
  330. //
  331. // validate parameters
  332. //
  333. if (dnDevInst == 0) {
  334. Status = CR_INVALID_DEVINST;
  335. goto Clean0;
  336. }
  337. if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
  338. Status = CR_INVALID_POINTER;
  339. goto Clean0;
  340. }
  341. if (INVALID_FLAGS(ulFlags, 0)) {
  342. Status = CR_INVALID_FLAG;
  343. goto Clean0;
  344. }
  345. if (ulProperty < CM_DRP_MIN || ulProperty > CM_DRP_MAX) {
  346. Status = CR_INVALID_PROPERTY;
  347. goto Clean0;
  348. }
  349. //
  350. // setup rpc binding handle and string table handle
  351. //
  352. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  353. Status = CR_FAILURE;
  354. goto Clean0;
  355. }
  356. //
  357. // retrieve the string form of the device id string
  358. //
  359. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulLen);
  360. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  361. Status = CR_INVALID_DEVNODE;
  362. goto Clean0;
  363. }
  364. //
  365. // we need to specify what registry data to use for storing this data
  366. //
  367. ulRegDataType = GetPropertyDataType(ulProperty);
  368. //
  369. // if data type is REG_DWORD, make sure size is right
  370. //
  371. if((ulRegDataType == REG_DWORD) && ulLength && (ulLength != sizeof(DWORD))) {
  372. Status = CR_INVALID_DATA;
  373. goto Clean0;
  374. }
  375. //
  376. // if the register is CM_DRP_SECURITY_SDS, convert it
  377. //
  378. if (ulProperty == CM_DRP_SECURITY_SDS) {
  379. if (ulLength) {
  380. //
  381. // this form of CM_DRP_SECURITY provides a string that needs to be converted to binary
  382. //
  383. PCWSTR UnicodeSecDesc = (PCWSTR)Buffer;
  384. Buffer2 = pSetupConvertTextToSD(UnicodeSecDesc,&ulLength);
  385. if (Buffer2 == NULL) {
  386. //
  387. // If last error is ERROR_SCE_DISABLED, then the failure is
  388. // due to SCE APIs being "turned off" on Embedded. Treat
  389. // this as a (successful) no-op...
  390. //
  391. if(GetLastError() == ERROR_SCE_DISABLED) {
  392. Status = CR_SUCCESS;
  393. } else {
  394. Status = CR_INVALID_DATA;
  395. }
  396. goto Clean0;
  397. }
  398. Buffer = Buffer2;
  399. }
  400. ulProperty = CM_DRP_SECURITY;
  401. ulRegDataType = REG_BINARY;
  402. }
  403. //
  404. // if data type is REG_MULTI_SZ, make sure it is double-NULL terminated
  405. //
  406. if ((ulRegDataType == REG_MULTI_SZ) && (ulLength != 0)) {
  407. ULONG ulNewLength;
  408. PWSTR tmpBuffer, bufferEnd;
  409. ulLength &= ~(ULONG)1;
  410. tmpBuffer = (PWSTR)Buffer;
  411. bufferEnd = (PWSTR)((PUCHAR)tmpBuffer + ulLength);
  412. ulNewLength = ulLength;
  413. while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
  414. while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
  415. tmpBuffer++;
  416. }
  417. if (tmpBuffer >= bufferEnd) {
  418. ulNewLength += sizeof(TEXT('\0'));;
  419. } else {
  420. tmpBuffer++;
  421. }
  422. }
  423. if (tmpBuffer >= bufferEnd) {
  424. ulNewLength += sizeof(TEXT('\0'));;
  425. } else {
  426. ulNewLength = ((ULONG)(tmpBuffer - (PWSTR)Buffer) + 1) * sizeof(WCHAR);
  427. }
  428. if (ulNewLength > ulLength) {
  429. Buffer3 = pSetupMalloc(ulNewLength);
  430. if (Buffer3 == NULL) {
  431. Status = CR_OUT_OF_MEMORY;
  432. goto Clean0;
  433. }
  434. memcpy(Buffer3, Buffer, ulLength);
  435. memset((PUCHAR)Buffer3 + ulLength, 0, ulNewLength - ulLength);
  436. Buffer = Buffer3;
  437. }
  438. ulLength = ulNewLength;
  439. }
  440. if (Buffer == NULL) {
  441. Buffer = &NullBuffer;
  442. }
  443. RpcTryExcept {
  444. //
  445. // call rpc service entry point
  446. //
  447. Status = PNP_SetDeviceRegProp(
  448. hBinding, // rpc binding handle
  449. pDeviceID, // string representation of devinst
  450. ulProperty, // string name for property
  451. ulRegDataType, // specify registry data type
  452. (LPBYTE)Buffer, // receives registry data
  453. ulLength, // amount to return in Buffer
  454. ulFlags); // not used
  455. }
  456. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  457. KdPrintEx((DPFLTR_PNPMGR_ID,
  458. DBGF_ERRORS,
  459. "PNP_SetDeviceRegProp caused an exception (%d)\n",
  460. RpcExceptionCode()));
  461. Status = MapRpcExceptionToCR(RpcExceptionCode());
  462. }
  463. RpcEndExcept
  464. Clean0:
  465. NOTHING;
  466. } except(EXCEPTION_EXECUTE_HANDLER) {
  467. Status = CR_FAILURE;
  468. }
  469. if (Buffer3) {
  470. pSetupFree(Buffer3);
  471. }
  472. if (Buffer2) {
  473. //
  474. // SceSvc requires LocalFree
  475. //
  476. LocalFree(Buffer2);
  477. }
  478. return Status;
  479. } // CM_Set_DevNode_Registry_Property_ExW
  480. CONFIGRET
  481. CM_Get_Class_Registry_PropertyW(
  482. IN LPGUID ClassGUID,
  483. IN ULONG ulProperty,
  484. OUT PULONG pulRegDataType OPTIONAL,
  485. OUT PVOID Buffer OPTIONAL,
  486. IN OUT PULONG pulLength,
  487. IN ULONG ulFlags,
  488. IN HMACHINE hMachine
  489. )
  490. /*++
  491. Routine Description:
  492. This routine retrieves the specified value from the classes's
  493. registry storage key.
  494. Parameters:
  495. ClassGUID Supplies the Class GUID.
  496. ulProperty Supplies an ordinal specifying the property to be retrieved.
  497. (CM_DRP_*)
  498. pulRegDataType Optionally, supplies the address of a variable that
  499. will receive the registry data type for this property
  500. (i.e., the REG_* constants).
  501. Buffer Supplies the address of the buffer that receives the
  502. registry data. Can be NULL when simply retrieving data size.
  503. pulLength Supplies the address of the variable that contains the size,
  504. in bytes, of the buffer. The API replaces the initial size
  505. with the number of bytes of registry data copied to the buffer.
  506. If the variable is initially zero, the API replaces it with
  507. the buffer size needed to receive all the registry data. In
  508. this case, the Buffer parameter is ignored.
  509. ulFlags Must be zero.
  510. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  511. Return Value:
  512. If the function succeeds, the return value is CR_SUCCESS.
  513. If the function fails, the return value is one of the following:
  514. CR_INVALID_DEVINST,
  515. CR_NO_SUCH_REGISTRY_KEY,
  516. CR_INVALID_FLAG,
  517. CR_INVALID_POINTER,
  518. CR_NO_SUCH_VALUE,
  519. CR_REGISTRY_ERROR, or
  520. CR_BUFFER_SMALL.
  521. --*/
  522. {
  523. CONFIGRET Status = CR_SUCCESS;
  524. ULONG ulTempDataType=0, ulTransferLen=0;
  525. BYTE NullBuffer=0;
  526. handle_t hBinding = NULL;
  527. BOOL Success;
  528. WCHAR szStringGuid[MAX_GUID_STRING_LEN];
  529. ULONG ulGetProperty = ulProperty;
  530. try {
  531. //
  532. // validate parameters
  533. //
  534. if (!ARGUMENT_PRESENT(ClassGUID)) {
  535. Status = CR_INVALID_POINTER;
  536. goto Clean0;
  537. }
  538. if (!ARGUMENT_PRESENT(pulLength)) {
  539. Status = CR_INVALID_POINTER;
  540. goto Clean0;
  541. }
  542. if ((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
  543. Status = CR_INVALID_POINTER;
  544. goto Clean0;
  545. }
  546. if (INVALID_FLAGS(ulFlags, 0)) {
  547. Status = CR_INVALID_FLAG;
  548. goto Clean0;
  549. }
  550. //
  551. // convert from guid to string
  552. //
  553. if (pSetupStringFromGuid(ClassGUID, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
  554. Status = CR_INVALID_DATA;
  555. goto Clean0;
  556. }
  557. if (ulProperty < CM_CRP_MIN || ulProperty > CM_CRP_MAX) {
  558. Status = CR_INVALID_PROPERTY;
  559. goto Clean0;
  560. }
  561. if (ulProperty == CM_CRP_SECURITY_SDS) {
  562. //
  563. // translates operation
  564. //
  565. LPVOID tmpBuffer = NULL;
  566. ULONG tmpBufferSize = 0;
  567. ULONG datatype;
  568. LPWSTR sds = NULL;
  569. ulTempDataType = REG_SZ;
  570. try {
  571. Status = CM_Get_Class_Registry_PropertyW(ClassGUID,CM_CRP_SECURITY,&datatype,NULL,&tmpBufferSize,ulFlags,hMachine);
  572. if (Status != CR_SUCCESS && Status != CR_BUFFER_SMALL) {
  573. leave;
  574. }
  575. tmpBuffer = pSetupMalloc(tmpBufferSize);
  576. if (tmpBuffer == NULL) {
  577. Status = CR_OUT_OF_MEMORY;
  578. leave;
  579. }
  580. Status = CM_Get_Class_Registry_PropertyW(ClassGUID,CM_CRP_SECURITY,&datatype,tmpBuffer,&tmpBufferSize,ulFlags,hMachine);
  581. if (Status != CR_SUCCESS) {
  582. leave;
  583. }
  584. //
  585. // now translate
  586. //
  587. sds = pSetupConvertSDToText((PSECURITY_DESCRIPTOR)tmpBuffer,NULL);
  588. if (sds == NULL) {
  589. Status = CR_FAILURE;
  590. leave;
  591. }
  592. ulTransferLen = (lstrlen(sds)+1) * sizeof(WCHAR); // required size
  593. if (*pulLength == 0 || Buffer == NULL || *pulLength < ulTransferLen) {
  594. //
  595. // buffer too small, or buffer size wanted
  596. // required buffer size
  597. //
  598. Status = CR_BUFFER_SMALL;
  599. *pulLength = ulTransferLen;
  600. ulTransferLen = 0;
  601. } else {
  602. //
  603. // copy data
  604. //
  605. memcpy(Buffer,sds,ulTransferLen);
  606. *pulLength = ulTransferLen;
  607. }
  608. } except(EXCEPTION_EXECUTE_HANDLER) {
  609. Status = CR_FAILURE;
  610. }
  611. if (tmpBuffer != NULL) {
  612. pSetupFree(tmpBuffer);
  613. }
  614. if (sds != NULL) {
  615. //
  616. // must use LocalFree
  617. //
  618. LocalFree(sds);
  619. }
  620. if (Status != CR_SUCCESS) {
  621. goto Clean0;
  622. }
  623. } else {
  624. //
  625. // setup rpc binding handle and string table handle
  626. //
  627. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  628. Status = CR_FAILURE;
  629. goto Clean0;
  630. }
  631. //
  632. // NOTE: The ulTransferLen variable is just used to control
  633. // how much data is marshalled via rpc between address spaces.
  634. // ulTransferLen should be set on entry to the size of the Buffer.
  635. // The last parameter should also be the size of the Buffer on entry
  636. // and on exit contains either the amount transferred (if a transfer
  637. // occured) or the amount required, this value should be passed back
  638. // in the callers pulLength parameter.
  639. //
  640. ulTransferLen = *pulLength;
  641. if (Buffer == NULL) {
  642. Buffer = &NullBuffer;
  643. }
  644. RpcTryExcept {
  645. //
  646. // call rpc service entry point
  647. //
  648. Status = PNP_GetClassRegProp(
  649. hBinding, // rpc binding handle
  650. szStringGuid, // string representation of class
  651. ulGetProperty, // id for the property
  652. &ulTempDataType, // receives registry data type
  653. Buffer, // receives registry data
  654. &ulTransferLen, // input/output buffer size
  655. pulLength, // bytes copied (or bytes required)
  656. ulFlags); // not used
  657. }
  658. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  659. KdPrintEx((DPFLTR_PNPMGR_ID,
  660. DBGF_ERRORS,
  661. "PNP_GetClassRegProp caused an exception (%d)\n",
  662. RpcExceptionCode()));
  663. Status = MapRpcExceptionToCR(RpcExceptionCode());
  664. }
  665. RpcEndExcept
  666. }
  667. if (pulRegDataType != NULL) {
  668. //
  669. // I pass a temp variable to the rpc stubs since they require the
  670. // output param to always be valid, then if user did pass in a valid
  671. // pointer to receive the info, do the assignment now
  672. //
  673. *pulRegDataType = ulTempDataType;
  674. }
  675. Clean0:
  676. NOTHING;
  677. } except(EXCEPTION_EXECUTE_HANDLER) {
  678. Status = CR_FAILURE;
  679. }
  680. return Status;
  681. } // CM_Get_Class_Registry_PropertyW
  682. CONFIGRET
  683. CM_Set_Class_Registry_PropertyW(
  684. IN LPGUID ClassGUID,
  685. IN ULONG ulProperty,
  686. IN PCVOID Buffer OPTIONAL,
  687. IN ULONG ulLength,
  688. IN ULONG ulFlags,
  689. IN HMACHINE hMachine
  690. )
  691. /*++
  692. Routine Description:
  693. This routine sets the specified value in the device instance's registry
  694. storage key.
  695. Parameters:
  696. ClassGUID Supplies the Class GUID.
  697. ulProperty Supplies an ordinal specifying the property to be set.
  698. (CM_DRP_*)
  699. Buffer Supplies the address of the buffer that contains the
  700. registry data. This data must be of the proper type
  701. for that property.
  702. ulLength Supplies the number of bytes of registry data to write.
  703. ulFlags Must be zero.
  704. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  705. Return Value:
  706. If the function succeeds, the return value is CR_SUCCESS.
  707. If the function fails, the return value is one of the following:
  708. CR_INVALID_DEVNODE,
  709. CR_NO_SUCH_REGISTRY_KEY,
  710. CR_INVALID_FLAG,
  711. CR_INVALID_POINTER,
  712. CR_NO_SUCH_VALUE,
  713. CR_REGISTRY_ERROR,
  714. CR_OUT_OF_MEMORY,
  715. CR_INVALID_DATA, or
  716. CR_BUFFER_SMALL.
  717. --*/
  718. {
  719. CONFIGRET Status = CR_SUCCESS;
  720. ULONG ulRegDataType = 0, ulLen = MAX_DEVICE_ID_LEN;
  721. BYTE NullBuffer = 0x0;
  722. handle_t hBinding = NULL;
  723. BOOL Success;
  724. WCHAR szStringGuid[MAX_GUID_STRING_LEN];
  725. PVOID Buffer2 = NULL;
  726. PVOID Buffer3 = NULL;
  727. try {
  728. //
  729. // validate parameters
  730. //
  731. if (!ARGUMENT_PRESENT(ClassGUID)) {
  732. Status = CR_INVALID_POINTER;
  733. goto Clean0;
  734. }
  735. if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
  736. Status = CR_INVALID_POINTER;
  737. goto Clean0;
  738. }
  739. if (INVALID_FLAGS(ulFlags, 0)) {
  740. Status = CR_INVALID_FLAG;
  741. goto Clean0;
  742. }
  743. //
  744. // convert from guid to string
  745. //
  746. if (pSetupStringFromGuid(ClassGUID, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
  747. Status = CR_INVALID_DATA;
  748. goto Clean0;
  749. }
  750. if (ulProperty < CM_CRP_MIN || ulProperty > CM_CRP_MAX) {
  751. Status = CR_INVALID_PROPERTY;
  752. goto Clean0;
  753. }
  754. //
  755. // setup rpc binding handle and string table handle
  756. //
  757. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  758. Status = CR_FAILURE;
  759. goto Clean0;
  760. }
  761. //
  762. // we need to specify what registry data to use for storing this data
  763. //
  764. ulRegDataType = GetPropertyDataType(ulProperty);
  765. //
  766. // if data type is REG_DWORD, make sure size is right
  767. //
  768. if((ulRegDataType == REG_DWORD) && ulLength && (ulLength != sizeof(DWORD))) {
  769. Status = CR_INVALID_DATA;
  770. goto Clean0;
  771. }
  772. //
  773. // if the register is CM_CRP_SECURITY_SDS, convert it
  774. //
  775. if (ulProperty == CM_CRP_SECURITY_SDS) {
  776. if (ulLength) {
  777. //
  778. // this form of CM_CRP_SECURITY provides a string that needs to be converted to binary
  779. //
  780. PCWSTR UnicodeSecDesc = (PCWSTR)Buffer;
  781. Buffer2 = pSetupConvertTextToSD(UnicodeSecDesc,&ulLength);
  782. if (Buffer2 == NULL) {
  783. //
  784. // If last error is ERROR_SCE_DISABLED, then the failure is
  785. // due to SCE APIs being "turned off" on Embedded. Treat
  786. // this as a (successful) no-op...
  787. //
  788. if(GetLastError() == ERROR_SCE_DISABLED) {
  789. Status = CR_SUCCESS;
  790. } else {
  791. Status = CR_INVALID_DATA;
  792. }
  793. goto Clean0;
  794. }
  795. Buffer = Buffer2;
  796. }
  797. ulProperty = CM_CRP_SECURITY;
  798. ulRegDataType = REG_BINARY;
  799. }
  800. //
  801. // if data type is REG_MULTI_SZ, make sure it is double-NULL terminated
  802. //
  803. if ((ulRegDataType == REG_MULTI_SZ) && (ulLength != 0)) {
  804. ULONG ulNewLength;
  805. PWSTR tmpBuffer, bufferEnd;
  806. ulLength &= ~(ULONG)1;
  807. tmpBuffer = (PWSTR)Buffer;
  808. bufferEnd = (PWSTR)((PUCHAR)tmpBuffer + ulLength);
  809. ulNewLength = ulLength;
  810. while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
  811. while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
  812. tmpBuffer++;
  813. }
  814. if (tmpBuffer >= bufferEnd) {
  815. ulNewLength += sizeof(TEXT('\0'));;
  816. } else {
  817. tmpBuffer++;
  818. }
  819. }
  820. if (tmpBuffer >= bufferEnd) {
  821. ulNewLength += sizeof(TEXT('\0'));;
  822. } else {
  823. ulNewLength = ((ULONG)(tmpBuffer - (PWSTR)Buffer) + 1) * sizeof(WCHAR);
  824. }
  825. if (ulNewLength > ulLength) {
  826. Buffer3 = pSetupMalloc(ulNewLength);
  827. if (Buffer3 == NULL) {
  828. Status = CR_OUT_OF_MEMORY;
  829. goto Clean0;
  830. }
  831. memcpy(Buffer3, Buffer, ulLength);
  832. memset((PUCHAR)Buffer3 + ulLength, 0, ulNewLength - ulLength);
  833. Buffer = Buffer3;
  834. }
  835. ulLength = ulNewLength;
  836. }
  837. if (Buffer == NULL) {
  838. Buffer = &NullBuffer;
  839. }
  840. RpcTryExcept {
  841. //
  842. // call rpc service entry point
  843. //
  844. Status = PNP_SetClassRegProp(
  845. hBinding, // rpc binding handle
  846. szStringGuid, // string representation of class
  847. ulProperty, // string name for property
  848. ulRegDataType, // specify registry data type
  849. (LPBYTE)Buffer, // receives registry data
  850. ulLength, // amount to return in Buffer
  851. ulFlags); // not used
  852. }
  853. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  854. KdPrintEx((DPFLTR_PNPMGR_ID,
  855. DBGF_ERRORS,
  856. "PNP_SetClassRegProp caused an exception (%d)\n",
  857. RpcExceptionCode()));
  858. Status = MapRpcExceptionToCR(RpcExceptionCode());
  859. }
  860. RpcEndExcept
  861. Clean0:
  862. NOTHING;
  863. } except(EXCEPTION_EXECUTE_HANDLER) {
  864. Status = CR_FAILURE;
  865. }
  866. if (Buffer2) {
  867. //
  868. // SceSvc requires LocalFree
  869. //
  870. LocalFree(Buffer2);
  871. }
  872. if (Buffer3) {
  873. pSetupFree(Buffer3);
  874. }
  875. return Status;
  876. } // CM_Set_Class_Registry_Property_ExW
  877. CONFIGRET
  878. CM_Open_DevNode_Key_Ex(
  879. IN DEVINST dnDevNode,
  880. IN REGSAM samDesired,
  881. IN ULONG ulHardwareProfile,
  882. IN REGDISPOSITION Disposition,
  883. OUT PHKEY phkDevice,
  884. IN ULONG ulFlags,
  885. IN HMACHINE hMachine
  886. )
  887. /*++
  888. Routine Description:
  889. This routine opens the software storage registry key associated with a
  890. device instance.
  891. Parameters:
  892. dnDevNode Handle of a device instance. This handle is typically
  893. retrieved by a call to CM_Locate_DevNode or
  894. CM_Create_DevNode.
  895. samDesired Specifies an access mask that describes the desired
  896. security access for the key. This parameter can be
  897. a combination of the values used in calls to RegOpenKeyEx.
  898. ulHardwareProfile Supplies the handle of the hardware profile to open the
  899. storage key under. This parameter is only used if the
  900. CM_REGISTRY_CONFIG flag is specified in ulFlags. If
  901. this parameter is 0, the API uses the current hardware
  902. profile.
  903. Disposition Specifies how the registry key is to be opened. May be
  904. one of the following values:
  905. RegDisposition_OpenAlways - Open the key if it exists,
  906. otherwise, create the key.
  907. RegDisposition_OpenExisting - Open the key only if it
  908. exists, otherwise fail with CR_NO_SUCH_REGISTRY_VALUE.
  909. phkDevice Supplies the address of the variable that receives an
  910. opened handle to the specified key. When access to this
  911. key is completed, it must be closed via RegCloseKey.
  912. ulFlags Specifies what type of storage key should be opened.
  913. Can be a combination of these values:
  914. CM_REGISTRY_HARDWARE (0x00000000)
  915. Open a key for storing driver-independent information
  916. relating to the device instance. On Windows NT, the
  917. full path to such a storage key is of the form:
  918. HKLM\System\CurrentControlSet\Enum\<enumerator>\
  919. <DeviceID>\<InstanceID>\Device Parameters
  920. CM_REGISTRY_SOFTWARE (0x00000001)
  921. Open a key for storing driver-specific information
  922. relating to the device instance. On Windows NT, the
  923. full path to such a storage key is of the form:
  924. HKLM\System\CurrentControlSet\Control\Class\
  925. <DevNodeClass>\<ClassInstanceOrdinal>
  926. CM_REGISTRY_USER (0x00000100)
  927. Open a key under HKEY_CURRENT_USER instead of
  928. HKEY_LOCAL_MACHINE. This flag may not be used with
  929. CM_REGISTRY_CONFIG. There is no analagous kernel-mode
  930. API on NT to get a per-user device configuration
  931. storage, since this concept does not apply to device
  932. drivers (no user may be logged on, etc). However,
  933. this flag is provided for consistency with Win95, and
  934. because it is foreseeable that it could be useful to
  935. Win32 services that interact with Plug-and-Play model.
  936. CM_REGISTRY_CONFIG (0x00000200)
  937. Open the key under a hardware profile branch instead
  938. of HKEY_LOCAL_MACHINE. If this flag is specified,
  939. then ulHardwareProfile supplies the handle of the
  940. hardware profile to be used. This flag may not be
  941. used with CM_REGISTRY_USER.
  942. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  943. Return Value:
  944. If the function succeeds, the return value is CR_SUCCESS.
  945. If the function fails, the return value is one of the following:
  946. CR_INVALID_DEVICE_ID,
  947. CR_INVALID_FLAG,
  948. CR_INVALID_POINTER, or
  949. CR_REGISTRY_ERROR
  950. --*/
  951. {
  952. CONFIGRET Status = CR_SUCCESS;
  953. LONG RegStatus = ERROR_SUCCESS;
  954. PWSTR pszMachineName = NULL;
  955. WCHAR pDeviceID[MAX_DEVICE_ID_LEN];
  956. HKEY hKey=NULL, hRemoteKey=NULL, hBranchKey=NULL;
  957. PWSTR pszKey = NULL, pszPrivateKey = NULL;
  958. PVOID hStringTable = NULL;
  959. handle_t hBinding = NULL;
  960. ULONG ulLen = MAX_DEVICE_ID_LEN;
  961. BOOL Success;
  962. try {
  963. //
  964. // validate parameters
  965. //
  966. if (!ARGUMENT_PRESENT(phkDevice)) {
  967. Status = CR_INVALID_POINTER;
  968. goto Clean0;
  969. }
  970. *phkDevice = NULL;
  971. if (dnDevNode == 0) {
  972. Status = CR_INVALID_DEVINST;
  973. goto Clean0;
  974. }
  975. if (INVALID_FLAGS(ulFlags, CM_REGISTRY_BITS)) {
  976. Status = CR_INVALID_FLAG;
  977. goto Clean0;
  978. }
  979. if (INVALID_FLAGS(Disposition, RegDisposition_Bits)) {
  980. Status = CR_INVALID_DATA;
  981. goto Clean0;
  982. }
  983. if ((ulFlags & CM_REGISTRY_CONFIG) &&
  984. (ulHardwareProfile > MAX_CONFIG_VALUE)) {
  985. Status = CR_INVALID_DATA;
  986. goto Clean0;
  987. }
  988. //
  989. // setup rpc binding handle and string table handle
  990. //
  991. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  992. Status = CR_FAILURE;
  993. goto Clean0;
  994. }
  995. if ((hBinding != hLocalBindingHandle) && (ulFlags & CM_REGISTRY_USER)) {
  996. Status = CR_ACCESS_DENIED; // current user key can't be remoted
  997. goto Clean0;
  998. }
  999. //
  1000. // retrieve the device id string and validate it
  1001. //
  1002. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevNode,pDeviceID,&ulLen);
  1003. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  1004. Status = CR_INVALID_DEVNODE;
  1005. goto Clean0;
  1006. }
  1007. //-------------------------------------------------------------
  1008. // determine the branch key to use; either HKLM or HKCU
  1009. //-------------------------------------------------------------
  1010. if (hBinding == hLocalBindingHandle) {
  1011. if (ulFlags & CM_REGISTRY_USER) {
  1012. hBranchKey = HKEY_CURRENT_USER;
  1013. }
  1014. else {
  1015. //
  1016. // all other cases go to HKLM (validate permission first?)
  1017. //
  1018. hBranchKey = HKEY_LOCAL_MACHINE;
  1019. }
  1020. }
  1021. else {
  1022. //
  1023. // retrieve machine name
  1024. //
  1025. pszMachineName = pSetupMalloc((MAX_PATH + 3)*sizeof(WCHAR));
  1026. if (pszMachineName == NULL) {
  1027. Status = CR_OUT_OF_MEMORY;
  1028. goto Clean0;
  1029. }
  1030. PnPRetrieveMachineName(hMachine, pszMachineName);
  1031. //
  1032. // use remote HKLM branch (we only support connect to
  1033. // HKEY_LOCAL_MACHINE on the remote machine, not HKEY_CURRENT_USER)
  1034. //
  1035. RegStatus = RegConnectRegistry(pszMachineName, HKEY_LOCAL_MACHINE,
  1036. &hRemoteKey);
  1037. pSetupFree(pszMachineName);
  1038. pszMachineName = NULL;
  1039. if (RegStatus != ERROR_SUCCESS) {
  1040. Status = CR_REGISTRY_ERROR;
  1041. goto Clean0;
  1042. }
  1043. //
  1044. // hBranchKey is either a predefined key or assigned to by
  1045. // another key, I never attempt to close it. If hRemoteKey is
  1046. // non-NULL I will attempt to close it during cleanup since
  1047. // it is explicitly opened.
  1048. //
  1049. hBranchKey = hRemoteKey;
  1050. }
  1051. //
  1052. // allocate some buffer space to work with
  1053. //
  1054. pszKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
  1055. if (pszKey == NULL) {
  1056. Status = CR_OUT_OF_MEMORY;
  1057. goto Clean0;
  1058. }
  1059. pszPrivateKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
  1060. if (pszPrivateKey == NULL) {
  1061. Status = CR_OUT_OF_MEMORY;
  1062. goto Clean0;
  1063. }
  1064. //
  1065. // form the registry path based on the device id and the flags.
  1066. //
  1067. Status = GetDevNodeKeyPath(hBinding, pDeviceID, ulFlags,
  1068. ulHardwareProfile, pszKey, pszPrivateKey);
  1069. if (Status != CR_SUCCESS) {
  1070. goto Clean0;
  1071. }
  1072. lstrcat(pszKey, TEXT("\\"));
  1073. lstrcat(pszKey, pszPrivateKey);
  1074. pSetupFree(pszPrivateKey);
  1075. pszPrivateKey = NULL;
  1076. //
  1077. // open the registry key (method of open is based on flags)
  1078. //
  1079. if (Disposition == RegDisposition_OpenAlways) {
  1080. //-----------------------------------------------------
  1081. // open the registry key always
  1082. //-----------------------------------------------------
  1083. //
  1084. // Only the main Enum subtree under HKLM has strict security
  1085. // that requires me to first create the key on the server
  1086. // side and then open it here on the client side. This
  1087. // condition currently only occurs if the flags have
  1088. // CM_REGISTRY_HARDWARE set but no other flags set.
  1089. //
  1090. if (ulFlags == CM_REGISTRY_HARDWARE) {
  1091. //
  1092. // first try to open it (in case it already exists). If it
  1093. // doesn't exist, then I'll have to have the protected server
  1094. // side create the key. I still need to open it from here, the
  1095. // client-side, so that the registry handle will be in the
  1096. // caller's address space.
  1097. //
  1098. RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1099. pszKey,
  1100. 0,
  1101. samDesired,
  1102. phkDevice);
  1103. if (RegStatus != ERROR_SUCCESS) {
  1104. //
  1105. // call server side to create the key
  1106. //
  1107. RpcTryExcept {
  1108. //
  1109. // call rpc service entry point
  1110. //
  1111. Status = PNP_CreateKey(
  1112. hBinding,
  1113. pDeviceID,
  1114. samDesired,
  1115. 0);
  1116. }
  1117. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1118. KdPrintEx((DPFLTR_PNPMGR_ID,
  1119. DBGF_ERRORS,
  1120. "PNP_CreateKey caused an exception (%d)\n",
  1121. RpcExceptionCode()));
  1122. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1123. }
  1124. RpcEndExcept
  1125. if (Status != CR_SUCCESS) {
  1126. *phkDevice = NULL;
  1127. goto Clean0;
  1128. }
  1129. //
  1130. // the key was created successfully, so open it now
  1131. //
  1132. RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1133. pszKey,
  1134. 0,
  1135. samDesired,
  1136. phkDevice);
  1137. if (RegStatus == ERROR_ACCESS_DENIED) {
  1138. *phkDevice = NULL;
  1139. Status = CR_ACCESS_DENIED;
  1140. goto Clean0;
  1141. }
  1142. else if (RegStatus != ERROR_SUCCESS) {
  1143. //
  1144. // if we still can't open the key, I give up
  1145. //
  1146. *phkDevice = NULL;
  1147. Status = CR_REGISTRY_ERROR;
  1148. goto Clean0;
  1149. }
  1150. }
  1151. }
  1152. else {
  1153. //
  1154. // these keys have admin-full privilege so try to open
  1155. // from the client-side and just let the security of the
  1156. // key judge whether the caller can access it.
  1157. //
  1158. RegStatus = RegCreateKeyEx(hBranchKey,
  1159. pszKey,
  1160. 0,
  1161. NULL,
  1162. REG_OPTION_NON_VOLATILE,
  1163. samDesired,
  1164. NULL,
  1165. phkDevice,
  1166. NULL);
  1167. if (RegStatus == ERROR_ACCESS_DENIED) {
  1168. *phkDevice = NULL;
  1169. Status = CR_ACCESS_DENIED;
  1170. goto Clean0;
  1171. }
  1172. else if (RegStatus != ERROR_SUCCESS) {
  1173. *phkDevice = NULL;
  1174. Status = CR_REGISTRY_ERROR;
  1175. goto Clean0;
  1176. }
  1177. }
  1178. }
  1179. else {
  1180. //-----------------------------------------------------
  1181. // open only if it already exists
  1182. //-----------------------------------------------------
  1183. //
  1184. // the actual open always occurs on the client side so I can
  1185. // pass back a handle that's valid for the calling process.
  1186. // Only creates need to happen on the server side
  1187. //
  1188. RegStatus = RegOpenKeyEx(hBranchKey,
  1189. pszKey,
  1190. 0,
  1191. samDesired,
  1192. phkDevice);
  1193. if (RegStatus == ERROR_ACCESS_DENIED) {
  1194. *phkDevice = NULL;
  1195. Status = CR_ACCESS_DENIED;
  1196. goto Clean0;
  1197. }
  1198. else if (RegStatus != ERROR_SUCCESS) {
  1199. *phkDevice = NULL;
  1200. Status = CR_NO_SUCH_REGISTRY_KEY;
  1201. }
  1202. }
  1203. Clean0:
  1204. NOTHING;
  1205. } except(EXCEPTION_EXECUTE_HANDLER) {
  1206. Status = CR_FAILURE;
  1207. //
  1208. // Reference the following variables so the compiler will respect
  1209. // statement ordering w.r.t. their assignment.
  1210. //
  1211. pszMachineName = pszMachineName;
  1212. pszPrivateKey = pszPrivateKey;
  1213. pszKey = pszKey;
  1214. }
  1215. if (pszMachineName) {
  1216. pSetupFree(pszMachineName);
  1217. }
  1218. if (pszPrivateKey) {
  1219. pSetupFree(pszPrivateKey);
  1220. }
  1221. if (pszKey) {
  1222. pSetupFree(pszKey);
  1223. }
  1224. if (hKey != NULL) {
  1225. RegCloseKey(hKey);
  1226. }
  1227. if (hRemoteKey != NULL) {
  1228. RegCloseKey(hRemoteKey);
  1229. }
  1230. return Status;
  1231. } // CM_Open_DevNode_Key_ExW
  1232. CONFIGRET
  1233. CM_Delete_DevNode_Key_Ex(
  1234. IN DEVNODE dnDevNode,
  1235. IN ULONG ulHardwareProfile,
  1236. IN ULONG ulFlags,
  1237. IN HANDLE hMachine
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. This routine deletes a registry storage key associated with a device
  1242. instance.
  1243. dnDevNode Handle of a device instance. This handle is typically
  1244. retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
  1245. ulHardwareProfile Supplies the handle of the hardware profile to delete
  1246. the storage key under. This parameter is only used if the
  1247. CM_REGISTRY_CONFIG flag is specified in ulFlags. If this
  1248. parameter is 0, the API uses the current hardware profile.
  1249. If this parameter is 0xFFFFFFFF, then the specified storage
  1250. key(s) for all hardware profiles is (are) deleted.
  1251. ulFlags Specifies what type(s) of storage key(s) should be deleted.
  1252. Can be a combination of these values:
  1253. CM_REGISTRY_HARDWARE - Delete the key for storing driver-
  1254. independent information relating to the device instance.
  1255. This may be combined with CM_REGISTRY_SOFTWARE to delete
  1256. both device and driver keys simultaneously.
  1257. CM_REGISTRY_SOFTWARE - Delete the key for storing driver-
  1258. specific information relating to the device instance.
  1259. This may be combined with CM_REGISTRY_HARDWARE to
  1260. delete both driver and device keys simultaneously.
  1261. CM_REGISTRY_USER - Delete the specified key(s) under
  1262. HKEY_CURRENT_USER instead of HKEY_LOCAL_MACHINE.
  1263. This flag may not be used with CM_REGISTRY_CONFIG.
  1264. CM_REGISTRY_CONFIG - Delete the specified keys(s) under a
  1265. hardware profile branch instead of HKEY_LOCAL_MACHINE.
  1266. If this flag is specified, then ulHardwareProfile
  1267. supplies the handle to the hardware profile to be used.
  1268. This flag may not be used with CM_REGISTRY_USER.
  1269. Return Value:
  1270. If the function succeeds, the return value is CR_SUCCESS.
  1271. If the function fails, the return value is one of the following:
  1272. CR_INVALID_DEVNODE,
  1273. CR_INVALID_FLAG,
  1274. CR_REGISTRY_ERROR
  1275. --*/
  1276. {
  1277. CONFIGRET Status = CR_SUCCESS;
  1278. LONG RegStatus = ERROR_SUCCESS;
  1279. PVOID hStringTable = NULL;
  1280. handle_t hBinding = NULL;
  1281. HKEY hKey = NULL;
  1282. PWSTR pszParentKey = NULL, pszChildKey = NULL, pszRegStr = NULL;
  1283. WCHAR pDeviceID[MAX_DEVICE_ID_LEN], szProfile[MAX_PROFILE_ID_LEN];
  1284. ULONG ulIndex = 0, ulSize = 0,ulLen = MAX_DEVICE_ID_LEN;
  1285. BOOL Success;
  1286. try {
  1287. //
  1288. // validate parameters
  1289. //
  1290. if (dnDevNode == 0) {
  1291. Status = CR_INVALID_DEVINST;
  1292. goto Clean0;
  1293. }
  1294. if (INVALID_FLAGS(ulFlags, CM_REGISTRY_BITS)) {
  1295. Status = CR_INVALID_FLAG;
  1296. goto Clean0;
  1297. }
  1298. if ((ulFlags & CM_REGISTRY_USER) && (ulFlags & CM_REGISTRY_CONFIG)) {
  1299. Status = CR_INVALID_FLAG; // can't specify both
  1300. goto Clean0;
  1301. }
  1302. //
  1303. // setup string table handle
  1304. //
  1305. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  1306. Status = CR_FAILURE;
  1307. goto Clean0;
  1308. }
  1309. //
  1310. // retrieve the device id string and validate it
  1311. //
  1312. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevNode,pDeviceID,&ulLen);
  1313. if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
  1314. Status = CR_INVALID_DEVNODE;
  1315. goto Clean0;
  1316. }
  1317. //
  1318. // allocate some buffer space to work with
  1319. //
  1320. pszParentKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
  1321. if (pszParentKey == NULL) {
  1322. Status = CR_OUT_OF_MEMORY;
  1323. goto Clean0;
  1324. }
  1325. pszChildKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
  1326. if (pszChildKey == NULL) {
  1327. Status = CR_OUT_OF_MEMORY;
  1328. goto Clean0;
  1329. }
  1330. pszRegStr = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
  1331. if (pszRegStr == NULL) {
  1332. Status = CR_OUT_OF_MEMORY;
  1333. goto Clean0;
  1334. }
  1335. //
  1336. // form the registry path based on the device id and the flags.
  1337. //
  1338. Status = GetDevNodeKeyPath(hBinding, pDeviceID, ulFlags,
  1339. ulHardwareProfile, pszParentKey, pszChildKey);
  1340. if (Status != CR_SUCCESS) {
  1341. goto Clean0;
  1342. }
  1343. //------------------------------------------------------------------
  1344. // For either hw and sw user keys, the client side is privileged
  1345. // enough to do the delete (if the caller doesn't have admin, it
  1346. // will be denied but that is the desired behaviour). Also, the
  1347. // service-side cannot access the HKEY_CURRENT_USER key unless it
  1348. // does some sort of impersonation.
  1349. //------------------------------------------------------------------
  1350. if (ulFlags & CM_REGISTRY_USER) {
  1351. //
  1352. // handle the special config-specific case when the profile
  1353. // specified is -1, then need to delete the private key
  1354. // for all profiles
  1355. //
  1356. if ((ulFlags & CM_REGISTRY_CONFIG) &&
  1357. (ulHardwareProfile == 0xFFFFFFFF)) {
  1358. wsprintf(pszRegStr, TEXT("%s\\%s"),
  1359. pszRegPathIDConfigDB,
  1360. pszRegKeyKnownDockingStates);
  1361. RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1362. pszRegStr,
  1363. 0,
  1364. KEY_ALL_ACCESS,
  1365. &hKey);
  1366. //
  1367. // enumerate the hardware profile keys
  1368. //
  1369. for (ulIndex = 0; RegStatus == ERROR_SUCCESS; ulIndex++) {
  1370. ulSize = MAX_PROFILE_ID_LEN * sizeof(WCHAR);
  1371. RegStatus = RegEnumKeyEx(hKey, ulIndex, szProfile, &ulSize,
  1372. NULL, NULL, NULL, NULL);
  1373. if (RegStatus == ERROR_SUCCESS) {
  1374. //
  1375. // pszParentKey contains replacement symbol for the
  1376. // profile id
  1377. //
  1378. wsprintf(pszRegStr, pszParentKey, szProfile);
  1379. Status = DeletePrivateKey(HKEY_CURRENT_USER,
  1380. pszRegStr,
  1381. pszChildKey);
  1382. if (Status != CR_SUCCESS) {
  1383. goto Clean0;
  1384. }
  1385. }
  1386. }
  1387. }
  1388. else {
  1389. //
  1390. // not for all profiles, so just delete the specified key
  1391. //
  1392. Status = DeletePrivateKey(HKEY_CURRENT_USER,
  1393. pszParentKey,
  1394. pszChildKey);
  1395. if (Status != CR_SUCCESS) {
  1396. goto Clean0;
  1397. }
  1398. }
  1399. }
  1400. //------------------------------------------------------------------
  1401. // For the remaining cases (no user keys), do the work on the
  1402. // server side, sense that side has the code to make the key
  1403. // volatile if necessary instead of deleting. Also, access to
  1404. // some of these registry keys requires system privilege.
  1405. //------------------------------------------------------------------
  1406. else {
  1407. if (!(ulFlags & CM_REGISTRY_CONFIG)) {
  1408. ulHardwareProfile = 0;
  1409. }
  1410. RpcTryExcept {
  1411. //
  1412. // call rpc service entry point
  1413. //
  1414. Status = PNP_DeleteRegistryKey(
  1415. hBinding, // rpc binding handle
  1416. pDeviceID, // device id
  1417. pszParentKey, // parent of key to delete
  1418. pszChildKey, // key to delete
  1419. ulHardwareProfile); // flags, not used
  1420. }
  1421. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1422. KdPrintEx((DPFLTR_PNPMGR_ID,
  1423. DBGF_ERRORS,
  1424. "PNP_DeleteRegistryKey caused an exception (%d)\n",
  1425. RpcExceptionCode()));
  1426. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1427. }
  1428. RpcEndExcept
  1429. }
  1430. Clean0:
  1431. NOTHING;
  1432. } except(EXCEPTION_EXECUTE_HANDLER) {
  1433. Status = CR_FAILURE;
  1434. //
  1435. // Reference the following variables so the compiler will respect
  1436. // statement ordering w.r.t. their assignment.
  1437. //
  1438. pszRegStr = pszRegStr;
  1439. pszChildKey = pszChildKey;
  1440. pszParentKey = pszParentKey;
  1441. }
  1442. if (hKey != NULL) {
  1443. RegCloseKey(hKey);
  1444. }
  1445. if (pszRegStr) {
  1446. pSetupFree(pszRegStr);
  1447. }
  1448. if (pszChildKey) {
  1449. pSetupFree(pszChildKey);
  1450. }
  1451. if (pszParentKey) {
  1452. pSetupFree(pszParentKey);
  1453. }
  1454. return Status;
  1455. } // CM_Delete_DevNode_Key_Ex
  1456. CONFIGRET
  1457. CM_Open_Class_Key_ExW(
  1458. IN LPGUID ClassGuid OPTIONAL,
  1459. IN LPCWSTR pszClassName OPTIONAL,
  1460. IN REGSAM samDesired,
  1461. IN REGDISPOSITION Disposition,
  1462. OUT PHKEY phkClass,
  1463. IN ULONG ulFlags,
  1464. IN HMACHINE hMachine
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. This routine opens the class registry key, and optionally, a specific
  1469. class's subkey.
  1470. Parameters:
  1471. ClassGuid Optionally, supplies the address of a class GUID representing
  1472. the class subkey to be opened.
  1473. pszClassName Specifies the string form of the class name for the class
  1474. represented by ClassGuid. This parameter is only valid if
  1475. the CM_OPEN_CLASS_KEY_INSTALLER flag is set in the ulFlags
  1476. parameter. If specified, this string will replace any existing
  1477. class name associated with this setup class GUID.
  1478. This parameter must be set to NULL if the
  1479. CM_OPEN_CLASS_KEY_INTERFACE bit is set in the ulFlags parameter.
  1480. samDesired Specifies an access mask that describes the desired security
  1481. access for the new key. This parameter can be a combination
  1482. of the values used in calls to RegOpenKeyEx.
  1483. Disposition Specifies how the registry key is to be opened. May be one
  1484. of the following values:
  1485. RegDisposition_OpenAlways - Open the key if it exists,
  1486. otherwise, create the key.
  1487. RegDisposition_OpenExisting - Open the key f it exists,
  1488. otherwise, fail with CR_NO_SUCH_REGISTRY_KEY.
  1489. phkClass Supplies the address of the variable that receives an opened
  1490. handle to the specified key. When access to this key is
  1491. completed, it must be closed via RegCloseKey.
  1492. ulFlags May be one of the following values:
  1493. CM_OPEN_CLASS_KEY_INSTALLER - open/create a setup class key for
  1494. the specified GUID under
  1495. HKLM\System\CurrentControlSet\Control\Class.
  1496. CM_OPEN_CLASS_KEY_INTERFACE - open/create a device interface
  1497. class key for the specified GUID under
  1498. HKLM\System\CurrentControlSet\Control\DeviceClasses.
  1499. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  1500. Return Value:
  1501. If the function succeeds, the return value is CR_SUCCESS.
  1502. If the function fails, the return value is one of the following:
  1503. CR_INVALID_FLAG,
  1504. CR_INVALID_POINTER, or
  1505. CR_REGISTRY_ERROR
  1506. --*/
  1507. {
  1508. CONFIGRET Status = CR_SUCCESS;
  1509. LONG RegStatus = ERROR_SUCCESS;
  1510. HKEY hRootKey = NULL, hRemoteKey = NULL;
  1511. PWSTR pszMachineName = NULL, pszRegStr = NULL;
  1512. PVOID hStringTable = NULL;
  1513. try {
  1514. //
  1515. // validate input parameters
  1516. //
  1517. if (!ARGUMENT_PRESENT(phkClass)) {
  1518. Status = CR_INVALID_POINTER;
  1519. goto Clean0;
  1520. }
  1521. *phkClass = NULL;
  1522. if (INVALID_FLAGS(Disposition, RegDisposition_Bits)) {
  1523. Status = CR_INVALID_DATA;
  1524. goto Clean0;
  1525. }
  1526. if (INVALID_FLAGS(ulFlags, CM_OPEN_CLASS_KEY_BITS)) {
  1527. Status = CR_INVALID_FLAG;
  1528. goto Clean0;
  1529. }
  1530. //
  1531. // If ulFlags == CM_OPEN_CLASS_KEY_INTERFACE then pszClassName had
  1532. // better be NULL.
  1533. //
  1534. if((ulFlags == CM_OPEN_CLASS_KEY_INTERFACE) && pszClassName) {
  1535. Status = CR_INVALID_DATA;
  1536. goto Clean0;
  1537. }
  1538. //
  1539. // get reg key for HKEY_LOCAL_MACHINE
  1540. //
  1541. if (hMachine == NULL) {
  1542. //
  1543. // local call
  1544. //
  1545. hRootKey = HKEY_LOCAL_MACHINE;
  1546. }
  1547. else {
  1548. //
  1549. // setup string table handle and retreive machine name
  1550. //
  1551. if (!PnPGetGlobalHandles(hMachine, &hStringTable, NULL)) {
  1552. Status = CR_FAILURE;
  1553. goto Clean0;
  1554. }
  1555. pszMachineName = pSetupMalloc((MAX_PATH + 3)*sizeof(WCHAR));
  1556. if (pszMachineName == NULL) {
  1557. Status = CR_OUT_OF_MEMORY;
  1558. goto Clean0;
  1559. }
  1560. PnPRetrieveMachineName(hMachine, pszMachineName);
  1561. //
  1562. // connect to HKEY_LOCAL_MACHINE on remote machine
  1563. //
  1564. RegStatus = RegConnectRegistry(pszMachineName, HKEY_LOCAL_MACHINE,
  1565. &hRemoteKey);
  1566. pSetupFree(pszMachineName);
  1567. pszMachineName = NULL;
  1568. if (RegStatus != ERROR_SUCCESS) {
  1569. Status = CR_REGISTRY_ERROR;
  1570. goto Clean0;
  1571. }
  1572. hRootKey = hRemoteKey;
  1573. }
  1574. //
  1575. // allocate some buffer space to work with
  1576. //
  1577. pszRegStr = pSetupMalloc(MAX_PATH*sizeof(WCHAR));
  1578. if (pszRegStr == NULL) {
  1579. Status = CR_OUT_OF_MEMORY;
  1580. goto Clean0;
  1581. }
  1582. //
  1583. // Form the registry path
  1584. //
  1585. if (ulFlags == CM_OPEN_CLASS_KEY_INTERFACE) {
  1586. lstrcpy(pszRegStr, pszRegPathDeviceClass);
  1587. } else {
  1588. lstrcpy(pszRegStr, pszRegPathClass);
  1589. }
  1590. if (ClassGuid != NULL) { // optional class guid was specified
  1591. WCHAR szStringGuid[MAX_GUID_STRING_LEN];
  1592. if (pSetupStringFromGuid(ClassGuid, szStringGuid,MAX_GUID_STRING_LEN) == NO_ERROR) {
  1593. lstrcat(pszRegStr, TEXT("\\"));
  1594. lstrcat(pszRegStr, szStringGuid);
  1595. }
  1596. }
  1597. //
  1598. // attempt to open/create that key
  1599. //
  1600. if (Disposition == RegDisposition_OpenAlways) {
  1601. ULONG ulDisposition;
  1602. RegStatus = RegCreateKeyEx(hRootKey, pszRegStr, 0, NULL,
  1603. REG_OPTION_NON_VOLATILE, samDesired,
  1604. NULL, phkClass, &ulDisposition);
  1605. } else {
  1606. RegStatus = RegOpenKeyEx(hRootKey, pszRegStr, 0, samDesired,
  1607. phkClass);
  1608. }
  1609. if((pszClassName != NULL) && (RegStatus == ERROR_SUCCESS)) {
  1610. RegSetValueEx(*phkClass, pszRegValueClass, 0, REG_SZ,
  1611. (LPBYTE)pszClassName,
  1612. (lstrlen(pszClassName) + 1) * sizeof(WCHAR));
  1613. }
  1614. if (RegStatus != ERROR_SUCCESS) {
  1615. *phkClass = NULL;
  1616. Status = CR_NO_SUCH_REGISTRY_KEY;
  1617. goto Clean0;
  1618. }
  1619. Clean0:
  1620. NOTHING;
  1621. } except(EXCEPTION_EXECUTE_HANDLER) {
  1622. Status = CR_FAILURE;
  1623. //
  1624. // Reference the following variables so the compiler will respect
  1625. // statement ordering w.r.t. their assignment.
  1626. //
  1627. pszMachineName = pszMachineName;
  1628. pszRegStr = pszRegStr;
  1629. }
  1630. if (pszMachineName != NULL) {
  1631. pSetupFree(pszMachineName);
  1632. }
  1633. if (pszRegStr != NULL) {
  1634. pSetupFree(pszRegStr);
  1635. }
  1636. if (hRemoteKey != NULL) {
  1637. RegCloseKey(hRemoteKey);
  1638. }
  1639. return Status;
  1640. } // CM_Open_Class_Key_ExW
  1641. CONFIGRET
  1642. CM_Enumerate_Classes_Ex(
  1643. IN ULONG ulClassIndex,
  1644. OUT LPGUID ClassGuid,
  1645. IN ULONG ulFlags,
  1646. IN HMACHINE hMachine
  1647. )
  1648. /*++
  1649. Routine Description:
  1650. This routine enumerates the installed classes in the system. It
  1651. retrieves the GUID string for a single class each time it is called.
  1652. To enumerate installed classes, an application should initially call the
  1653. CM_Enumerate_Classes function with the ulClassIndex parameter set to
  1654. zero. The application should then increment the ulClassIndex parameter
  1655. and call CM_Enumerate_Classes until there are no more classes (until the
  1656. function returns CR_NO_SUCH_VALUE).
  1657. It is possible to receive a CR_INVALID_DATA error while enumerating
  1658. installed classes. This may happen if the registry key represented by
  1659. the specified index is determined to be an invalid class key. Such keys
  1660. should be ignored during enumeration.
  1661. Parameters:
  1662. ulClassIndex Supplies the index of the class to retrieve the class
  1663. GUID string for.
  1664. ClassGuid Supplies the address of a variable that receives the GUID
  1665. for the class whose index is specified by ulClassIndex.
  1666. ulFlags Must be zero.
  1667. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  1668. Return Value:
  1669. If the function succeeds, the return value is CR_SUCCESS.
  1670. If the function fails, the return value is one of the following:
  1671. CR_INVALID_FLAG,
  1672. CR_INVALID_POINTER,
  1673. CR_NO_SUCH_VALUE,
  1674. CR_REGISTRY_ERROR,
  1675. CR_REMOTE_COMM_FAILURE,
  1676. CR_MACHINE_UNAVAILABLE,
  1677. CR_FAILURE.
  1678. --*/
  1679. {
  1680. CONFIGRET Status = CR_SUCCESS;
  1681. WCHAR szClassGuid[MAX_GUID_STRING_LEN];
  1682. ULONG ulLength = MAX_GUID_STRING_LEN;
  1683. handle_t hBinding = NULL;
  1684. try {
  1685. //
  1686. // validate input parameters
  1687. //
  1688. if (!ARGUMENT_PRESENT(ClassGuid)) {
  1689. Status = CR_INVALID_POINTER;
  1690. goto Clean0;
  1691. }
  1692. if (INVALID_FLAGS(ulFlags, 0)) {
  1693. Status = CR_INVALID_FLAG;
  1694. goto Clean0;
  1695. }
  1696. //
  1697. // initialize guid struct
  1698. //
  1699. ZeroMemory(ClassGuid, sizeof(GUID));
  1700. //
  1701. // setup rpc binding handle
  1702. //
  1703. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  1704. Status = CR_FAILURE;
  1705. goto Clean0;
  1706. }
  1707. RpcTryExcept {
  1708. //
  1709. // call rpc service entry point
  1710. //
  1711. Status = PNP_EnumerateSubKeys(
  1712. hBinding, // rpc binding handle
  1713. PNP_CLASS_SUBKEYS, // subkeys of class branch
  1714. ulClassIndex, // index of class key to enumerate
  1715. szClassGuid, // will contain class name
  1716. ulLength, // length of Buffer in chars,
  1717. &ulLength, // size copied (or size required)
  1718. ulFlags); // currently unused
  1719. }
  1720. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1721. KdPrintEx((DPFLTR_PNPMGR_ID,
  1722. DBGF_ERRORS,
  1723. "PNP_EnumerateSubKeys caused an exception (%d)\n",
  1724. RpcExceptionCode()));
  1725. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1726. }
  1727. RpcEndExcept
  1728. if (Status == CR_SUCCESS) {
  1729. if (pSetupGuidFromString(szClassGuid, ClassGuid) != NO_ERROR) {
  1730. Status = CR_FAILURE;
  1731. }
  1732. }
  1733. Clean0:
  1734. NOTHING;
  1735. } except(EXCEPTION_EXECUTE_HANDLER) {
  1736. Status = CR_FAILURE;
  1737. }
  1738. return Status;
  1739. } // CM_Enumerate_Classes_Ex
  1740. CONFIGRET
  1741. CM_Get_Class_Name_ExW(
  1742. IN LPGUID ClassGuid,
  1743. OUT PTCHAR Buffer,
  1744. IN OUT PULONG pulLength,
  1745. IN ULONG ulFlags,
  1746. IN HMACHINE hMachine
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. This routine retrieves the class name associated with the specified
  1751. class GUID string.
  1752. Parameters:
  1753. ClassGuid Supplies a pointer to the class GUID whose name
  1754. is to be retrieved.
  1755. Buffer Supplies the address of the character buffer that receives
  1756. the class name corresponding to the specified GUID.
  1757. pulLength Supplies the address of the variable that contains the
  1758. length, in characters, of the Buffer. Upon return, this
  1759. variable will contain the number of characters (including
  1760. terminating NULL) written to Buffer (if the supplied buffer
  1761. isn't large enough, then the routine will fail with
  1762. CR_BUFFER_SMALL, and this value will indicate how large the
  1763. buffer needs to be in order to succeed).
  1764. ulFlags Must be zero.
  1765. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  1766. Return Value:
  1767. If the function succeeds, the return value is CR_SUCCESS.
  1768. If the function fails, the return value is one of the following:
  1769. CR_INVALID_FLAG,
  1770. CR_INVALID_POINTER,
  1771. CR_BUFFER_SMALL, or
  1772. CR_REGISTRY_ERROR
  1773. --*/
  1774. {
  1775. CONFIGRET Status = CR_SUCCESS;
  1776. WCHAR szStringGuid[MAX_GUID_STRING_LEN];
  1777. handle_t hBinding = NULL;
  1778. try {
  1779. //
  1780. // validate input parameters
  1781. //
  1782. if ((!ARGUMENT_PRESENT(ClassGuid)) ||
  1783. (!ARGUMENT_PRESENT(Buffer)) ||
  1784. (!ARGUMENT_PRESENT(pulLength))) {
  1785. Status = CR_INVALID_POINTER;
  1786. goto Clean0;
  1787. }
  1788. if (INVALID_FLAGS(ulFlags, 0)) {
  1789. Status = CR_INVALID_FLAG;
  1790. goto Clean0;
  1791. }
  1792. //
  1793. // convert from guid to string
  1794. //
  1795. if (pSetupStringFromGuid(ClassGuid, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
  1796. Status = CR_INVALID_DATA;
  1797. goto Clean0;
  1798. }
  1799. //
  1800. // setup rpc binding handle
  1801. //
  1802. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  1803. Status = CR_FAILURE;
  1804. goto Clean0;
  1805. }
  1806. RpcTryExcept {
  1807. //
  1808. // call rpc service entry point
  1809. //
  1810. Status = PNP_GetClassName(
  1811. hBinding, // rpc binding handle
  1812. szStringGuid,
  1813. Buffer,
  1814. pulLength, // returns count of keys under Class
  1815. ulFlags); // not used
  1816. }
  1817. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1818. KdPrintEx((DPFLTR_PNPMGR_ID,
  1819. DBGF_ERRORS,
  1820. "PNP_GetClassName caused an exception (%d)\n",
  1821. RpcExceptionCode()));
  1822. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1823. }
  1824. RpcEndExcept
  1825. Clean0:
  1826. NOTHING;
  1827. } except(EXCEPTION_EXECUTE_HANDLER) {
  1828. Status = CR_FAILURE;
  1829. }
  1830. return Status;
  1831. } // CM_Get_Class_Name_ExW
  1832. CONFIGRET
  1833. CM_Get_Class_Key_Name_ExW(
  1834. IN LPGUID ClassGuid,
  1835. OUT LPWSTR pszKeyName,
  1836. IN OUT PULONG pulLength,
  1837. IN ULONG ulFlags,
  1838. IN HMACHINE hMachine
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. This routine retrieves the class name associated with the specified
  1843. class GUID string.
  1844. Parameters:
  1845. ClassGuid Supplies a pointer to the class GUID whose name
  1846. is to be retrieved.
  1847. pszKeyName Returns the name of the class key in the registry that
  1848. corresponds to the specified ClassGuid. The returned key
  1849. name is relative to
  1850. HKLM\System\CurrentControlSet\Control\Class.
  1851. pulLength Supplies the address of the variable that contains the
  1852. length, in characters, of the Buffer. Upon return, this
  1853. variable will contain the number of characters (including
  1854. terminating NULL) written to Buffer (if the supplied buffer
  1855. isn't large enough, then the routine will fail with
  1856. CR_BUFFER_SMALL, and this value will indicate how large the
  1857. buffer needs to be in order to succeed).
  1858. ulFlags Must be zero.
  1859. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  1860. Return Value:
  1861. If the function succeeds, the return value is CR_SUCCESS.
  1862. If the function fails, the return value is one of the following:
  1863. CR_INVALID_FLAG,
  1864. CR_INVALID_POINTER,
  1865. CR_BUFFER_SMALL, or
  1866. CR_REGISTRY_ERROR
  1867. --*/
  1868. {
  1869. CONFIGRET Status = CR_SUCCESS;
  1870. handle_t hBinding = NULL;
  1871. //
  1872. // NOTE: the supplied machine handle is never referenced by this routine,
  1873. // since it is known/assumed that the key name of the class key requested is
  1874. // always just the string representation of the supplied class GUID.
  1875. // there is no corresponding UMPNPMGR server-side routine.
  1876. //
  1877. UNREFERENCED_PARAMETER(hMachine);
  1878. try {
  1879. //
  1880. // validate input parameters
  1881. //
  1882. if (!ARGUMENT_PRESENT(pulLength)) {
  1883. Status = CR_INVALID_POINTER;
  1884. goto Clean0;
  1885. }
  1886. if ((!ARGUMENT_PRESENT(ClassGuid)) ||
  1887. (!ARGUMENT_PRESENT(pszKeyName))) {
  1888. Status = CR_INVALID_POINTER;
  1889. goto Clean0;
  1890. }
  1891. if (INVALID_FLAGS(ulFlags, 0)) {
  1892. Status = CR_INVALID_FLAG;
  1893. goto Clean0;
  1894. }
  1895. if (*pulLength < MAX_GUID_STRING_LEN) {
  1896. *pulLength = MAX_GUID_STRING_LEN;
  1897. Status = CR_BUFFER_SMALL;
  1898. goto Clean0;
  1899. }
  1900. //
  1901. // convert from guid to string
  1902. //
  1903. if (pSetupStringFromGuid(ClassGuid, pszKeyName,MAX_GUID_STRING_LEN) == NO_ERROR) {
  1904. *pulLength = MAX_GUID_STRING_LEN;
  1905. } else {
  1906. Status = CR_INVALID_DATA;
  1907. }
  1908. Clean0:
  1909. NOTHING;
  1910. } except(EXCEPTION_EXECUTE_HANDLER) {
  1911. Status = CR_FAILURE;
  1912. }
  1913. return Status;
  1914. } // CM_Get_Class_Key_Name_ExW
  1915. CONFIGRET
  1916. CM_Delete_Class_Key_Ex(
  1917. IN LPGUID ClassGuid,
  1918. IN ULONG ulFlags,
  1919. IN HANDLE hMachine
  1920. )
  1921. /*++
  1922. Routine Description:
  1923. This routine deletes the specified class key from the registry.
  1924. Parameters:
  1925. ClassGuid Supplies a pointer to the class GUID to delete.
  1926. ulFlags Must be one of the following values:
  1927. CM_DELETE_CLASS_ONLY - only deletes the class key if it
  1928. doesn't have any subkeys.
  1929. CM_DELETE_CLASS_SUBKEYS - deletes the class key and any
  1930. subkeys of the class key.
  1931. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  1932. Return Value:
  1933. If the function succeeds, the return value is CR_SUCCESS.
  1934. If the function fails, the return value is one of the following:
  1935. CR_INVALID_FLAG,
  1936. CR_INVALID_POINTER,
  1937. CR_BUFFER_SMALL, or
  1938. CR_REGISTRY_ERROR
  1939. --*/
  1940. {
  1941. CONFIGRET Status = CR_SUCCESS;
  1942. WCHAR szStringGuid[MAX_GUID_STRING_LEN];
  1943. handle_t hBinding = NULL;
  1944. try {
  1945. //
  1946. // validate input parameters
  1947. //
  1948. if (!ARGUMENT_PRESENT(ClassGuid)) {
  1949. Status = CR_INVALID_POINTER;
  1950. goto Clean0;
  1951. }
  1952. if (INVALID_FLAGS(ulFlags, CM_DELETE_CLASS_BITS)) {
  1953. Status = CR_INVALID_FLAG;
  1954. goto Clean0;
  1955. }
  1956. //
  1957. // convert from guid to string
  1958. //
  1959. if (pSetupStringFromGuid(ClassGuid, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
  1960. Status = CR_INVALID_DATA;
  1961. goto Clean0;
  1962. }
  1963. //
  1964. // setup rpc binding handle
  1965. //
  1966. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  1967. Status = CR_FAILURE;
  1968. goto Clean0;
  1969. }
  1970. RpcTryExcept {
  1971. //
  1972. // call rpc service entry point
  1973. //
  1974. Status = PNP_DeleteClassKey(
  1975. hBinding, // rpc binding handle
  1976. szStringGuid,
  1977. ulFlags);
  1978. }
  1979. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1980. KdPrintEx((DPFLTR_PNPMGR_ID,
  1981. DBGF_ERRORS,
  1982. "PNP_DeleteClassKey caused an exception (%d)\n",
  1983. RpcExceptionCode()));
  1984. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1985. }
  1986. RpcEndExcept
  1987. Clean0:
  1988. NOTHING;
  1989. } except(EXCEPTION_EXECUTE_HANDLER) {
  1990. Status = CR_FAILURE;
  1991. }
  1992. return Status;
  1993. } // CM_Delete_Class_Key_Ex
  1994. CMAPI
  1995. CONFIGRET
  1996. WINAPI
  1997. CM_Get_Device_Interface_Alias_ExW(
  1998. IN LPCWSTR pszDeviceInterface,
  1999. IN LPGUID AliasInterfaceGuid,
  2000. OUT LPWSTR pszAliasDeviceInterface,
  2001. IN OUT PULONG pulLength,
  2002. IN ULONG ulFlags,
  2003. IN HMACHINE hMachine
  2004. )
  2005. {
  2006. CONFIGRET Status = CR_SUCCESS;
  2007. handle_t hBinding = NULL;
  2008. ULONG ulTransferLen = 0;
  2009. try {
  2010. //
  2011. // validate input parameters
  2012. //
  2013. if ((!ARGUMENT_PRESENT(pszDeviceInterface)) ||
  2014. (!ARGUMENT_PRESENT(AliasInterfaceGuid)) ||
  2015. (!ARGUMENT_PRESENT(pszAliasDeviceInterface)) ||
  2016. (!ARGUMENT_PRESENT(pulLength))) {
  2017. Status = CR_INVALID_POINTER;
  2018. goto Clean0;
  2019. }
  2020. if (INVALID_FLAGS(ulFlags, 0)) {
  2021. Status = CR_INVALID_FLAG;
  2022. goto Clean0;
  2023. }
  2024. //
  2025. // initialize output parameters
  2026. //
  2027. *pszAliasDeviceInterface = '\0';
  2028. ulTransferLen = *pulLength;
  2029. //
  2030. // setup rpc binding handle
  2031. //
  2032. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  2033. Status = CR_FAILURE;
  2034. goto Clean0;
  2035. }
  2036. RpcTryExcept {
  2037. //
  2038. // call rpc service entry point
  2039. //
  2040. Status = PNP_GetInterfaceDeviceAlias(
  2041. hBinding,
  2042. pszDeviceInterface,
  2043. AliasInterfaceGuid,
  2044. pszAliasDeviceInterface,
  2045. pulLength,
  2046. &ulTransferLen,
  2047. ulFlags);
  2048. }
  2049. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  2050. KdPrintEx((DPFLTR_PNPMGR_ID,
  2051. DBGF_ERRORS,
  2052. "PNP_GetInterfaceDeviceAlias caused an exception (%d)\n",
  2053. RpcExceptionCode()));
  2054. Status = MapRpcExceptionToCR(RpcExceptionCode());
  2055. }
  2056. RpcEndExcept
  2057. Clean0:
  2058. NOTHING;
  2059. } except(EXCEPTION_EXECUTE_HANDLER) {
  2060. Status = CR_FAILURE;
  2061. }
  2062. return Status;
  2063. } // CM_Get_Device_Interface_Alias_ExW
  2064. CMAPI
  2065. CONFIGRET
  2066. WINAPI
  2067. CM_Get_Device_Interface_List_ExW(
  2068. IN LPGUID InterfaceClassGuid,
  2069. IN DEVINSTID_W pDeviceID OPTIONAL,
  2070. OUT PWCHAR Buffer,
  2071. IN ULONG BufferLen,
  2072. IN ULONG ulFlags,
  2073. IN HMACHINE hMachine
  2074. )
  2075. /*++
  2076. Routine Description:
  2077. This routine returns a list of interface devices of the specified interface
  2078. class. You can optionally filter the list of returned interface devices
  2079. based on only those created by a particular devinst. Typically the
  2080. CM_Get_Interface_Device_List routine is called first to determine how big
  2081. a buffer must be allocated to hold the interface device list.
  2082. Parameters:
  2083. InterfaceClassGuid This GUID specifies which interface devices to return (only
  2084. those interface devices that belong to this interface class).
  2085. pDeviceID Optional devinst to filter the list of returned interface
  2086. devices (if non-zero, only the interfaces devices associated
  2087. with this devinst will be returned).
  2088. Buffer Supplies the buffer that will contain the returned multi_sz
  2089. list of interface devices.
  2090. BufferLen Specifies how big the Buffer parameter is in characters.
  2091. ulFlags Must be one of the following values:
  2092. CM_GET_DEVICE_INTERFACE_LIST_PRESENT -
  2093. only currently 'live' devices
  2094. CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES 0x00000001 -
  2095. all registered devices, live or not
  2096. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  2097. Return Value:
  2098. If the function succeeds, the return value is CR_SUCCESS.
  2099. If the function fails, the return value is one of the following:
  2100. CR_INVALID_FLAG,
  2101. CR_INVALID_POINTER,
  2102. CR_BUFFER_SMALL, or
  2103. CR_REGISTRY_ERROR
  2104. --*/
  2105. {
  2106. CONFIGRET Status = CR_SUCCESS;
  2107. handle_t hBinding = NULL;
  2108. try {
  2109. //
  2110. // validate input parameters
  2111. //
  2112. if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
  2113. Status = CR_INVALID_POINTER;
  2114. goto Clean0;
  2115. }
  2116. if (INVALID_FLAGS(ulFlags, CM_GET_DEVICE_INTERFACE_LIST_BITS)) {
  2117. Status = CR_INVALID_FLAG;
  2118. goto Clean0;
  2119. }
  2120. //
  2121. // initialize output parameters
  2122. //
  2123. *Buffer = '\0';
  2124. //
  2125. // setup rpc binding handle
  2126. //
  2127. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  2128. Status = CR_FAILURE;
  2129. goto Clean0;
  2130. }
  2131. RpcTryExcept {
  2132. //
  2133. // call rpc service entry point
  2134. //
  2135. Status = PNP_GetInterfaceDeviceList(
  2136. hBinding, // RPC Binding Handle
  2137. InterfaceClassGuid, // Device interface GUID
  2138. pDeviceID, // filter string, optional
  2139. Buffer, // will contain device list
  2140. &BufferLen, // in/out size of Buffer
  2141. ulFlags); // filter flag
  2142. }
  2143. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  2144. KdPrintEx((DPFLTR_PNPMGR_ID,
  2145. DBGF_ERRORS,
  2146. "PNP_GetInterfaceDeviceList caused an exception (%d)\n",
  2147. RpcExceptionCode()));
  2148. Status = MapRpcExceptionToCR(RpcExceptionCode());
  2149. }
  2150. RpcEndExcept
  2151. Clean0:
  2152. NOTHING;
  2153. } except(EXCEPTION_EXECUTE_HANDLER) {
  2154. Status = CR_FAILURE;
  2155. }
  2156. return Status;
  2157. } // CM_Get_Device_Interface_List_ExW
  2158. CMAPI
  2159. CONFIGRET
  2160. WINAPI
  2161. CM_Get_Device_Interface_List_Size_ExW(
  2162. IN PULONG pulLen,
  2163. IN LPGUID InterfaceClassGuid,
  2164. IN DEVINSTID_W pDeviceID OPTIONAL,
  2165. IN ULONG ulFlags,
  2166. IN HMACHINE hMachine
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. This routine returns the size (in characters) of buffer required to hold a
  2171. multi_sz list of interface devices of the specified interface class. You
  2172. can optionally filter the list of returned interface devices based on only
  2173. those created by a particular devinst. This routine is typically called before
  2174. a call to the CM_Get_Interface_Device_List routine.
  2175. Parameters:
  2176. pulLen On a successful return from this routine, this parameter
  2177. will contain the size (in characters) required to hold the
  2178. multi_sz list of returned interface devices.
  2179. InterfaceClassGuid This GUID specifies which interface devices to include (only
  2180. those interface devices that belong to this interface class).
  2181. pDeviceID Optional devinst to filter the list of returned interface
  2182. devices (if non-zero, only the interfaces devices associated
  2183. with this devinst will be returned).
  2184. ulFlags Must be one of the following values:
  2185. CM_GET_DEVICE_INTERFACE_LIST_PRESENT -
  2186. only currently 'live' devices
  2187. CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES -
  2188. all registered devices, live or not
  2189. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  2190. Return Value:
  2191. If the function succeeds, the return value is CR_SUCCESS.
  2192. If the function fails, the return value is one of the following:
  2193. CR_INVALID_FLAG,
  2194. CR_INVALID_POINTER,
  2195. CR_BUFFER_SMALL, or
  2196. CR_REGISTRY_ERROR
  2197. --*/
  2198. {
  2199. CONFIGRET Status = CR_SUCCESS;
  2200. handle_t hBinding = NULL;
  2201. try {
  2202. //
  2203. // validate input parameters
  2204. //
  2205. if (!ARGUMENT_PRESENT(pulLen)) {
  2206. Status = CR_INVALID_POINTER;
  2207. goto Clean0;
  2208. }
  2209. if (INVALID_FLAGS(ulFlags, CM_GET_DEVICE_INTERFACE_LIST_BITS)) {
  2210. Status = CR_INVALID_FLAG;
  2211. goto Clean0;
  2212. }
  2213. //
  2214. // initialize output parameters
  2215. //
  2216. *pulLen = 0;
  2217. //
  2218. // setup rpc binding handle
  2219. //
  2220. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  2221. Status = CR_FAILURE;
  2222. goto Clean0;
  2223. }
  2224. RpcTryExcept {
  2225. //
  2226. // call rpc service entry point
  2227. //
  2228. Status = PNP_GetInterfaceDeviceListSize(
  2229. hBinding, // RPC Binding Handle
  2230. pulLen, // Size of buffer required (in chars)
  2231. InterfaceClassGuid, // Device interface GUID
  2232. pDeviceID, // filter string, optional
  2233. ulFlags); // filter flag
  2234. }
  2235. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  2236. KdPrintEx((DPFLTR_PNPMGR_ID,
  2237. DBGF_ERRORS,
  2238. "PNP_GetInterfaceDeviceListSize caused an exception (%d)\n",
  2239. RpcExceptionCode()));
  2240. Status = MapRpcExceptionToCR(RpcExceptionCode());
  2241. }
  2242. RpcEndExcept
  2243. Clean0:
  2244. NOTHING;
  2245. } except(EXCEPTION_EXECUTE_HANDLER) {
  2246. Status = CR_FAILURE;
  2247. }
  2248. return Status;
  2249. } // CM_Get_Device_Interface_List_Size_Ex
  2250. CMAPI
  2251. CONFIGRET
  2252. WINAPI
  2253. CM_Register_Device_Interface_ExW(
  2254. IN DEVINST dnDevInst,
  2255. IN LPGUID InterfaceClassGuid,
  2256. IN LPCWSTR pszReference OPTIONAL,
  2257. OUT LPWSTR pszDeviceInterface,
  2258. IN OUT PULONG pulLength,
  2259. IN ULONG ulFlags,
  2260. IN HMACHINE hMachine
  2261. )
  2262. /*++
  2263. Routine Description:
  2264. Parameters:
  2265. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  2266. Return Value:
  2267. If the function succeeds, the return value is CR_SUCCESS.
  2268. If the function fails, the return value is one of the following:
  2269. CR_INVALID_FLAG,
  2270. CR_INVALID_POINTER,
  2271. CR_BUFFER_SMALL, or
  2272. CR_REGISTRY_ERROR
  2273. --*/
  2274. {
  2275. CONFIGRET Status = CR_SUCCESS;
  2276. WCHAR pszDeviceID [MAX_DEVICE_ID_LEN];
  2277. ULONG ulTransferLen,ulLen = MAX_DEVICE_ID_LEN;
  2278. PVOID hStringTable = NULL;
  2279. handle_t hBinding = NULL;
  2280. BOOL Success;
  2281. try {
  2282. //
  2283. // validate input parameters
  2284. //
  2285. if ((!ARGUMENT_PRESENT(pulLength)) ||
  2286. (!ARGUMENT_PRESENT(pszDeviceInterface)) ||
  2287. (!ARGUMENT_PRESENT(InterfaceClassGuid))) {
  2288. Status = CR_INVALID_POINTER;
  2289. goto Clean0;
  2290. }
  2291. if (dnDevInst == 0) {
  2292. Status = CR_INVALID_DEVINST;
  2293. goto Clean0;
  2294. }
  2295. if (INVALID_FLAGS(ulFlags, 0)) {
  2296. Status = CR_INVALID_FLAG;
  2297. goto Clean0;
  2298. }
  2299. //
  2300. // setup rpc binding handle and string table handle
  2301. //
  2302. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  2303. Status = CR_FAILURE;
  2304. goto Clean0;
  2305. }
  2306. //
  2307. // retreive device instance string that corresponds to dnParent
  2308. // (note that this is not optional, even a first level device instance
  2309. // has a parent (the root device instance)
  2310. //
  2311. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pszDeviceID,&ulLen);
  2312. if (Success == FALSE || INVALID_DEVINST(pszDeviceID)) {
  2313. Status = CR_INVALID_DEVNODE;
  2314. goto Clean0;
  2315. }
  2316. //
  2317. // ulTransferLen is just used to control how many bytes in the
  2318. // pszInterfaceDevice buffer must be marshalled. We need two
  2319. // length params, since pulLength may contained the required bytes
  2320. // (if the passed in buffer was too small) which may differ from
  2321. // how many types are actually available to marshall (in the buffer
  2322. // too small case, we'll marshall zero so ulTransferLen will be zero
  2323. // but pulLength will describe how many bytes are required to hold
  2324. // the Interface Device string.
  2325. //
  2326. ulTransferLen = *pulLength;
  2327. RpcTryExcept {
  2328. //
  2329. // call rpc service entry point
  2330. //
  2331. Status = PNP_RegisterDeviceClassAssociation(
  2332. hBinding, // RPC Binding Handle
  2333. pszDeviceID, // device instance
  2334. InterfaceClassGuid, // Device interface GUID
  2335. pszReference, // reference string, optional
  2336. pszDeviceInterface, // returns interface device name
  2337. pulLength, // pszInterfaceDevice buffer required in chars
  2338. &ulTransferLen, // how many chars to marshall back
  2339. ulFlags); // filter flag
  2340. }
  2341. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  2342. KdPrintEx((DPFLTR_PNPMGR_ID,
  2343. DBGF_ERRORS,
  2344. "PNP_RegisterDeviceClassAssociation caused an exception (%d)\n",
  2345. RpcExceptionCode()));
  2346. Status = MapRpcExceptionToCR(RpcExceptionCode());
  2347. }
  2348. RpcEndExcept
  2349. Clean0:
  2350. NOTHING;
  2351. } except(EXCEPTION_EXECUTE_HANDLER) {
  2352. Status = CR_FAILURE;
  2353. }
  2354. return Status;
  2355. } // CM_Register_Device_Interface
  2356. CMAPI
  2357. CONFIGRET
  2358. WINAPI
  2359. CM_Unregister_Device_Interface_ExW(
  2360. IN LPCWSTR pszDeviceInterface,
  2361. IN ULONG ulFlags,
  2362. IN HMACHINE hMachine
  2363. )
  2364. /*++
  2365. Routine Description:
  2366. Parameters:
  2367. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  2368. Return Value:
  2369. If the function succeeds, the return value is CR_SUCCESS.
  2370. If the function fails, the return value is one of the following:
  2371. CR_INVALID_FLAG,
  2372. CR_INVALID_POINTER,
  2373. CR_BUFFER_SMALL, or
  2374. CR_REGISTRY_ERROR
  2375. --*/
  2376. {
  2377. CONFIGRET Status = CR_SUCCESS;
  2378. handle_t hBinding = NULL;
  2379. try {
  2380. //
  2381. // validate input parameters
  2382. //
  2383. if (!ARGUMENT_PRESENT(pszDeviceInterface)) {
  2384. Status = CR_INVALID_POINTER;
  2385. goto Clean0;
  2386. }
  2387. if (INVALID_FLAGS(ulFlags, 0)) {
  2388. Status = CR_INVALID_FLAG;
  2389. goto Clean0;
  2390. }
  2391. //
  2392. // setup rpc binding handle
  2393. //
  2394. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  2395. Status = CR_FAILURE;
  2396. goto Clean0;
  2397. }
  2398. RpcTryExcept {
  2399. //
  2400. // call rpc service entry point
  2401. //
  2402. Status = PNP_UnregisterDeviceClassAssociation(
  2403. hBinding, // RPC Binding Handle
  2404. pszDeviceInterface, // interface device
  2405. ulFlags); // unused
  2406. }
  2407. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  2408. KdPrintEx((DPFLTR_PNPMGR_ID,
  2409. DBGF_ERRORS,
  2410. "PNP_UnregisterDeviceClassAssociation caused an exception (%d)\n",
  2411. RpcExceptionCode()));
  2412. Status = MapRpcExceptionToCR(RpcExceptionCode());
  2413. }
  2414. RpcEndExcept
  2415. Clean0:
  2416. NOTHING;
  2417. } except(EXCEPTION_EXECUTE_HANDLER) {
  2418. Status = CR_FAILURE;
  2419. }
  2420. return Status;
  2421. } // CM_Unregister_Device_Interface_ExW
  2422. CMAPI
  2423. CONFIGRET
  2424. WINAPI
  2425. CM_Get_DevNode_Custom_Property_ExW(
  2426. IN DEVINST dnDevInst,
  2427. IN PCWSTR pszCustomPropertyName,
  2428. OUT PULONG pulRegDataType OPTIONAL,
  2429. OUT PVOID Buffer OPTIONAL,
  2430. IN OUT PULONG pulLength,
  2431. IN ULONG ulFlags,
  2432. IN HMACHINE hMachine
  2433. )
  2434. /*++
  2435. Routine Description:
  2436. This routine retrieves the specified property, either from the devnode's
  2437. device (aka, hardware) key, or from the most-specific per-hardware-id
  2438. storage key for that devnode.
  2439. Parameters:
  2440. dnDevInst Supplies the handle of the device instance for which a
  2441. custom property is to be retrieved.
  2442. pszCustomPropertyName Supplies a string identifying the name of the
  2443. property (registry value entry name) to be retrieved.
  2444. pulRegDataType Optionally, supplies the address of a variable that
  2445. will receive the registry data type for this property
  2446. (i.e., the REG_* constants).
  2447. Buffer Supplies the address of the buffer that receives the
  2448. registry data. Can be NULL when simply retrieving data size.
  2449. pulLength Supplies the address of the variable that contains the size,
  2450. in bytes, of the buffer. The API replaces the initial size
  2451. with the number of bytes of registry data copied to the buffer.
  2452. If the variable is initially zero, the API replaces it with
  2453. the buffer size needed to receive all the registry data. In
  2454. this case, the Buffer parameter is ignored.
  2455. ulFlags May be a combination of the following values:
  2456. CM_CUSTOMDEVPROP_MERGE_MULTISZ : merge the devnode-specific
  2457. REG_SZ or REG_MULTI_SZ property (if present) with the
  2458. per-hardware-id REG_SZ or REG_MULTI_SZ property (if
  2459. present). The result will always be a REG_MULTI_SZ.
  2460. hMachine Machine handle returned from CM_Connect_Machine or NULL.
  2461. Return Value:
  2462. If the function succeeds, the return value is CR_SUCCESS.
  2463. If the function fails, the return value indicates the cause of failure, and
  2464. is typically one of the following:
  2465. CR_INVALID_DEVNODE,
  2466. CR_INVALID_FLAG,
  2467. CR_INVALID_POINTER,
  2468. CR_REGISTRY_ERROR,
  2469. CR_BUFFER_SMALL,
  2470. CR_NO_SUCH_VALUE, or
  2471. CR_FAILURE.
  2472. --*/
  2473. {
  2474. CONFIGRET Status = CR_SUCCESS;
  2475. WCHAR pDeviceID[MAX_DEVICE_ID_LEN];
  2476. ULONG ulSizeID, ulTempDataType, ulTransferLen;
  2477. BYTE NullBuffer = 0;
  2478. handle_t hBinding;
  2479. PVOID hStringTable;
  2480. BOOL Success;
  2481. try {
  2482. //
  2483. // validate parameters
  2484. //
  2485. if(!dnDevInst) {
  2486. Status = CR_INVALID_DEVINST;
  2487. goto Clean0;
  2488. }
  2489. if(!pszCustomPropertyName) {
  2490. Status = CR_INVALID_POINTER;
  2491. goto Clean0;
  2492. }
  2493. if(!pulLength) {
  2494. Status = CR_INVALID_POINTER;
  2495. goto Clean0;
  2496. }
  2497. if(!Buffer && *pulLength) {
  2498. Status = CR_INVALID_POINTER;
  2499. goto Clean0;
  2500. }
  2501. if(INVALID_FLAGS(ulFlags, CM_CUSTOMDEVPROP_BITS)) {
  2502. Status = CR_INVALID_FLAG;
  2503. goto Clean0;
  2504. }
  2505. //
  2506. // setup rpc binding handle and string table handle
  2507. //
  2508. if(!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  2509. Status = CR_FAILURE;
  2510. goto Clean0;
  2511. }
  2512. //
  2513. // retrieve the string form of the device id string
  2514. //
  2515. ulSizeID = SIZECHARS(pDeviceID);
  2516. Success = pSetupStringTableStringFromIdEx(hStringTable,
  2517. dnDevInst,
  2518. pDeviceID,
  2519. &ulSizeID
  2520. );
  2521. if(!Success || INVALID_DEVINST(pDeviceID)) {
  2522. Status = CR_INVALID_DEVINST;
  2523. goto Clean0;
  2524. }
  2525. if(!Buffer) {
  2526. Buffer = &NullBuffer;
  2527. }
  2528. RpcTryExcept {
  2529. //
  2530. // call rpc service entry point
  2531. //
  2532. Status = PNP_GetCustomDevProp(
  2533. hBinding, // rpc binding handle
  2534. pDeviceID, // string representation of device instance
  2535. pszCustomPropertyName, // name of the property
  2536. &ulTempDataType, // receives registry data type
  2537. Buffer, // receives registry data
  2538. &ulTransferLen, // input/output buffer size
  2539. pulLength, // bytes copied (or bytes required)
  2540. ulFlags); // flags (e.g., merge-multi-sz?)
  2541. }
  2542. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  2543. KdPrintEx((DPFLTR_PNPMGR_ID,
  2544. DBGF_ERRORS,
  2545. "PNP_GetCustomDevProp caused an exception (%d)\n",
  2546. RpcExceptionCode()));
  2547. Status = MapRpcExceptionToCR(RpcExceptionCode());
  2548. }
  2549. RpcEndExcept
  2550. if(pulRegDataType) {
  2551. //
  2552. // I pass a temp variable to the rpc stubs since they require the
  2553. // output param to always be valid, then if user did pass in a valid
  2554. // pointer to receive the info, do the assignment now
  2555. //
  2556. *pulRegDataType = ulTempDataType;
  2557. }
  2558. Clean0:
  2559. NOTHING;
  2560. } except(EXCEPTION_EXECUTE_HANDLER) {
  2561. Status = CR_FAILURE;
  2562. }
  2563. return Status;
  2564. } // CM_Get_DevNode_Custom_Property_ExW
  2565. //-------------------------------------------------------------------
  2566. // Local Stubs
  2567. //-------------------------------------------------------------------
  2568. CONFIGRET
  2569. CM_Get_DevNode_Registry_PropertyW(
  2570. IN DEVINST dnDevInst,
  2571. IN ULONG ulProperty,
  2572. OUT PULONG pulRegDataType OPTIONAL,
  2573. OUT PVOID Buffer OPTIONAL,
  2574. IN OUT PULONG pulLength,
  2575. IN ULONG ulFlags
  2576. )
  2577. {
  2578. return CM_Get_DevNode_Registry_Property_ExW(dnDevInst, ulProperty,
  2579. pulRegDataType, Buffer,
  2580. pulLength, ulFlags, NULL);
  2581. }
  2582. CONFIGRET
  2583. CM_Get_DevNode_Registry_PropertyA(
  2584. IN DEVINST dnDevInst,
  2585. IN ULONG ulProperty,
  2586. OUT PULONG pulRegDataType OPTIONAL,
  2587. OUT PVOID Buffer OPTIONAL,
  2588. IN OUT PULONG pulLength,
  2589. IN ULONG ulFlags
  2590. )
  2591. {
  2592. return CM_Get_DevNode_Registry_Property_ExA(dnDevInst, ulProperty,
  2593. pulRegDataType, Buffer,
  2594. pulLength, ulFlags, NULL);
  2595. }
  2596. CONFIGRET
  2597. CM_Set_DevNode_Registry_PropertyW(
  2598. IN DEVINST dnDevInst,
  2599. IN ULONG ulProperty,
  2600. IN PCVOID Buffer OPTIONAL,
  2601. IN OUT ULONG ulLength,
  2602. IN ULONG ulFlags
  2603. )
  2604. {
  2605. return CM_Set_DevNode_Registry_Property_ExW(dnDevInst, ulProperty, Buffer,
  2606. ulLength, ulFlags, NULL);
  2607. }
  2608. CONFIGRET
  2609. CM_Set_DevNode_Registry_PropertyA(
  2610. IN DEVINST dnDevInst,
  2611. IN ULONG ulProperty,
  2612. IN PCVOID Buffer OPTIONAL,
  2613. IN OUT ULONG ulLength,
  2614. IN ULONG ulFlags
  2615. )
  2616. {
  2617. return CM_Set_DevNode_Registry_Property_ExA(dnDevInst, ulProperty, Buffer,
  2618. ulLength, ulFlags, NULL);
  2619. }
  2620. CONFIGRET
  2621. CM_Open_DevNode_Key(
  2622. IN DEVINST dnDevNode,
  2623. IN REGSAM samDesired,
  2624. IN ULONG ulHardwareProfile,
  2625. IN REGDISPOSITION Disposition,
  2626. OUT PHKEY phkDevice,
  2627. IN ULONG ulFlags
  2628. )
  2629. {
  2630. return CM_Open_DevNode_Key_Ex(dnDevNode, samDesired, ulHardwareProfile,
  2631. Disposition, phkDevice, ulFlags, NULL);
  2632. }
  2633. CONFIGRET
  2634. CM_Delete_DevNode_Key(
  2635. IN DEVNODE dnDevNode,
  2636. IN ULONG ulHardwareProfile,
  2637. IN ULONG ulFlags
  2638. )
  2639. {
  2640. return CM_Delete_DevNode_Key_Ex(dnDevNode, ulHardwareProfile,
  2641. ulFlags, NULL);
  2642. }
  2643. CONFIGRET
  2644. CM_Open_Class_KeyW(
  2645. IN LPGUID ClassGuid OPTIONAL,
  2646. IN LPCWSTR pszClassName OPTIONAL,
  2647. IN REGSAM samDesired,
  2648. IN REGDISPOSITION Disposition,
  2649. OUT PHKEY phkClass,
  2650. IN ULONG ulFlags
  2651. )
  2652. {
  2653. return CM_Open_Class_Key_ExW(ClassGuid, pszClassName, samDesired,
  2654. Disposition, phkClass, ulFlags, NULL);
  2655. }
  2656. CONFIGRET
  2657. CM_Open_Class_KeyA(
  2658. IN LPGUID ClassGuid OPTIONAL,
  2659. IN LPCSTR pszClassName OPTIONAL,
  2660. IN REGSAM samDesired,
  2661. IN REGDISPOSITION Disposition,
  2662. OUT PHKEY phkClass,
  2663. IN ULONG ulFlags
  2664. )
  2665. {
  2666. return CM_Open_Class_Key_ExA(ClassGuid, pszClassName, samDesired,
  2667. Disposition, phkClass, ulFlags, NULL);
  2668. }
  2669. CONFIGRET
  2670. CM_Enumerate_Classes(
  2671. IN ULONG ulClassIndex,
  2672. OUT LPGUID ClassGuid,
  2673. IN ULONG ulFlags
  2674. )
  2675. {
  2676. return CM_Enumerate_Classes_Ex(ulClassIndex, ClassGuid, ulFlags, NULL);
  2677. }
  2678. CONFIGRET
  2679. CM_Get_Class_NameW(
  2680. IN LPGUID ClassGuid,
  2681. OUT PWCHAR Buffer,
  2682. IN OUT PULONG pulLength,
  2683. IN ULONG ulFlags
  2684. )
  2685. {
  2686. return CM_Get_Class_Name_ExW(ClassGuid, Buffer, pulLength, ulFlags, NULL);
  2687. }
  2688. CONFIGRET
  2689. CM_Get_Class_NameA(
  2690. IN LPGUID ClassGuid,
  2691. OUT PCHAR Buffer,
  2692. IN OUT PULONG pulLength,
  2693. IN ULONG ulFlags
  2694. )
  2695. {
  2696. return CM_Get_Class_Name_ExA(ClassGuid, Buffer, pulLength, ulFlags, NULL);
  2697. }
  2698. CONFIGRET
  2699. CM_Get_Class_Key_NameA(
  2700. IN LPGUID ClassGuid,
  2701. OUT LPSTR pszKeyName,
  2702. IN OUT PULONG pulLength,
  2703. IN ULONG ulFlags
  2704. )
  2705. {
  2706. return CM_Get_Class_Key_Name_ExA(ClassGuid, pszKeyName, pulLength,
  2707. ulFlags, NULL);
  2708. }
  2709. CONFIGRET
  2710. CM_Get_Class_Key_NameW(
  2711. IN LPGUID ClassGuid,
  2712. OUT LPWSTR pszKeyName,
  2713. IN OUT PULONG pulLength,
  2714. IN ULONG ulFlags
  2715. )
  2716. {
  2717. return CM_Get_Class_Key_Name_ExW(ClassGuid, pszKeyName, pulLength,
  2718. ulFlags, NULL);
  2719. }
  2720. CONFIGRET
  2721. CM_Delete_Class_Key(
  2722. IN LPGUID ClassGuid,
  2723. IN ULONG ulFlags
  2724. )
  2725. {
  2726. return CM_Delete_Class_Key_Ex(ClassGuid, ulFlags, NULL);
  2727. }
  2728. CMAPI
  2729. CONFIGRET
  2730. WINAPI
  2731. CM_Get_Device_Interface_AliasA(
  2732. IN LPCSTR pszDeviceInterface,
  2733. IN LPGUID AliasInterfaceGuid,
  2734. OUT LPSTR pszAliasDeviceInterface,
  2735. IN OUT PULONG pulLength,
  2736. IN ULONG ulFlags
  2737. )
  2738. {
  2739. return CM_Get_Device_Interface_Alias_ExA(pszDeviceInterface, AliasInterfaceGuid,
  2740. pszAliasDeviceInterface, pulLength,
  2741. ulFlags, NULL);
  2742. }
  2743. CMAPI
  2744. CONFIGRET
  2745. WINAPI
  2746. CM_Get_Device_Interface_AliasW(
  2747. IN LPCWSTR pszDeviceInterface,
  2748. IN LPGUID AliasInterfaceGuid,
  2749. OUT LPWSTR pszAliasDeviceInterface,
  2750. IN OUT PULONG pulLength,
  2751. IN ULONG ulFlags
  2752. )
  2753. {
  2754. return CM_Get_Device_Interface_Alias_ExW(pszDeviceInterface, AliasInterfaceGuid,
  2755. pszAliasDeviceInterface, pulLength,
  2756. ulFlags, NULL);
  2757. }
  2758. CMAPI
  2759. CONFIGRET
  2760. WINAPI
  2761. CM_Get_Device_Interface_ListA(
  2762. IN LPGUID InterfaceClassGuid,
  2763. IN DEVINSTID_A pDeviceID OPTIONAL,
  2764. OUT PCHAR Buffer,
  2765. IN ULONG BufferLen,
  2766. IN ULONG ulFlags
  2767. )
  2768. {
  2769. return CM_Get_Device_Interface_List_ExA(InterfaceClassGuid, pDeviceID, Buffer,
  2770. BufferLen, ulFlags, NULL);
  2771. }
  2772. CMAPI
  2773. CONFIGRET
  2774. WINAPI
  2775. CM_Get_Device_Interface_ListW(
  2776. IN LPGUID InterfaceClassGuid,
  2777. IN DEVINSTID_W pDeviceID OPTIONAL,
  2778. OUT PWCHAR Buffer,
  2779. IN ULONG BufferLen,
  2780. IN ULONG ulFlags
  2781. )
  2782. {
  2783. return CM_Get_Device_Interface_List_ExW(InterfaceClassGuid, pDeviceID, Buffer,
  2784. BufferLen, ulFlags, NULL);
  2785. }
  2786. CMAPI
  2787. CONFIGRET
  2788. WINAPI
  2789. CM_Get_Device_Interface_List_SizeA(
  2790. IN PULONG pulLen,
  2791. IN LPGUID InterfaceClassGuid,
  2792. IN DEVINSTID_A pDeviceID OPTIONAL,
  2793. IN ULONG ulFlags
  2794. )
  2795. {
  2796. return CM_Get_Device_Interface_List_Size_ExA(pulLen, InterfaceClassGuid,
  2797. pDeviceID, ulFlags, NULL);
  2798. }
  2799. CMAPI
  2800. CONFIGRET
  2801. WINAPI
  2802. CM_Get_Device_Interface_List_SizeW(
  2803. IN PULONG pulLen,
  2804. IN LPGUID InterfaceClassGuid,
  2805. IN DEVINSTID_W pDeviceID OPTIONAL,
  2806. IN ULONG ulFlags
  2807. )
  2808. {
  2809. return CM_Get_Device_Interface_List_Size_ExW(pulLen, InterfaceClassGuid,
  2810. pDeviceID, ulFlags, NULL);
  2811. }
  2812. CMAPI
  2813. CONFIGRET
  2814. WINAPI
  2815. CM_Register_Device_InterfaceA(
  2816. IN DEVINST dnDevInst,
  2817. IN LPGUID InterfaceClassGuid,
  2818. IN LPCSTR pszReference OPTIONAL,
  2819. OUT LPSTR pszDeviceInterface,
  2820. IN OUT PULONG pulLength,
  2821. IN ULONG ulFlags
  2822. )
  2823. {
  2824. return CM_Register_Device_Interface_ExA(dnDevInst, InterfaceClassGuid,
  2825. pszReference, pszDeviceInterface,
  2826. pulLength, ulFlags, NULL);
  2827. }
  2828. CMAPI
  2829. CONFIGRET
  2830. WINAPI
  2831. CM_Register_Device_InterfaceW(
  2832. IN DEVINST dnDevInst,
  2833. IN LPGUID InterfaceClassGuid,
  2834. IN LPCWSTR pszReference OPTIONAL,
  2835. OUT LPWSTR pszDeviceInterface,
  2836. IN OUT PULONG pulLength,
  2837. IN ULONG ulFlags
  2838. )
  2839. {
  2840. return CM_Register_Device_Interface_ExW(dnDevInst, InterfaceClassGuid,
  2841. pszReference, pszDeviceInterface,
  2842. pulLength, ulFlags, NULL);
  2843. }
  2844. CMAPI
  2845. CONFIGRET
  2846. WINAPI
  2847. CM_Unregister_Device_InterfaceA(
  2848. IN LPCSTR pszDeviceInterface,
  2849. IN ULONG ulFlags
  2850. )
  2851. {
  2852. return CM_Unregister_Device_Interface_ExA(pszDeviceInterface, ulFlags, NULL);
  2853. }
  2854. CMAPI
  2855. CONFIGRET
  2856. WINAPI
  2857. CM_Unregister_Device_InterfaceW(
  2858. IN LPCWSTR pszDeviceInterface,
  2859. IN ULONG ulFlags
  2860. )
  2861. {
  2862. return CM_Unregister_Device_Interface_ExW(pszDeviceInterface, ulFlags, NULL);
  2863. }
  2864. CMAPI
  2865. CONFIGRET
  2866. WINAPI
  2867. CM_Get_DevNode_Custom_PropertyW(
  2868. IN DEVINST dnDevInst,
  2869. IN PCWSTR pszCustomPropertyName,
  2870. OUT PULONG pulRegDataType OPTIONAL,
  2871. OUT PVOID Buffer OPTIONAL,
  2872. IN OUT PULONG pulLength,
  2873. IN ULONG ulFlags
  2874. )
  2875. {
  2876. return CM_Get_DevNode_Custom_Property_ExW(dnDevInst,
  2877. pszCustomPropertyName,
  2878. pulRegDataType,
  2879. Buffer,
  2880. pulLength,
  2881. ulFlags,
  2882. NULL
  2883. );
  2884. }
  2885. CMAPI
  2886. CONFIGRET
  2887. WINAPI
  2888. CM_Get_DevNode_Custom_PropertyA(
  2889. IN DEVINST dnDevInst,
  2890. IN PCSTR pszCustomPropertyName,
  2891. OUT PULONG pulRegDataType OPTIONAL,
  2892. OUT PVOID Buffer OPTIONAL,
  2893. IN OUT PULONG pulLength,
  2894. IN ULONG ulFlags
  2895. )
  2896. {
  2897. return CM_Get_DevNode_Custom_Property_ExA(dnDevInst,
  2898. pszCustomPropertyName,
  2899. pulRegDataType,
  2900. Buffer,
  2901. pulLength,
  2902. ulFlags,
  2903. NULL
  2904. );
  2905. }
  2906. //-------------------------------------------------------------------
  2907. // ANSI STUBS
  2908. //-------------------------------------------------------------------
  2909. CONFIGRET
  2910. CM_Get_DevNode_Registry_Property_ExA(
  2911. IN DEVINST dnDevInst,
  2912. IN ULONG ulProperty,
  2913. OUT PULONG pulRegDataType OPTIONAL,
  2914. OUT PVOID Buffer OPTIONAL,
  2915. IN OUT PULONG pulLength,
  2916. IN ULONG ulFlags,
  2917. IN HMACHINE hMachine
  2918. )
  2919. {
  2920. CONFIGRET Status = CR_SUCCESS;
  2921. ULONG ulDataType, UniLen;
  2922. PWSTR pUniBuffer;
  2923. //
  2924. // validate essential parameters only
  2925. //
  2926. if (!ARGUMENT_PRESENT(pulLength)) {
  2927. return CR_INVALID_POINTER;
  2928. }
  2929. //
  2930. // examine datatype to see if need to convert return data
  2931. //
  2932. ulDataType = GetPropertyDataType(ulProperty);
  2933. //
  2934. // for all string type registry properties, we pass a Unicode buffer and
  2935. // convert back to caller's ANSI buffer on return. since the Unicode ->
  2936. // ANSI conversion may involve DBCS chars, we can't make any assumptions
  2937. // about the size of the required ANSI buffer relative to the size of the
  2938. // require Unicode buffer, so we must always get the Unicode string buffer
  2939. // and convert it whether a buffer was actually supplied by the caller or
  2940. // not.
  2941. //
  2942. if (ulDataType == REG_SZ ||
  2943. ulDataType == REG_MULTI_SZ ||
  2944. ulDataType == REG_EXPAND_SZ) {
  2945. //
  2946. // first, call the Wide version with a zero-length buffer to retrieve
  2947. // the size required for the Unicode property.
  2948. //
  2949. UniLen = 0;
  2950. Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
  2951. ulProperty,
  2952. pulRegDataType,
  2953. NULL,
  2954. &UniLen,
  2955. ulFlags,
  2956. hMachine);
  2957. if (Status != CR_BUFFER_SMALL) {
  2958. return Status;
  2959. }
  2960. //
  2961. // allocate the required buffer.
  2962. //
  2963. pUniBuffer = pSetupMalloc(UniLen);
  2964. if (pUniBuffer == NULL) {
  2965. return CR_OUT_OF_MEMORY;
  2966. }
  2967. //
  2968. // call the Wide version to retrieve the Unicode property.
  2969. //
  2970. Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
  2971. ulProperty,
  2972. pulRegDataType,
  2973. pUniBuffer,
  2974. &UniLen,
  2975. ulFlags,
  2976. hMachine);
  2977. //
  2978. // We specifically allocated the buffer of the required size, so it
  2979. // should always be large enough.
  2980. //
  2981. ASSERT(Status != CR_BUFFER_SMALL);
  2982. if (Status == CR_SUCCESS) {
  2983. //
  2984. // do the ANSI conversion or retrieve the ANSI buffer size required.
  2985. // this may be a single-sz or multi-sz string, so we pass in the
  2986. // length, and let PnPUnicodeToMultiByte convert the entire buffer.
  2987. //
  2988. Status = PnPUnicodeToMultiByte(pUniBuffer,
  2989. UniLen,
  2990. Buffer,
  2991. pulLength);
  2992. }
  2993. pSetupFree(pUniBuffer);
  2994. } else {
  2995. //
  2996. // for the non-string registry data types, just pass call on through to
  2997. // the Wide version
  2998. //
  2999. Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
  3000. ulProperty,
  3001. pulRegDataType,
  3002. Buffer,
  3003. pulLength,
  3004. ulFlags,
  3005. hMachine);
  3006. }
  3007. return Status;
  3008. } // CM_Get_DevNode_Registry_Property_ExA
  3009. CONFIGRET
  3010. CM_Set_DevNode_Registry_Property_ExA(
  3011. IN DEVINST dnDevInst,
  3012. IN ULONG ulProperty,
  3013. IN PCVOID Buffer OPTIONAL,
  3014. IN ULONG ulLength,
  3015. IN ULONG ulFlags,
  3016. IN HMACHINE hMachine
  3017. )
  3018. {
  3019. CONFIGRET Status = CR_SUCCESS;
  3020. ULONG ulDataType = 0, UniSize = 0, UniBufferSize = 0;
  3021. PWSTR pUniBuffer = NULL, pUniString = NULL, pUniNext = NULL;
  3022. PSTR pAnsiString = NULL;
  3023. //
  3024. // validate essential parameters only
  3025. //
  3026. if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
  3027. return CR_INVALID_POINTER;
  3028. }
  3029. if (!ARGUMENT_PRESENT(Buffer)) {
  3030. //
  3031. // No need to convert the parameter
  3032. //
  3033. return CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
  3034. ulProperty,
  3035. Buffer,
  3036. ulLength,
  3037. ulFlags,
  3038. hMachine);
  3039. }
  3040. //
  3041. // examine datatype to see if need to convert input buffer
  3042. //
  3043. ulDataType = GetPropertyDataType(ulProperty);
  3044. if (ulDataType == REG_SZ || ulDataType == REG_EXPAND_SZ) {
  3045. //
  3046. // convert buffer string data to unicode and pass to wide version
  3047. //
  3048. if (pSetupCaptureAndConvertAnsiArg(Buffer, &pUniBuffer) == NO_ERROR) {
  3049. UniSize = (lstrlen(pUniBuffer)+1) * sizeof(WCHAR);
  3050. Status = CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
  3051. ulProperty,
  3052. pUniBuffer,
  3053. UniSize,
  3054. ulFlags,
  3055. hMachine);
  3056. pSetupFree(pUniBuffer);
  3057. } else {
  3058. Status = CR_INVALID_DATA;
  3059. }
  3060. } else if (ulDataType == REG_MULTI_SZ) {
  3061. //
  3062. // must convert the multi_sz list to unicode first
  3063. //
  3064. UniBufferSize = ulLength * sizeof(WCHAR);
  3065. pUniBuffer = pSetupMalloc(UniBufferSize);
  3066. if (pUniBuffer == NULL) {
  3067. return CR_OUT_OF_MEMORY;
  3068. }
  3069. for (pAnsiString = (PSTR)Buffer, pUniNext = pUniBuffer;
  3070. *pAnsiString;
  3071. pAnsiString += lstrlenA(pAnsiString) + 1) {
  3072. if (pSetupCaptureAndConvertAnsiArg(pAnsiString, &pUniString) == NO_ERROR) {
  3073. UniSize += (lstrlen(pUniString)+1) * sizeof(WCHAR);
  3074. if (UniSize >= UniBufferSize) {
  3075. pSetupFree(pUniString);
  3076. pSetupFree(pUniBuffer);
  3077. return CR_INVALID_DATA;
  3078. }
  3079. lstrcpy(pUniNext, pUniString);
  3080. pUniNext += lstrlen(pUniNext) + 1;
  3081. pSetupFree(pUniString);
  3082. } else {
  3083. pSetupFree(pUniBuffer);
  3084. return CR_INVALID_DATA;
  3085. }
  3086. }
  3087. *(pUniNext++) = L'\0'; // add second null term
  3088. Status = CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
  3089. ulProperty,
  3090. pUniBuffer,
  3091. UniBufferSize,
  3092. ulFlags,
  3093. hMachine);
  3094. pSetupFree(pUniBuffer);
  3095. } else {
  3096. Status = CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
  3097. ulProperty,
  3098. Buffer,
  3099. ulLength,
  3100. ulFlags,
  3101. hMachine);
  3102. }
  3103. return Status;
  3104. } // CM_Set_DevNode_Registry_Property_ExA
  3105. CONFIGRET
  3106. CM_Get_Class_Registry_PropertyA(
  3107. IN LPGUID pClassGuid,
  3108. IN ULONG ulProperty,
  3109. OUT PULONG pulRegDataType OPTIONAL,
  3110. OUT PVOID Buffer OPTIONAL,
  3111. IN OUT PULONG pulLength,
  3112. IN ULONG ulFlags,
  3113. IN HMACHINE hMachine
  3114. )
  3115. {
  3116. CONFIGRET Status = CR_SUCCESS;
  3117. ULONG ulDataType, UniLen;
  3118. PWSTR pUniBuffer;
  3119. //
  3120. // validate essential parameters only
  3121. //
  3122. if (!ARGUMENT_PRESENT(pulLength)) {
  3123. return CR_INVALID_POINTER;
  3124. }
  3125. //
  3126. // examine datatype to see if need to convert return data
  3127. //
  3128. ulDataType = GetPropertyDataType(ulProperty);
  3129. //
  3130. // for all string type registry properties, we pass a Unicode buffer and
  3131. // convert back to caller's ANSI buffer on return. since the Unicode ->
  3132. // ANSI conversion may involve DBCS chars, we can't make any assumptions
  3133. // about the size of the required ANSI buffer relative to the size of the
  3134. // require Unicode buffer, so we must always get the Unicode string buffer
  3135. // and convert it whether a buffer was actually supplied by the caller or
  3136. // not.
  3137. //
  3138. if (ulDataType == REG_SZ ||
  3139. ulDataType == REG_MULTI_SZ ||
  3140. ulDataType == REG_EXPAND_SZ) {
  3141. //
  3142. // first, call the Wide version with a zero-length buffer to retrieve
  3143. // the size required for the Unicode property.
  3144. //
  3145. UniLen = 0;
  3146. Status = CM_Get_Class_Registry_PropertyW(pClassGuid,
  3147. ulProperty,
  3148. pulRegDataType,
  3149. NULL,
  3150. &UniLen,
  3151. ulFlags,
  3152. hMachine);
  3153. if (Status != CR_BUFFER_SMALL) {
  3154. return Status;
  3155. }
  3156. //
  3157. // allocate the required buffer.
  3158. //
  3159. pUniBuffer = pSetupMalloc(UniLen);
  3160. if (pUniBuffer == NULL) {
  3161. return CR_OUT_OF_MEMORY;
  3162. }
  3163. //
  3164. // call the Wide version to retrieve the Unicode property.
  3165. //
  3166. Status = CM_Get_Class_Registry_PropertyW(pClassGuid,
  3167. ulProperty,
  3168. pulRegDataType,
  3169. pUniBuffer,
  3170. &UniLen,
  3171. ulFlags,
  3172. hMachine);
  3173. //
  3174. // We specifically allocated the buffer of the required size, so it
  3175. // should always be large enough.
  3176. //
  3177. ASSERT(Status != CR_BUFFER_SMALL);
  3178. if (Status == CR_SUCCESS) {
  3179. //
  3180. // do the ANSI conversion or retrieve the ANSI buffer size required.
  3181. // this may be a single-sz or multi-sz string, so we pass in the
  3182. // length, and let PnPUnicodeToMultiByte convert the entire buffer.
  3183. //
  3184. Status = PnPUnicodeToMultiByte(pUniBuffer,
  3185. UniLen,
  3186. Buffer,
  3187. pulLength);
  3188. }
  3189. pSetupFree(pUniBuffer);
  3190. } else {
  3191. //
  3192. // for the non-string registry data types, just pass call
  3193. // on through to the Wide version
  3194. //
  3195. Status = CM_Get_Class_Registry_PropertyW(pClassGuid,
  3196. ulProperty,
  3197. pulRegDataType,
  3198. Buffer,
  3199. pulLength,
  3200. ulFlags,
  3201. hMachine);
  3202. }
  3203. return Status;
  3204. } // CM_Get_Class_Registry_PropertyA
  3205. CONFIGRET
  3206. CM_Set_Class_Registry_PropertyA(
  3207. IN LPGUID pClassGuid,
  3208. IN ULONG ulProperty,
  3209. IN PCVOID Buffer OPTIONAL,
  3210. IN ULONG ulLength,
  3211. IN ULONG ulFlags,
  3212. IN HMACHINE hMachine
  3213. )
  3214. {
  3215. CONFIGRET Status = CR_SUCCESS;
  3216. ULONG ulDataType = 0, UniSize = 0, UniBufferSize = 0;
  3217. PWSTR pUniBuffer = NULL, pUniString = NULL, pUniNext = NULL;
  3218. PSTR pAnsiString = NULL;
  3219. //
  3220. // validate essential parameters only
  3221. //
  3222. if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
  3223. return CR_INVALID_POINTER;
  3224. }
  3225. if (!ARGUMENT_PRESENT(Buffer)) {
  3226. //
  3227. // No need to convert the parameter
  3228. //
  3229. return CM_Set_Class_Registry_PropertyW(pClassGuid,
  3230. ulProperty,
  3231. Buffer,
  3232. ulLength,
  3233. ulFlags,
  3234. hMachine);
  3235. }
  3236. //
  3237. // examine datatype to see if need to convert input buffer
  3238. //
  3239. ulDataType = GetPropertyDataType(ulProperty);
  3240. if (ulDataType == REG_SZ || ulDataType == REG_EXPAND_SZ) {
  3241. //
  3242. // convert buffer string data to unicode and pass to wide version
  3243. //
  3244. if (pSetupCaptureAndConvertAnsiArg(Buffer, &pUniBuffer) == NO_ERROR) {
  3245. UniSize = (lstrlen(pUniBuffer)+1) * sizeof(WCHAR);
  3246. Status = CM_Set_Class_Registry_PropertyW(pClassGuid,
  3247. ulProperty,
  3248. pUniBuffer,
  3249. UniSize,
  3250. ulFlags,
  3251. hMachine);
  3252. pSetupFree(pUniBuffer);
  3253. } else {
  3254. Status = CR_INVALID_DATA;
  3255. }
  3256. } else if (ulDataType == REG_MULTI_SZ) {
  3257. //
  3258. // must convert the multi_sz list to unicode first
  3259. //
  3260. UniBufferSize = ulLength * sizeof(WCHAR);
  3261. pUniBuffer = pSetupMalloc(UniBufferSize);
  3262. if (pUniBuffer == NULL) {
  3263. return CR_OUT_OF_MEMORY;
  3264. }
  3265. for (pAnsiString = (PSTR)Buffer, pUniNext = pUniBuffer;
  3266. *pAnsiString;
  3267. pAnsiString += lstrlenA(pAnsiString) + 1) {
  3268. if (pSetupCaptureAndConvertAnsiArg(pAnsiString, &pUniString) == NO_ERROR) {
  3269. UniSize += (lstrlen(pUniString)+1) * sizeof(WCHAR);
  3270. if (UniSize >= UniBufferSize) {
  3271. pSetupFree(pUniString);
  3272. pSetupFree(pUniBuffer);
  3273. return CR_INVALID_DATA;
  3274. }
  3275. lstrcpy(pUniNext, pUniString);
  3276. pUniNext += lstrlen(pUniNext) + 1;
  3277. pSetupFree(pUniString);
  3278. } else {
  3279. pSetupFree(pUniBuffer);
  3280. return CR_INVALID_DATA;
  3281. }
  3282. }
  3283. *(pUniNext++) = L'\0'; // add second null term
  3284. Status = CM_Set_Class_Registry_PropertyW(pClassGuid,
  3285. ulProperty,
  3286. pUniBuffer,
  3287. UniBufferSize,
  3288. ulFlags,
  3289. hMachine);
  3290. pSetupFree(pUniBuffer);
  3291. } else {
  3292. Status = CM_Set_Class_Registry_PropertyW(pClassGuid,
  3293. ulProperty,
  3294. Buffer,
  3295. ulLength,
  3296. ulFlags,
  3297. hMachine);
  3298. }
  3299. return Status;
  3300. } // CM_Set_Class_Registry_Property_ExA
  3301. CONFIGRET
  3302. CM_Open_Class_Key_ExA(
  3303. IN LPGUID ClassGuid OPTIONAL,
  3304. IN LPCSTR pszClassName OPTIONAL,
  3305. IN REGSAM samDesired,
  3306. IN REGDISPOSITION Disposition,
  3307. OUT PHKEY phkClass,
  3308. IN ULONG ulFlags,
  3309. IN HMACHINE hMachine
  3310. )
  3311. {
  3312. CONFIGRET Status = CR_SUCCESS;
  3313. PWSTR pUniClassName = NULL;
  3314. if (ARGUMENT_PRESENT(pszClassName)) {
  3315. if (pSetupCaptureAndConvertAnsiArg(pszClassName, &pUniClassName) != NO_ERROR) {
  3316. return CR_INVALID_DATA;
  3317. }
  3318. }
  3319. Status = CM_Open_Class_Key_ExW(ClassGuid,
  3320. pUniClassName,
  3321. samDesired,
  3322. Disposition,
  3323. phkClass,
  3324. ulFlags,
  3325. hMachine);
  3326. if (pUniClassName) {
  3327. pSetupFree(pUniClassName);
  3328. }
  3329. return Status;
  3330. } // CM_Open_Class_Key_ExA
  3331. CONFIGRET
  3332. CM_Get_Class_Name_ExA(
  3333. IN LPGUID ClassGuid,
  3334. OUT PCHAR Buffer,
  3335. IN OUT PULONG pulLength,
  3336. IN ULONG ulFlags,
  3337. IN HMACHINE hMachine
  3338. )
  3339. {
  3340. CONFIGRET Status = CR_SUCCESS;
  3341. WCHAR UniBuffer[MAX_CLASS_NAME_LEN];
  3342. ULONG UniLen = MAX_CLASS_NAME_LEN;
  3343. //
  3344. // validate essential parameters only
  3345. //
  3346. if ((!ARGUMENT_PRESENT(Buffer)) ||
  3347. (!ARGUMENT_PRESENT(pulLength))) {
  3348. return CR_INVALID_POINTER;
  3349. }
  3350. //
  3351. // call the wide version, passing a unicode buffer as a parameter
  3352. //
  3353. Status = CM_Get_Class_Name_ExW(ClassGuid,
  3354. UniBuffer,
  3355. &UniLen,
  3356. ulFlags,
  3357. hMachine);
  3358. //
  3359. // We should never return a class name longer than MAX_CLASS_NAME_LEN.
  3360. //
  3361. ASSERT(Status != CR_BUFFER_SMALL);
  3362. //
  3363. // convert the unicode buffer to an ansi string and copy to the
  3364. // caller's buffer
  3365. //
  3366. if (Status == CR_SUCCESS) {
  3367. Status = PnPUnicodeToMultiByte(UniBuffer,
  3368. (lstrlenW(UniBuffer)+1)*sizeof(WCHAR),
  3369. Buffer,
  3370. pulLength);
  3371. }
  3372. return Status;
  3373. } // CM_Get_Class_Name_ExA
  3374. CONFIGRET
  3375. CM_Get_Class_Key_Name_ExA(
  3376. IN LPGUID ClassGuid,
  3377. OUT LPSTR pszKeyName,
  3378. IN OUT PULONG pulLength,
  3379. IN ULONG ulFlags,
  3380. IN HMACHINE hMachine
  3381. )
  3382. {
  3383. CONFIGRET Status = CR_SUCCESS;
  3384. WCHAR UniBuffer[MAX_GUID_STRING_LEN];
  3385. ULONG UniLen = MAX_GUID_STRING_LEN;
  3386. //
  3387. // validate essential parameters only
  3388. //
  3389. if ((!ARGUMENT_PRESENT(pszKeyName)) ||
  3390. (!ARGUMENT_PRESENT(pulLength))) {
  3391. return CR_INVALID_POINTER;
  3392. }
  3393. //
  3394. // call the wide version, passing a unicode buffer as a parameter
  3395. //
  3396. Status = CM_Get_Class_Key_Name_ExW(ClassGuid,
  3397. UniBuffer,
  3398. &UniLen,
  3399. ulFlags,
  3400. hMachine);
  3401. //
  3402. // We should never return a class key name longer than MAX_GUID_STRING_LEN.
  3403. //
  3404. ASSERT(Status != CR_BUFFER_SMALL);
  3405. //
  3406. // convert the unicode buffer to an ansi string and copy to the
  3407. // caller's buffer
  3408. //
  3409. if (Status == CR_SUCCESS) {
  3410. Status = PnPUnicodeToMultiByte(UniBuffer,
  3411. (lstrlenW(UniBuffer)+1)*sizeof(WCHAR),
  3412. pszKeyName,
  3413. pulLength);
  3414. }
  3415. return Status;
  3416. } // CM_Get_Class_Key_Name_ExA
  3417. CMAPI
  3418. CONFIGRET
  3419. WINAPI
  3420. CM_Get_Device_Interface_Alias_ExA(
  3421. IN LPCSTR pszDeviceInterface,
  3422. IN LPGUID AliasInterfaceGuid,
  3423. OUT LPSTR pszAliasDeviceInterface,
  3424. IN OUT PULONG pulLength,
  3425. IN ULONG ulFlags,
  3426. IN HMACHINE hMachine
  3427. )
  3428. {
  3429. CONFIGRET Status = CR_SUCCESS;
  3430. PWSTR pUniDeviceInterface, pUniAliasDeviceInterface;
  3431. ULONG UniLen;
  3432. //
  3433. // validate essential parameters only
  3434. //
  3435. if ((!ARGUMENT_PRESENT(pszDeviceInterface)) ||
  3436. (!ARGUMENT_PRESENT(pszAliasDeviceInterface)) ||
  3437. (!ARGUMENT_PRESENT(pulLength))) {
  3438. return CR_INVALID_POINTER;
  3439. }
  3440. //
  3441. // convert buffer string data to unicode to pass to wide version
  3442. //
  3443. if (pSetupCaptureAndConvertAnsiArg(pszDeviceInterface, &pUniDeviceInterface) != NO_ERROR) {
  3444. return CR_INVALID_DATA;
  3445. }
  3446. //
  3447. // first, call the Wide version with a zero-length buffer to retrieve
  3448. // the size required for the Unicode property.
  3449. //
  3450. UniLen = 0;
  3451. Status = CM_Get_Device_Interface_Alias_ExW(pUniDeviceInterface,
  3452. AliasInterfaceGuid,
  3453. NULL,
  3454. &UniLen,
  3455. ulFlags,
  3456. hMachine);
  3457. if (Status != CR_BUFFER_SMALL) {
  3458. return Status;
  3459. goto Clean0;
  3460. }
  3461. //
  3462. // allocate the required buffer.
  3463. //
  3464. pUniAliasDeviceInterface = pSetupMalloc(UniLen);
  3465. if (pUniAliasDeviceInterface == NULL) {
  3466. Status = CR_OUT_OF_MEMORY;
  3467. goto Clean0;
  3468. }
  3469. //
  3470. // call the Wide version to retrieve the Unicode property.
  3471. //
  3472. Status = CM_Get_Device_Interface_Alias_ExW(pUniDeviceInterface,
  3473. AliasInterfaceGuid,
  3474. pUniAliasDeviceInterface,
  3475. &UniLen,
  3476. ulFlags,
  3477. hMachine);
  3478. //
  3479. // We specifically allocated the buffer of the required size, so it should
  3480. // always be large enough.
  3481. //
  3482. ASSERT(Status != CR_BUFFER_SMALL);
  3483. if (Status == CR_SUCCESS) {
  3484. //
  3485. // do the ANSI conversion or retrieve the ANSI buffer size required.
  3486. //
  3487. Status = PnPUnicodeToMultiByte(pUniAliasDeviceInterface,
  3488. (lstrlenW(pUniAliasDeviceInterface)+1)*sizeof(WCHAR),
  3489. pszAliasDeviceInterface,
  3490. pulLength);
  3491. }
  3492. pSetupFree(pUniAliasDeviceInterface);
  3493. Clean0:
  3494. pSetupFree(pUniDeviceInterface);
  3495. return Status;
  3496. } // CM_Get_Device_Interface_Alias_ExA
  3497. CMAPI
  3498. CONFIGRET
  3499. WINAPI
  3500. CM_Get_Device_Interface_List_ExA(
  3501. IN LPGUID InterfaceClassGuid,
  3502. IN DEVINSTID_A pDeviceID OPTIONAL,
  3503. OUT PCHAR Buffer,
  3504. IN ULONG BufferLen,
  3505. IN ULONG ulFlags,
  3506. IN HMACHINE hMachine
  3507. )
  3508. {
  3509. CONFIGRET Status = CR_SUCCESS;
  3510. PWSTR pUniBuffer, pUniDeviceID = NULL;
  3511. ULONG ulAnsiBufferLen;
  3512. //
  3513. // validate essential parameters only
  3514. //
  3515. if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
  3516. return CR_INVALID_POINTER;
  3517. }
  3518. if (ARGUMENT_PRESENT(pDeviceID)) {
  3519. //
  3520. // if a filter string was passed in, convert to UNICODE before
  3521. // passing on to the wide version
  3522. //
  3523. if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) != NO_ERROR) {
  3524. return CR_INVALID_DEVICE_ID;
  3525. }
  3526. ASSERT(pUniDeviceID != NULL);
  3527. } else {
  3528. ASSERT(pUniDeviceID == NULL);
  3529. }
  3530. //
  3531. // prepare a larger buffer to hold the unicode formatted
  3532. // multi_sz data returned by CM_Get_Device_Interface_List_ExW.
  3533. //
  3534. pUniBuffer = pSetupMalloc(BufferLen * sizeof(WCHAR));
  3535. if (pUniBuffer == NULL) {
  3536. Status = CR_OUT_OF_MEMORY;
  3537. goto Clean0;
  3538. }
  3539. *pUniBuffer = L'\0';
  3540. //
  3541. // call the wide version
  3542. //
  3543. Status = CM_Get_Device_Interface_List_ExW(InterfaceClassGuid,
  3544. pUniDeviceID,
  3545. pUniBuffer,
  3546. BufferLen, // size in chars
  3547. ulFlags,
  3548. hMachine);
  3549. //
  3550. // convert the unicode buffer to an ansi string and copy to the
  3551. // caller's buffer
  3552. //
  3553. if (Status == CR_SUCCESS) {
  3554. ulAnsiBufferLen = BufferLen;
  3555. Status = PnPUnicodeToMultiByte(pUniBuffer,
  3556. BufferLen*sizeof(WCHAR),
  3557. Buffer,
  3558. &ulAnsiBufferLen);
  3559. }
  3560. pSetupFree(pUniBuffer);
  3561. Clean0:
  3562. if (pUniDeviceID) {
  3563. pSetupFree(pUniDeviceID);
  3564. }
  3565. return Status;
  3566. } // CM_Get_Device_Interface_List_ExA
  3567. CMAPI
  3568. CONFIGRET
  3569. WINAPI
  3570. CM_Get_Device_Interface_List_Size_ExA(
  3571. IN PULONG pulLen,
  3572. IN LPGUID InterfaceClassGuid,
  3573. IN DEVINSTID_A pDeviceID OPTIONAL,
  3574. IN ULONG ulFlags,
  3575. IN HMACHINE hMachine
  3576. )
  3577. {
  3578. CONFIGRET Status = CR_SUCCESS, tmpStatus;
  3579. PWSTR pUniDeviceID = NULL, pUniDeviceInterfaceList;
  3580. ULONG UniLen;
  3581. //
  3582. // validate essential parameters only
  3583. //
  3584. if (!ARGUMENT_PRESENT(pulLen)) {
  3585. return CR_INVALID_POINTER;
  3586. }
  3587. if (ARGUMENT_PRESENT(pDeviceID)) {
  3588. //
  3589. // if a device ID string was passed in, convert to UNICODE before
  3590. // passing on to the wide version
  3591. //
  3592. if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) != NO_ERROR) {
  3593. return CR_INVALID_DEVICE_ID;
  3594. }
  3595. ASSERT(pUniDeviceID != NULL);
  3596. } else {
  3597. ASSERT(pUniDeviceID == NULL);
  3598. }
  3599. //
  3600. // first, call the Wide version to retrieve the size required for the
  3601. // Unicode device interface list.
  3602. //
  3603. UniLen = 0;
  3604. Status = CM_Get_Device_Interface_List_Size_ExW(&UniLen,
  3605. InterfaceClassGuid,
  3606. pUniDeviceID,
  3607. ulFlags,
  3608. hMachine);
  3609. if (Status != CR_SUCCESS) {
  3610. goto Clean0;
  3611. }
  3612. //
  3613. // allocate the required buffer.
  3614. //
  3615. pUniDeviceInterfaceList = pSetupMalloc(UniLen*sizeof(WCHAR));
  3616. if (pUniDeviceInterfaceList == NULL) {
  3617. Status = CR_OUT_OF_MEMORY;
  3618. goto Clean0;
  3619. }
  3620. //
  3621. // call the Wide version to retrieve the Unicode device interface list.
  3622. //
  3623. Status = CM_Get_Device_Interface_List_ExW(InterfaceClassGuid,
  3624. pUniDeviceID,
  3625. pUniDeviceInterfaceList,
  3626. UniLen,
  3627. ulFlags,
  3628. hMachine);
  3629. //
  3630. // We specifically allocated the buffer of the required size, so it should
  3631. // always be large enough.
  3632. //
  3633. ASSERT(Status != CR_BUFFER_SMALL);
  3634. if (Status == CR_SUCCESS) {
  3635. //
  3636. // retrieve the size, in bytes, of the ANSI buffer size required to
  3637. // convert this list. since this is a multi-sz string, we pass in the
  3638. // length and let PnPUnicodeToMultiByte convert the entire buffer.
  3639. //
  3640. tmpStatus = PnPUnicodeToMultiByte(pUniDeviceInterfaceList,
  3641. UniLen*sizeof(WCHAR),
  3642. NULL,
  3643. pulLen);
  3644. ASSERT(tmpStatus == CR_BUFFER_SMALL);
  3645. }
  3646. pSetupFree(pUniDeviceInterfaceList);
  3647. Clean0:
  3648. if (pUniDeviceID) {
  3649. pSetupFree(pUniDeviceID);
  3650. }
  3651. return Status;
  3652. } // CM_Get_Device_Interface_List_Size_ExA
  3653. CMAPI
  3654. CONFIGRET
  3655. WINAPI
  3656. CM_Register_Device_Interface_ExA(
  3657. IN DEVINST dnDevInst,
  3658. IN LPGUID InterfaceClassGuid,
  3659. IN LPCSTR pszReference OPTIONAL,
  3660. OUT LPSTR pszDeviceInterface,
  3661. IN OUT PULONG pulLength,
  3662. IN ULONG ulFlags,
  3663. IN HMACHINE hMachine
  3664. )
  3665. {
  3666. CONFIGRET Status = CR_SUCCESS;
  3667. PWSTR pUniReference = NULL, pUniDeviceInterface = NULL;
  3668. ULONG UniLen;
  3669. try {
  3670. //
  3671. // validate essential parameters only
  3672. //
  3673. if ((!ARGUMENT_PRESENT(pulLength)) ||
  3674. (!ARGUMENT_PRESENT(pszDeviceInterface))) {
  3675. return CR_INVALID_POINTER;
  3676. }
  3677. //
  3678. // if a device reference string was passed in, convert to Unicode before
  3679. // passing on to the wide version
  3680. //
  3681. if (ARGUMENT_PRESENT(pszReference)) {
  3682. if (pSetupCaptureAndConvertAnsiArg(pszReference, &pUniReference) != NO_ERROR) {
  3683. return CR_INVALID_DATA;
  3684. }
  3685. }
  3686. //
  3687. // pass a Unicode buffer instead and convert back to caller's ANSI buffer on
  3688. // return
  3689. //
  3690. UniLen = *pulLength;
  3691. pUniDeviceInterface = pSetupMalloc(UniLen*sizeof(WCHAR));
  3692. if (pUniDeviceInterface == NULL) {
  3693. Status = CR_OUT_OF_MEMORY;
  3694. goto Clean0;
  3695. }
  3696. Status = CM_Register_Device_Interface_ExW(dnDevInst,
  3697. InterfaceClassGuid,
  3698. pUniReference,
  3699. pUniDeviceInterface,
  3700. &UniLen,
  3701. ulFlags,
  3702. hMachine);
  3703. if (Status == CR_SUCCESS) {
  3704. //
  3705. // if the call succeeded, convert the Unicode string to ANSI
  3706. //
  3707. Status = PnPUnicodeToMultiByte(pUniDeviceInterface,
  3708. (lstrlenW(pUniDeviceInterface)+1)*sizeof(WCHAR),
  3709. pszDeviceInterface,
  3710. pulLength);
  3711. } else if (Status == CR_BUFFER_SMALL) {
  3712. //
  3713. // returned size is in chars
  3714. //
  3715. *pulLength = UniLen;
  3716. }
  3717. Clean0:
  3718. NOTHING;
  3719. } except(EXCEPTION_EXECUTE_HANDLER) {
  3720. Status = CR_FAILURE;
  3721. }
  3722. if (pUniDeviceInterface) {
  3723. pSetupFree(pUniDeviceInterface);
  3724. }
  3725. if (pUniReference) {
  3726. pSetupFree(pUniReference);
  3727. }
  3728. return Status;
  3729. } // CM_Register_Device_Interface_ExA
  3730. CMAPI
  3731. CONFIGRET
  3732. WINAPI
  3733. CM_Unregister_Device_Interface_ExA(
  3734. IN LPCSTR pszDeviceInterface,
  3735. IN ULONG ulFlags,
  3736. IN HMACHINE hMachine
  3737. )
  3738. {
  3739. CONFIGRET Status = CR_SUCCESS;
  3740. PWSTR pUniDeviceInterface = NULL;
  3741. try {
  3742. //
  3743. // validate essential parameters only
  3744. //
  3745. if (!ARGUMENT_PRESENT(pszDeviceInterface)) {
  3746. return CR_INVALID_POINTER;
  3747. }
  3748. //
  3749. // convert buffer string data to unicode and pass to wide version
  3750. //
  3751. if (pSetupCaptureAndConvertAnsiArg(pszDeviceInterface, &pUniDeviceInterface) == NO_ERROR) {
  3752. Status = CM_Unregister_Device_Interface_ExW(pUniDeviceInterface,
  3753. ulFlags,
  3754. hMachine);
  3755. } else {
  3756. Status = CR_INVALID_DATA;
  3757. }
  3758. } except(EXCEPTION_EXECUTE_HANDLER) {
  3759. Status = CR_FAILURE;
  3760. }
  3761. if (pUniDeviceInterface) {
  3762. pSetupFree(pUniDeviceInterface);
  3763. }
  3764. return Status;
  3765. } // CM_Unregister_Device_Interface_ExA
  3766. CMAPI
  3767. CONFIGRET
  3768. WINAPI
  3769. CM_Get_DevNode_Custom_Property_ExA(
  3770. IN DEVINST dnDevInst,
  3771. IN PCSTR pszCustomPropertyName,
  3772. OUT PULONG pulRegDataType OPTIONAL,
  3773. OUT PVOID Buffer OPTIONAL,
  3774. IN OUT PULONG pulLength,
  3775. IN ULONG ulFlags,
  3776. IN HMACHINE hMachine
  3777. )
  3778. {
  3779. DWORD Win32Status;
  3780. CONFIGRET Status = CR_SUCCESS;
  3781. PWSTR UnicodeCustomPropName = NULL;
  3782. DWORD UniLen;
  3783. PBYTE pUniBuffer = NULL;
  3784. PSTR pAnsiBuffer = NULL;
  3785. ULONG ulDataType;
  3786. ULONG ulAnsiBufferLen;
  3787. PWSTR pUniString;
  3788. try {
  3789. //
  3790. // Validate parameters not validated by upcoming call to Unicode API
  3791. // (CM_Get_DevNode_Registry_Property_ExW).
  3792. //
  3793. if(!ARGUMENT_PRESENT(pulLength)) {
  3794. Status = CR_INVALID_POINTER;
  3795. goto Clean0;
  3796. }
  3797. if((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
  3798. Status = CR_INVALID_POINTER;
  3799. goto Clean0;
  3800. }
  3801. if(pszCustomPropertyName) {
  3802. //
  3803. // Convert property name to Unicode.
  3804. //
  3805. Win32Status = pSetupCaptureAndConvertAnsiArg(pszCustomPropertyName,
  3806. &UnicodeCustomPropName
  3807. );
  3808. if(Win32Status != NO_ERROR) {
  3809. //
  3810. // This routine guarantees that the returned unicode string
  3811. // pointer will be null upon failure, so we don't have to reset
  3812. // it here--just bail.
  3813. //
  3814. if(Win32Status == ERROR_NOT_ENOUGH_MEMORY) {
  3815. Status = CR_OUT_OF_MEMORY;
  3816. } else {
  3817. Status = CR_INVALID_POINTER;
  3818. }
  3819. goto Clean0;
  3820. }
  3821. } else {
  3822. Status = CR_INVALID_POINTER;
  3823. goto Clean0;
  3824. }
  3825. //
  3826. // Unfortunately, we have no clue as to whether or not the requested
  3827. // property is a string (thus requiring conversion from Unicode to
  3828. // ANSI). Therefore, we'll retrieve the data (if any) in its entirety,
  3829. // then convert to ANSI if necessary. Only then can we determine the
  3830. // data size (and whether it can be returned to the caller).
  3831. //
  3832. // Start out with a reasonable guess as to buffer size in an attempt to
  3833. // avoid calling the Unicode get-property API twice...
  3834. //
  3835. UniLen = 1024;
  3836. do {
  3837. pUniBuffer = pSetupMalloc(UniLen);
  3838. if(!pUniBuffer) {
  3839. Status = CR_OUT_OF_MEMORY;
  3840. goto Clean0;
  3841. }
  3842. Status = CM_Get_DevNode_Custom_Property_ExW(dnDevInst,
  3843. UnicodeCustomPropName,
  3844. &ulDataType,
  3845. pUniBuffer,
  3846. &UniLen,
  3847. ulFlags,
  3848. hMachine
  3849. );
  3850. if(Status != CR_SUCCESS) {
  3851. pSetupFree(pUniBuffer);
  3852. pUniBuffer = NULL;
  3853. }
  3854. } while(Status == CR_BUFFER_SMALL);
  3855. if(Status != CR_SUCCESS) {
  3856. goto Clean0;
  3857. }
  3858. //
  3859. // If we get to here, we successfully retrieved the property.
  3860. //
  3861. if(pulRegDataType) {
  3862. *pulRegDataType = ulDataType;
  3863. }
  3864. if(UniLen == 0) {
  3865. //
  3866. // We retrieved an empty buffer--no need to worry about
  3867. // transferring any data into caller's buffer.
  3868. //
  3869. *pulLength = 0;
  3870. goto Clean0;
  3871. }
  3872. switch(ulDataType) {
  3873. case REG_MULTI_SZ :
  3874. case REG_SZ :
  3875. case REG_EXPAND_SZ :
  3876. //
  3877. // Worst case, an ANSI buffer large enough to hold the results
  3878. // would be the same size as the Unicode results.
  3879. //
  3880. pAnsiBuffer = pSetupMalloc(UniLen);
  3881. if(!pAnsiBuffer) {
  3882. Status = CR_OUT_OF_MEMORY;
  3883. goto Clean0;
  3884. }
  3885. //
  3886. // do the ANSI conversion or retrieve the ANSI buffer size required.
  3887. // this may be a single-sz or multi-sz string, so we pass in the
  3888. // length, and let PnPUnicodeToMultiByte convert the entire buffer.
  3889. //
  3890. ulAnsiBufferLen = *pulLength;
  3891. Status = PnPUnicodeToMultiByte((PWSTR)pUniBuffer,
  3892. UniLen,
  3893. pAnsiBuffer,
  3894. &ulAnsiBufferLen);
  3895. if(ulAnsiBufferLen > *pulLength) {
  3896. ASSERT(Status == CR_BUFFER_SMALL);
  3897. Status = CR_BUFFER_SMALL;
  3898. } else {
  3899. //
  3900. // Copy ANSI string(s) into caller's buffer.
  3901. //
  3902. CopyMemory(Buffer, pAnsiBuffer, ulAnsiBufferLen);
  3903. }
  3904. *pulLength = ulAnsiBufferLen;
  3905. break;
  3906. default :
  3907. //
  3908. // buffer doesn't contain text, no conversion necessary.
  3909. //
  3910. if(UniLen > *pulLength) {
  3911. Status = CR_BUFFER_SMALL;
  3912. } else {
  3913. CopyMemory(Buffer, pUniBuffer, UniLen);
  3914. }
  3915. *pulLength = UniLen;
  3916. }
  3917. Clean0:
  3918. NOTHING;
  3919. } except(EXCEPTION_EXECUTE_HANDLER) {
  3920. Status = CR_FAILURE;
  3921. //
  3922. // Reference the following variables so the compiler will respect
  3923. // statement ordering w.r.t. their assignment.
  3924. //
  3925. pUniBuffer = pUniBuffer;
  3926. pAnsiBuffer = pAnsiBuffer;
  3927. }
  3928. if(UnicodeCustomPropName) {
  3929. pSetupFree(UnicodeCustomPropName);
  3930. }
  3931. if(pUniBuffer) {
  3932. pSetupFree(pUniBuffer);
  3933. }
  3934. if(pAnsiBuffer) {
  3935. pSetupFree(pAnsiBuffer);
  3936. }
  3937. return Status;
  3938. } // CM_Get_DevNode_Custom_Property_ExA
  3939. //-------------------------------------------------------------------
  3940. // Private utility routines
  3941. //-------------------------------------------------------------------
  3942. ULONG
  3943. GetPropertyDataType(
  3944. IN ULONG ulProperty)
  3945. /*++
  3946. Routine Description:
  3947. This routine takes a property ID and returns the registry data type that
  3948. is used to store this property data (i.e., REG_SZ, etc).
  3949. Parameters:
  3950. ulProperty Property ID (one of the CM_DRP_* defines)
  3951. Return Value:
  3952. Returns one of the predefined registry data types, REG_BINARY is the default.
  3953. --*/
  3954. {
  3955. switch(ulProperty) {
  3956. case CM_DRP_DEVICEDESC:
  3957. case CM_DRP_SERVICE:
  3958. case CM_DRP_CLASS:
  3959. case CM_DRP_CLASSGUID:
  3960. case CM_DRP_DRIVER:
  3961. case CM_DRP_MFG:
  3962. case CM_DRP_FRIENDLYNAME:
  3963. case CM_DRP_LOCATION_INFORMATION:
  3964. case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
  3965. case CM_DRP_ENUMERATOR_NAME:
  3966. case CM_DRP_SECURITY_SDS: // and CM_CRP_SECURITY_SDS
  3967. case CM_DRP_UI_NUMBER_DESC_FORMAT:
  3968. return REG_SZ;
  3969. case CM_DRP_HARDWAREID:
  3970. case CM_DRP_COMPATIBLEIDS:
  3971. case CM_DRP_UPPERFILTERS:
  3972. case CM_DRP_LOWERFILTERS:
  3973. return REG_MULTI_SZ;
  3974. case CM_DRP_CONFIGFLAGS:
  3975. case CM_DRP_CAPABILITIES:
  3976. case CM_DRP_UI_NUMBER:
  3977. case CM_DRP_LEGACYBUSTYPE:
  3978. case CM_DRP_BUSNUMBER:
  3979. case CM_DRP_CHARACTERISTICS: // and CM_CRP_CHARACTERISTICS
  3980. case CM_DRP_EXCLUSIVE: // and CM_CRP_EXCLUSIVE
  3981. case CM_DRP_DEVTYPE: // and CM_CRP_DEVTYPE
  3982. case CM_DRP_ADDRESS:
  3983. case CM_DRP_REMOVAL_POLICY:
  3984. case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
  3985. case CM_DRP_REMOVAL_POLICY_OVERRIDE:
  3986. case CM_DRP_INSTALL_STATE:
  3987. return REG_DWORD;
  3988. case CM_DRP_BUSTYPEGUID:
  3989. case CM_DRP_SECURITY: // and CM_CRP_SECURITY
  3990. return REG_BINARY;
  3991. case CM_DRP_DEVICE_POWER_DATA:
  3992. return REG_BINARY;
  3993. default:
  3994. //
  3995. // We should never get here!
  3996. //
  3997. ASSERT(0);
  3998. return REG_BINARY;
  3999. }
  4000. } // GetPropertyDataType