Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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