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.

2428 lines
67 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devnode.c
  5. Abstract:
  6. This module contains the API routines that operate directly on device
  7. instances (or DevNodes, in Win95 terminology).
  8. CM_Create_DevNode
  9. CM_Setup_DevNode
  10. CM_Disable_DevNode
  11. CM_Enable_DevNode
  12. CM_Get_DevNode_Status
  13. CM_Set_DevNode_Problem
  14. CM_Reenumerate_DevNode
  15. CM_Query_And_Remove_SubTree
  16. CM_Uninstall_DevNode
  17. CM_Request_Device_Eject
  18. CM_Add_ID
  19. CM_Register_Device_Driver
  20. This module also contains the following API routines which are
  21. not implemented.
  22. CM_Move_DevNode
  23. CM_Query_Remove_Subtree
  24. CM_Remove_SubTree
  25. Author:
  26. Paula Tomlinson (paulat) 6-20-1995
  27. Environment:
  28. User mode only.
  29. Revision History:
  30. 6-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 <pnpmgr.h>
  40. CONFIGRET
  41. CM_Create_DevNode_ExW(
  42. OUT PDEVINST pdnDevInst,
  43. IN DEVINSTID_W pDeviceID,
  44. IN DEVINST dnParent,
  45. IN ULONG ulFlags,
  46. IN HMACHINE hMachine
  47. )
  48. /*++
  49. Routine Description:
  50. This routine creates a new device instance in the hardware tree.
  51. Parameters:
  52. pdnDevNode Supplies the address of the variable that receives a handle
  53. to the new device instance.
  54. pDeviceID Supplies a pointer to a NULL-terminated string specifying
  55. the device instance ID for this new device instance. This
  56. is the registry path (relative to the Enum branch) where
  57. this device instance will be located (e.g., Root\*PNP0500\0000).
  58. In Windows NT, this parameter is not optional.
  59. dnParent Supplies the handle of the device instance that is the parent
  60. of the device instance being created.
  61. ulFlags Supplies flags specifying options for the creation of the
  62. device instance. May be one of the following values:
  63. CM_CREATE_DEVNODE_NORMAL
  64. Create the device instance now, and perform installation
  65. for it at a later time.
  66. CM_CREATE_DEVNODE_NO_WAIT_INSTALL
  67. Create the device instance, and perform installation for
  68. it immediately.
  69. CM_CREATE_DEVNODE_PHANTOM
  70. Create a phantom device instance (i.e., a handle to a
  71. device instance that is not alive as far as the ConfigMgr
  72. APIs are concerned). This may be used for CM APIs that
  73. require a devnode handle, but for which no real devnode
  74. currently exists (e.g., registry property APIs). This
  75. flag may not be specified with CR_CREATE_DEVNODE_NORMAL
  76. or CR_CREATE_DEVNODE_NO_WAIT_INSTALL. A phantom devnode
  77. created in this manner is not accessible to other callers
  78. (i.e., CM_Locate_DevNode won't find it). However, callers
  79. attempting to create a devnode with the same name as this
  80. phantom devnode will not be able to do so (they will get
  81. CR_ALREADY_SUCH_DEVNODE).
  82. CM_CREATE_DEVNODE_GENERATE_ID
  83. Create a Root-enumerated devnode using a unique device
  84. instance ID generated from the supplied device ID in
  85. pDeviceID. If this flag is set, then pDeviceID is assumed
  86. to contain simply a device ID (i.e., no enumerator key
  87. prefix, and no device instance suffix). A unique 4-digit,
  88. base-10 identifier string will be created under
  89. Enum\Root\<pDeviceID>, and the devnode will be created
  90. based on that device instance ID. For instance, to add a
  91. new legacy COM port devnode, this API would be called with
  92. a pDeviceID of *PNP0500. Assuming there was already one
  93. COM port instance in the registry (instance 0000), the new
  94. device instance ID would be: Root\*PNP0500\0001
  95. The caller may find out what device instance name was
  96. generated by calling CM_Get_Device_ID with the devnode
  97. returned from this API.
  98. Return Value:
  99. If the function succeeds, the return value is CR_SUCCESS.
  100. If the function fails, the return value is a CR error code.
  101. CR_ALREADY_SUCH_DEVNODE,
  102. CR_INVALID_DEVICE_ID,
  103. CR_INVALID_DEVNODE,
  104. CR_INVALID_FLAG,
  105. CR_INVALID_POINTER,
  106. CR_OUT_OF_MEMORY,
  107. CR_ACCESS_DENIED, or
  108. CR_FAILURE.
  109. --*/
  110. {
  111. CONFIGRET Status = CR_SUCCESS;
  112. WCHAR ParentID[MAX_DEVICE_ID_LEN];
  113. WCHAR szNewDeviceID[MAX_DEVICE_ID_LEN];
  114. PVOID hStringTable = NULL;
  115. handle_t hBinding = NULL;
  116. ULONG ulLen=MAX_DEVICE_ID_LEN;
  117. BOOL Success;
  118. size_t DeviceIDLen;
  119. try {
  120. //
  121. // validate parameters
  122. //
  123. if (!ARGUMENT_PRESENT(pdnDevInst)) {
  124. Status = CR_INVALID_POINTER;
  125. goto Clean0;
  126. }
  127. if (dnParent == 0) {
  128. Status = CR_INVALID_DEVINST;
  129. goto Clean0;
  130. }
  131. if (!ARGUMENT_PRESENT(pDeviceID)) {
  132. Status = CR_INVALID_DEVICE_ID;
  133. goto Clean0;
  134. }
  135. //
  136. // the length of the supplied device id string must be shorter than
  137. // MAX_DEVICE_ID_LEN chars so that there is also room for the NULL term
  138. // char in a buffer of this size. (many of the CM_ APIs make different
  139. // assumptions about the consideration of the NULL term char in
  140. // MAX_DEVICE_ID_LEN; account for the NULL term char to be safe)
  141. //
  142. if (FAILED(StringCchLength(pDeviceID,
  143. MAX_DEVICE_ID_LEN,
  144. &DeviceIDLen))) {
  145. Status = CR_INVALID_DEVICE_ID;
  146. goto Clean0;
  147. }
  148. ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
  149. if (DeviceIDLen == 0) {
  150. Status = CR_INVALID_DEVICE_ID;
  151. goto Clean0;
  152. }
  153. if (INVALID_FLAGS(ulFlags, CM_CREATE_DEVNODE_BITS)) {
  154. Status = CR_INVALID_FLAG;
  155. goto Clean0;
  156. }
  157. //
  158. // Windows NT 5.0 does not support CM_CREATE_DEVNODE_NO_WAIT_INSTALL
  159. //
  160. if (ulFlags & CM_CREATE_DEVNODE_NO_WAIT_INSTALL) {
  161. Status = CR_INVALID_FLAG;
  162. goto Clean0;
  163. }
  164. //
  165. // setup rpc binding handle and string table handle
  166. //
  167. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  168. Status = CR_FAILURE;
  169. goto Clean0;
  170. }
  171. //
  172. // Initialize the caller's devnode. This will have the side effect of
  173. // generating an exception before we actually do anything if the caller
  174. // supplied a bogus address.
  175. //
  176. *pdnDevInst = 0;
  177. //
  178. // retreive device instance string that corresponds to dnParent
  179. // (note that this is not optional, even a first level device instance
  180. // has a parent (the root device instance)
  181. //
  182. Success = pSetupStringTableStringFromIdEx(hStringTable, dnParent,ParentID,&ulLen);
  183. if (Success == FALSE || INVALID_DEVINST(ParentID)) {
  184. Status = CR_INVALID_DEVNODE;
  185. goto Clean0;
  186. }
  187. //
  188. // make sure the new device instance is properly formatted
  189. //
  190. CopyFixedUpDeviceId(szNewDeviceID,
  191. pDeviceID,
  192. (DWORD)DeviceIDLen);
  193. //
  194. // If not requesting instance generation, then it must be a
  195. // valid device instance path.
  196. //
  197. if (!(ulFlags & CM_CREATE_DEVINST_GENERATE_ID)) {
  198. if ((!*szNewDeviceID) ||
  199. (!IsLegalDeviceId(szNewDeviceID))) {
  200. Status = CR_INVALID_DEVINST;
  201. goto Clean0;
  202. }
  203. }
  204. //
  205. // Special privileges are no longer required by the server.
  206. //
  207. // Note that with previous versions of the PlugPlay RPC server,
  208. // SE_LOAD_DRIVER_PRIVILEGE was required for this operation. We do not
  209. // need to enable the privilege for local callers, since this version of
  210. // CFGMGR32 should match a local version of UMPNPMGR that does not
  211. // require the privilege. For remote calls, it's not always possible
  212. // for us to enable the privilege anyways, since the client may not have
  213. // the privilege on the local machine, but may as authenticated on the
  214. // server. The server typically sees all privileges that a remote
  215. // caller has as "enabled by default", so we are not required to enable
  216. // the privilege here either.
  217. //
  218. RpcTryExcept {
  219. //
  220. // call rpc service entry point
  221. //
  222. Status = PNP_CreateDevInst(
  223. hBinding, // rpc binding handle
  224. szNewDeviceID, // device instance to create
  225. ParentID, // parent device instance
  226. MAX_DEVICE_ID_LEN, // max length of szNewDeviceID
  227. ulFlags); // flags
  228. }
  229. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  230. KdPrintEx((DPFLTR_PNPMGR_ID,
  231. DBGF_ERRORS,
  232. "PNP_CreateDevInst caused an exception (%d)\n",
  233. RpcExceptionCode()));
  234. Status = MapRpcExceptionToCR(RpcExceptionCode());
  235. }
  236. RpcEndExcept
  237. if (Status != CR_SUCCESS) {
  238. goto Clean0;
  239. }
  240. //
  241. // assign a unique device instance value to the newly created device
  242. // instance
  243. //
  244. ASSERT(*szNewDeviceID && IsLegalDeviceId(szNewDeviceID));
  245. *pdnDevInst = pSetupStringTableAddString(hStringTable, szNewDeviceID,
  246. STRTAB_CASE_SENSITIVE);
  247. if (*pdnDevInst == 0) {
  248. Status = CR_NO_SUCH_DEVNODE;
  249. }
  250. Clean0:
  251. NOTHING;
  252. } except(EXCEPTION_EXECUTE_HANDLER) {
  253. Status = CR_FAILURE;
  254. }
  255. return Status;
  256. } // CM_Create_DevNode_ExW
  257. CONFIGRET
  258. CM_Move_DevNode_Ex(
  259. IN DEVINST dnFromDevInst,
  260. IN DEVINST dnToDevInst,
  261. IN ULONG ulFlags,
  262. IN HMACHINE hMachine
  263. )
  264. /*++
  265. Routine Description:
  266. This routine replaces a root-enumerated device instance by the valid
  267. non-root-enumerated device instance. The device installer uses this
  268. service when it detects that a non-root enumerated device instance is
  269. really the same as its root enumerated counterpart. This API migrates
  270. the old device instance to the new location, and marks the old location
  271. as having a problem.
  272. ** THIS ROUTINE IS NOT IMPLEMENTED **
  273. Parameters:
  274. dnFromDevNode Supplies the handle of the device instance that has been
  275. root enumerated.
  276. dnToDevNode Supplies the handle of the device instance that is a
  277. reenumeration (duplicate) of the root device instance.
  278. ulFlags Must be zero.
  279. Return Value:
  280. ** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
  281. --*/
  282. {
  283. UNREFERENCED_PARAMETER(dnFromDevInst);
  284. UNREFERENCED_PARAMETER(dnToDevInst);
  285. UNREFERENCED_PARAMETER(ulFlags);
  286. UNREFERENCED_PARAMETER(hMachine);
  287. return CR_CALL_NOT_IMPLEMENTED;
  288. } // CM_Move_DevNode_Ex
  289. CONFIGRET
  290. CM_Setup_DevNode_Ex(
  291. IN DEVINST dnDevInst,
  292. IN ULONG ulFlags,
  293. IN HMACHINE hMachine
  294. )
  295. /*++
  296. Routine Description:
  297. This routine reenables and configures a specified device instance or
  298. retrieves information from its enumerator.
  299. Parameters:
  300. dnDevNode Supplies the handle of the device instance which may be
  301. reconfigured.
  302. ulFlags Supplies a flag indicating the action to take. Can be one
  303. of the following values:
  304. CM_SETUP_DEVNODE_READY
  305. Reenable the device instance that had a problem.
  306. CM_SETUP_DOWNLOAD
  307. Retrieve information about this device instance
  308. from its enumerator.
  309. Return Value:
  310. If the function succeeds, the return value is CR_SUCCESS.
  311. If the function fails, the return value is a CR error code.
  312. CR_INVALID_FLAG,
  313. CR_INVALID_DEVNODE,
  314. CR_OUT_OF_MEMORY,
  315. CR_ACCESS_DENIED, or
  316. CR_FAILURE.
  317. --*/
  318. {
  319. CONFIGRET Status = CR_SUCCESS;
  320. WCHAR DeviceID[MAX_DEVICE_ID_LEN];
  321. PVOID hStringTable = NULL;
  322. handle_t hBinding = NULL;
  323. ULONG ulLen=MAX_DEVICE_ID_LEN;
  324. BOOL Success;
  325. HANDLE hToken;
  326. ULONG ulPrivilege;
  327. try {
  328. //
  329. // validate parameters
  330. //
  331. if (INVALID_FLAGS(ulFlags, CM_SETUP_BITS)) {
  332. Status = CR_INVALID_FLAG;
  333. goto Clean0;
  334. }
  335. if (dnDevInst == 0) {
  336. Status = CR_INVALID_DEVINST;
  337. goto Clean0;
  338. }
  339. //
  340. // setup rpc binding handle and string table handle
  341. //
  342. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  343. Status = CR_FAILURE;
  344. goto Clean0;
  345. }
  346. //
  347. // retrieve the device instance ID string associated with the devinst
  348. //
  349. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  350. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  351. Status = CR_INVALID_DEVINST;
  352. goto Clean0;
  353. }
  354. //
  355. // Enable privileges required by the server
  356. //
  357. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  358. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  359. RpcTryExcept {
  360. //
  361. // call rpc service entry point
  362. //
  363. Status = PNP_DeviceInstanceAction(
  364. hBinding, // rpc binding handle
  365. PNP_DEVINST_SETUP, // requested major action - SETUP
  366. ulFlags, // requested minor action
  367. DeviceID, // device instance to create
  368. NULL); // (not used)
  369. }
  370. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  371. KdPrintEx((DPFLTR_PNPMGR_ID,
  372. DBGF_ERRORS,
  373. "PNP_DeviceInstanceAction caused an exception (%d)\n",
  374. RpcExceptionCode()));
  375. Status = MapRpcExceptionToCR(RpcExceptionCode());
  376. }
  377. RpcEndExcept
  378. //
  379. // Restore previous privileges
  380. //
  381. PnPRestorePrivileges(hToken);
  382. Clean0:
  383. NOTHING;
  384. } except(EXCEPTION_EXECUTE_HANDLER) {
  385. Status = CR_FAILURE;
  386. }
  387. return Status;
  388. } // CM_Setup_DevNode_Ex
  389. CONFIGRET
  390. CM_Disable_DevNode_Ex(
  391. IN DEVINST dnDevInst,
  392. IN ULONG ulFlags,
  393. IN HMACHINE hMachine
  394. )
  395. /*++
  396. Routine Description:
  397. This routine disables a device instance.
  398. Parameters:
  399. dnDevNode Supplies the handle of the device instance to be disabled.
  400. ulFlags May be one of CM_DISABLE_BITS.
  401. Return Value:
  402. If the function succeeds, the return value is CR_SUCCESS.
  403. If the function fails, the return value is a CR error code.
  404. CR_INVALID_FLAG,
  405. CR_NOT_DISABLEABLE,
  406. CR_INVALID_DEVNODE,
  407. CR_ACCESS_DENIED, or
  408. CR_FAILURE.
  409. --*/
  410. {
  411. CONFIGRET Status = CR_SUCCESS;
  412. WCHAR DeviceID[MAX_DEVICE_ID_LEN];
  413. ULONG ulLen = MAX_DEVICE_ID_LEN;
  414. PVOID hStringTable = NULL;
  415. handle_t hBinding = NULL;
  416. BOOL Success;
  417. PNP_VETO_TYPE vetoType, *pVetoType;
  418. WCHAR vetoName[MAX_DEVICE_ID_LEN], *pszVetoName;
  419. ULONG ulNameLength;
  420. HANDLE hToken;
  421. ULONG ulPrivilege;
  422. try {
  423. //
  424. // validate parameters
  425. //
  426. if (INVALID_FLAGS(ulFlags, CM_DISABLE_BITS)) {
  427. Status = CR_INVALID_FLAG;
  428. goto Clean0;
  429. }
  430. if (dnDevInst == 0) {
  431. Status = CR_INVALID_DEVINST;
  432. goto Clean0;
  433. }
  434. //
  435. // setup rpc binding handle and string table handle
  436. //
  437. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  438. Status = CR_FAILURE;
  439. goto Clean0;
  440. }
  441. //
  442. // retrieve the device instance ID string associated with the devinst
  443. //
  444. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  445. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  446. Status = CR_INVALID_DEVINST;
  447. goto Clean0;
  448. }
  449. if (ulFlags & CM_DISABLE_UI_NOT_OK) {
  450. vetoType = PNP_VetoTypeUnknown;
  451. pVetoType = &vetoType;
  452. vetoName[0] = L'\0';
  453. pszVetoName = &vetoName[0];
  454. ulNameLength = MAX_DEVICE_ID_LEN;
  455. } else {
  456. pVetoType = NULL;
  457. pszVetoName = NULL;
  458. ulNameLength = 0;
  459. }
  460. //
  461. // Enable privileges required by the server
  462. //
  463. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  464. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  465. RpcTryExcept {
  466. //
  467. // call rpc service entry point
  468. //
  469. Status = PNP_DisableDevInst(
  470. hBinding, // rpc binding handle
  471. DeviceID, // device instance to create
  472. pVetoType,
  473. pszVetoName,
  474. ulNameLength,
  475. ulFlags); // requested minor action (not used)
  476. }
  477. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  478. KdPrintEx((DPFLTR_PNPMGR_ID,
  479. DBGF_ERRORS,
  480. "PNP_DisableDevInst caused an exception (%d)\n",
  481. RpcExceptionCode()));
  482. Status = MapRpcExceptionToCR(RpcExceptionCode());
  483. }
  484. RpcEndExcept
  485. //
  486. // Restore previous privileges
  487. //
  488. PnPRestorePrivileges(hToken);
  489. Clean0:
  490. NOTHING;
  491. } except(EXCEPTION_EXECUTE_HANDLER) {
  492. Status = CR_FAILURE;
  493. }
  494. return Status;
  495. } // CM_Disable_DevNode_Ex
  496. CONFIGRET
  497. CM_Enable_DevNode_Ex(
  498. IN DEVINST dnDevInst,
  499. IN ULONG ulFlags,
  500. IN HMACHINE hMachine
  501. )
  502. /*++
  503. Routine Description:
  504. This routine enables a device instance.
  505. Parameters:
  506. dnDevNode Supplies the handle of the device instance to enable.
  507. ulFlags Must be zero.
  508. Return Value:
  509. If the function succeeds, the return value is CR_SUCCESS.
  510. If the function fails, the return value is a CR error code.
  511. CR_INVALID_FLAG,
  512. CR_INVALID_DEVNODE,
  513. CR_ACCESS_DENIED, or
  514. CR_FAILURE.
  515. --*/
  516. {
  517. CONFIGRET Status = CR_SUCCESS;
  518. WCHAR DeviceID[MAX_DEVICE_ID_LEN];
  519. ULONG ulLen = MAX_DEVICE_ID_LEN;
  520. PVOID hStringTable = NULL;
  521. handle_t hBinding = NULL;
  522. BOOL Success;
  523. HANDLE hToken;
  524. ULONG ulPrivilege;
  525. try {
  526. //
  527. // validate parameters
  528. //
  529. if (INVALID_FLAGS(ulFlags, 0)) {
  530. Status = CR_INVALID_FLAG;
  531. goto Clean0;
  532. }
  533. if (dnDevInst == 0) {
  534. Status = CR_INVALID_DEVINST;
  535. goto Clean0;
  536. }
  537. //
  538. // setup rpc binding handle and string table handle
  539. //
  540. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  541. Status = CR_FAILURE;
  542. goto Clean0;
  543. }
  544. //
  545. // retrieve the device instance ID string associated with the devinst
  546. //
  547. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  548. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  549. Status = CR_INVALID_DEVINST;
  550. goto Clean0;
  551. }
  552. //
  553. // Enable privileges required by the server
  554. //
  555. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  556. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  557. RpcTryExcept {
  558. //
  559. // call rpc service entry point
  560. //
  561. Status = PNP_DeviceInstanceAction(
  562. hBinding, // rpc binding handle
  563. PNP_DEVINST_ENABLE, // requested major action - ENABLE
  564. ulFlags, // requested minor action (not used)
  565. DeviceID, // device instance to enable
  566. NULL); // (not used)
  567. }
  568. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  569. KdPrintEx((DPFLTR_PNPMGR_ID,
  570. DBGF_ERRORS,
  571. "PNP_DeviceInstanceAction caused an exception (%d)\n",
  572. RpcExceptionCode()));
  573. Status = MapRpcExceptionToCR(RpcExceptionCode());
  574. }
  575. RpcEndExcept
  576. //
  577. // Restore previous privileges
  578. //
  579. PnPRestorePrivileges(hToken);
  580. Clean0:
  581. NOTHING;
  582. } except(EXCEPTION_EXECUTE_HANDLER) {
  583. Status = CR_FAILURE;
  584. }
  585. return Status;
  586. } // CM_Enable_DevNode_Ex
  587. CONFIGRET
  588. CM_Get_DevNode_Status_Ex(
  589. OUT PULONG pulStatus,
  590. OUT PULONG pulProblemNumber,
  591. IN DEVINST dnDevInst,
  592. IN ULONG ulFlags,
  593. IN HMACHINE hMachine
  594. )
  595. /*++
  596. Routine Description:
  597. This routine retrieves the status of a device instance.
  598. Parameters:
  599. pulStatus Supplies the address of the variable that receives the
  600. status flag of the device instance. Can be a combination
  601. of the DN_* values.
  602. pulProblemNumber Supplies the address of the variable that receives an
  603. identifier indicating the problem. Can be one of the
  604. CM_PROB_* values.
  605. dnDevNode Supplies the handle of the device instance for which
  606. to retrieve status.
  607. ulFlags Must be zero.
  608. Return Value:
  609. If the function succeeds, the return value is CR_SUCCESS.
  610. If the function fails, the return value is a CR error code.
  611. CR_INVALID_DEVNODE,
  612. CR_INVALID_FLAG,
  613. CR_INVALID_POINTER, or
  614. CR_FAILURE.
  615. --*/
  616. {
  617. CONFIGRET Status = CR_SUCCESS;
  618. WCHAR DeviceID [MAX_DEVICE_ID_LEN];
  619. ULONG ulLen = MAX_DEVICE_ID_LEN;
  620. PVOID hStringTable = NULL;
  621. handle_t hBinding = NULL;
  622. BOOL Success;
  623. try {
  624. //
  625. // validate parameters
  626. //
  627. if (dnDevInst == 0) {
  628. Status = CR_INVALID_DEVINST;
  629. goto Clean0;
  630. }
  631. if ((!ARGUMENT_PRESENT(pulStatus)) ||
  632. (!ARGUMENT_PRESENT(pulProblemNumber))) {
  633. Status = CR_INVALID_POINTER;
  634. goto Clean0;
  635. }
  636. if (INVALID_FLAGS(ulFlags, 0)) {
  637. Status = CR_INVALID_FLAG;
  638. goto Clean0;
  639. }
  640. //
  641. // setup rpc binding handle and string table handle
  642. //
  643. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  644. Status = CR_FAILURE;
  645. goto Clean0;
  646. }
  647. //
  648. // retrieve the device instance ID string associated with the devinst
  649. //
  650. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  651. if (Success == FALSE) {
  652. Status = CR_INVALID_DEVINST;
  653. goto Clean0;
  654. }
  655. //
  656. // No special privileges are required by the server
  657. //
  658. RpcTryExcept {
  659. //
  660. // call rpc service entry point
  661. //
  662. Status = PNP_GetDeviceStatus(
  663. hBinding, // rpc binding handle
  664. DeviceID, // device instance to get status for
  665. pulStatus, // return StatusFlags here
  666. pulProblemNumber, // return Problem here
  667. ulFlags); // (not used)
  668. }
  669. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  670. KdPrintEx((DPFLTR_PNPMGR_ID,
  671. DBGF_ERRORS,
  672. "PNP_GetDeviceStatus caused an exception (%d)\n",
  673. RpcExceptionCode()));
  674. Status = MapRpcExceptionToCR(RpcExceptionCode());
  675. }
  676. RpcEndExcept
  677. Clean0:
  678. NOTHING;
  679. } except(EXCEPTION_EXECUTE_HANDLER) {
  680. Status = CR_FAILURE;
  681. }
  682. return Status;
  683. } // CM_Get_DevNode_Status_Ex
  684. CONFIGRET
  685. CM_Set_DevNode_Problem_Ex(
  686. IN DEVINST dnDevInst,
  687. IN ULONG ulProblem,
  688. IN ULONG ulFlags,
  689. IN HMACHINE hMachine
  690. )
  691. /*++
  692. Routine Description:
  693. This routine clears or set the problem of a device instance.
  694. Parameters:
  695. dnDevNode Supplies the handle of the device instance for which
  696. to set the problem.
  697. ulProblem Supplies the new problem value. Can be one of the
  698. CM_PROB_* values. If zero, the problem is cleared.
  699. ulFlags Must be zero.
  700. Return Value:
  701. If the function succeeds, the return value is CR_SUCCESS.
  702. If the function fails, the return value is a CR error code.
  703. CR_INVALID_DEVNODE,
  704. CR_INVALID_FLAG,
  705. CR_ACCESS_DENIED, or
  706. CR_FAILURE.
  707. --*/
  708. {
  709. CONFIGRET Status = CR_SUCCESS;
  710. WCHAR DeviceID[MAX_DEVICE_ID_LEN];
  711. PVOID hStringTable = NULL;
  712. handle_t hBinding = NULL;
  713. ULONG ulLen = MAX_DEVICE_ID_LEN;
  714. BOOL Success;
  715. HANDLE hToken;
  716. ULONG ulPrivilege;
  717. try {
  718. //
  719. // validate parameters
  720. //
  721. if (dnDevInst == 0) {
  722. Status = CR_INVALID_DEVINST;
  723. goto Clean0;
  724. }
  725. if (INVALID_FLAGS(ulFlags, CM_SET_DEVNODE_PROBLEM_BITS)) {
  726. Status = CR_INVALID_FLAG;
  727. goto Clean0;
  728. }
  729. //
  730. // setup rpc binding handle and string table handle
  731. //
  732. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  733. Status = CR_FAILURE;
  734. goto Clean0;
  735. }
  736. //
  737. // retrieve the device instance ID string associated with the devinst
  738. //
  739. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  740. if (Success == FALSE) {
  741. Status = CR_INVALID_DEVINST;
  742. goto Clean0;
  743. }
  744. //
  745. // Enable privileges required by the server
  746. //
  747. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  748. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  749. RpcTryExcept {
  750. //
  751. // call rpc service entry point
  752. //
  753. Status = PNP_SetDeviceProblem(
  754. hBinding, // rpc binding handle
  755. DeviceID, // device instance
  756. ulProblem, // specifies new Problem
  757. ulFlags); // (not used)
  758. }
  759. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  760. KdPrintEx((DPFLTR_PNPMGR_ID,
  761. DBGF_ERRORS,
  762. "PNP_SetDeviceProblem caused an exception (%d)\n",
  763. RpcExceptionCode()));
  764. Status = MapRpcExceptionToCR(RpcExceptionCode());
  765. }
  766. RpcEndExcept
  767. //
  768. // Restore previous privileges
  769. //
  770. PnPRestorePrivileges(hToken);
  771. Clean0:
  772. NOTHING;
  773. } except(EXCEPTION_EXECUTE_HANDLER) {
  774. Status = CR_FAILURE;
  775. }
  776. return Status;
  777. } // CM_Set_DevNode_Problem_Ex
  778. CONFIGRET
  779. CM_Reenumerate_DevNode_Ex(
  780. IN DEVINST dnDevInst,
  781. IN ULONG ulFlags,
  782. IN HMACHINE hMachine
  783. )
  784. /*++
  785. Routine Description:
  786. This routine causes the specified device instance to be enumerated
  787. (if it is enumerable).
  788. Parameters:
  789. dnDevNode Supplies the handle of the device instance to be enumerated.
  790. ulFlags Supplies flags specifying options for the re-enumeration of the
  791. device instance. May be one of the following values:
  792. CM_REENUMERATE_NORMAL
  793. CM_REENUMERATE_SYNCHRONOUS
  794. CM_REENUMERATE_RETRY_INSTALLATION
  795. CM_REENUMERATE_ASYNCHRONOUS
  796. Return Value:
  797. If the function succeeds, the return value is CR_SUCCESS.
  798. If the function fails, the return value is a CR error code.
  799. CR_INVALID_DEVNODE,
  800. CR_INVALID_FLAG,
  801. CR_ACCESS_DENIED, or
  802. CR_FAILURE.
  803. --*/
  804. {
  805. CONFIGRET Status = CR_SUCCESS;
  806. WCHAR DeviceID [MAX_DEVICE_ID_LEN];
  807. PVOID hStringTable = NULL;
  808. handle_t hBinding = NULL;
  809. ULONG ulLen = MAX_DEVICE_ID_LEN;
  810. BOOL Success;
  811. HANDLE hToken;
  812. ULONG ulPrivilege;
  813. try {
  814. //
  815. // validate parameters
  816. //
  817. if (INVALID_FLAGS(ulFlags, CM_REENUMERATE_BITS)) {
  818. Status = CR_INVALID_FLAG;
  819. goto Clean0;
  820. }
  821. if (dnDevInst == 0) {
  822. Status = CR_INVALID_DEVINST;
  823. goto Clean0;
  824. }
  825. //
  826. // setup rpc binding handle and string table handle
  827. //
  828. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  829. Status = CR_FAILURE;
  830. goto Clean0;
  831. }
  832. //
  833. // retrieve the device instance ID string associated with the devinst
  834. //
  835. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  836. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  837. Status = CR_INVALID_DEVINST;
  838. goto Clean0;
  839. }
  840. //
  841. // Enable privileges required by the server
  842. //
  843. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  844. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  845. RpcTryExcept {
  846. //
  847. // call rpc service entry point
  848. //
  849. Status = PNP_DeviceInstanceAction(
  850. hBinding, // rpc binding handle
  851. PNP_DEVINST_REENUMERATE,// requested major action - REENUMERATE
  852. ulFlags, // requested minor action
  853. DeviceID, // device instance subtree to reenumerate
  854. NULL); // (not used)
  855. }
  856. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  857. KdPrintEx((DPFLTR_PNPMGR_ID,
  858. DBGF_ERRORS,
  859. "PNP_DeviceInstanceAction caused an exception (%d)\n",
  860. RpcExceptionCode()));
  861. Status = MapRpcExceptionToCR(RpcExceptionCode());
  862. }
  863. RpcEndExcept
  864. //
  865. // Restore previous privileges
  866. //
  867. PnPRestorePrivileges(hToken);
  868. Clean0:
  869. NOTHING;
  870. } except(EXCEPTION_EXECUTE_HANDLER) {
  871. Status = CR_FAILURE;
  872. }
  873. return Status;
  874. } // CM_Reenumerate_DevNode_Ex
  875. CONFIGRET
  876. CM_Query_And_Remove_SubTree_ExW(
  877. IN DEVINST dnAncestor,
  878. OUT PPNP_VETO_TYPE pVetoType,
  879. OUT LPWSTR pszVetoName,
  880. IN ULONG ulNameLength,
  881. IN ULONG ulFlags,
  882. IN HMACHINE hMachine
  883. )
  884. /*++
  885. Routine Description:
  886. This routine checks whether a device instance and its progeny can be
  887. removed. If the query isn't vetoed then a remove is done. The replaces
  888. the old CM_Query_Remove_SubTree followed by CM_Remove_SubTree.
  889. Parameters:
  890. dnAncestor Supplies the handle of the device instance at the root of
  891. the subtree to be removed.
  892. ulFlags Specifies whether UI should be presented for
  893. this action. Can be one of the following values:
  894. CM_REMOVE_UI_OK - OK to present UI for query-removal.
  895. CM_REMOVE_UI_NOT_OK - Don't present UI for query-removal.
  896. CM_REMOVE_NO_RESTART - Don't attempt to restart the devnode.
  897. Return Value:
  898. If the function succeeds, the return value is CR_SUCCESS.
  899. If the function fails, the return value is a CR error code.
  900. CR_INVALID_DEVNODE,
  901. CR_INVALID_FLAG,
  902. CR_REMOVE_VETOED,
  903. CR_ACCESS_DENIED, or
  904. CR_FAILURE.
  905. --*/
  906. {
  907. CONFIGRET Status = CR_SUCCESS;
  908. WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
  909. PVOID hStringTable = NULL;
  910. handle_t hBinding = NULL;
  911. ULONG ulLen = MAX_DEVICE_ID_LEN;
  912. HANDLE hToken;
  913. ULONG ulPrivilege;
  914. try {
  915. //
  916. // validate parameters
  917. //
  918. if (dnAncestor == 0) {
  919. Status = CR_INVALID_DEVINST;
  920. goto Clean0;
  921. }
  922. if (INVALID_FLAGS(ulFlags, CM_REMOVE_BITS)) {
  923. Status = CR_INVALID_FLAG;
  924. goto Clean0;
  925. }
  926. //
  927. // setup rpc binding handle and string table handle
  928. //
  929. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  930. Status = CR_FAILURE;
  931. goto Clean0;
  932. }
  933. //
  934. // retrieve the device instance ID string associated with the devinst
  935. //
  936. pSetupStringTableStringFromIdEx(hStringTable, dnAncestor,pDeviceID,&ulLen);
  937. ASSERT(pDeviceID && *pDeviceID && IsLegalDeviceId(pDeviceID));
  938. if (pDeviceID == NULL || INVALID_DEVINST(pDeviceID)) {
  939. Status = CR_INVALID_DEVINST;
  940. goto Clean0;
  941. }
  942. if (ulNameLength == 0) {
  943. pszVetoName = NULL;
  944. }
  945. if (pszVetoName != NULL) {
  946. *pszVetoName = L'\0';
  947. }
  948. if (pVetoType != NULL) {
  949. *pVetoType = PNP_VetoTypeUnknown;
  950. }
  951. //
  952. // Enable privileges required by the server
  953. //
  954. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  955. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  956. RpcTryExcept {
  957. //
  958. // call rpc service entry point
  959. //
  960. Status = PNP_QueryRemove(
  961. hBinding, // rpc binding handle
  962. pDeviceID, // device instance subtree to remove
  963. pVetoType,
  964. pszVetoName,
  965. ulNameLength,
  966. ulFlags);
  967. }
  968. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  969. KdPrintEx((DPFLTR_PNPMGR_ID,
  970. DBGF_ERRORS,
  971. "PNP_QueryRemove caused an exception (%d)\n",
  972. RpcExceptionCode()));
  973. Status = MapRpcExceptionToCR(RpcExceptionCode());
  974. }
  975. RpcEndExcept
  976. //
  977. // Restore previous privileges
  978. //
  979. PnPRestorePrivileges(hToken);
  980. Clean0:
  981. NOTHING;
  982. } except(EXCEPTION_EXECUTE_HANDLER) {
  983. Status = CR_FAILURE;
  984. }
  985. return Status;
  986. } // CM_Query_And_Remove_SubTree_ExW
  987. CONFIGRET
  988. CM_Query_Remove_SubTree_Ex(
  989. IN DEVINST dnAncestor,
  990. IN ULONG ulFlags,
  991. IN HMACHINE hMachine
  992. )
  993. /*++
  994. Routine Description:
  995. This routine checks whether a device instance and its progeny can be
  996. removed. This API must be called before calling CM_Remove_SubTree to
  997. make sure applications prepare for the removal of the device or to
  998. give the applications a chance to deny the request to remove the device.
  999. If the removal happens ?surprise style? (i.e., there?s no advanced
  1000. warning or chance to veto), then this API should not be called before
  1001. calling CM_Remove_SubTree.
  1002. Parameters:
  1003. dnAncestor Supplies the handle of the device instance at the root of
  1004. the subtree to be removed.
  1005. ulFlags Specifies whether UI should be presented for
  1006. this action. Can be one of the following values:
  1007. CM_QUERY_REMOVE_UI_OK - OK to present UI for query-removal.
  1008. CM_QUERY_REMOVE_UI_NOT_OK -Don't present UI for query-removal.
  1009. Return Value:
  1010. ** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
  1011. --*/
  1012. {
  1013. UNREFERENCED_PARAMETER(dnAncestor);
  1014. UNREFERENCED_PARAMETER(ulFlags);
  1015. UNREFERENCED_PARAMETER(hMachine);
  1016. return CR_CALL_NOT_IMPLEMENTED;
  1017. } // CM_Query_Remove_SubTree_Ex
  1018. CONFIGRET
  1019. CM_Remove_SubTree_Ex(
  1020. IN DEVINST dnAncestor,
  1021. IN ULONG ulFlags,
  1022. IN HMACHINE hMachine
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. This routine removes a device instance and its children from the
  1027. running system. This API notifies each device instance in the subtree
  1028. of the dnAncestor parameter of the device's removal. (On Windows NT,
  1029. this means that each driver/service controlling a device in this
  1030. subtree receives a device removal notification.)
  1031. Parameters:
  1032. dnAncestor Supplies the handle of the device instance that is being removed.
  1033. ulFlags Must be either CM_REMOVE_UI_OK or CM_REMOVE_UI_NOT_OK.
  1034. Return Value:
  1035. ** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
  1036. --*/
  1037. {
  1038. UNREFERENCED_PARAMETER(dnAncestor);
  1039. UNREFERENCED_PARAMETER(ulFlags);
  1040. UNREFERENCED_PARAMETER(hMachine);
  1041. return CR_CALL_NOT_IMPLEMENTED;
  1042. } // CM_Remove_SubTree_Ex
  1043. CONFIGRET
  1044. CM_Uninstall_DevNode_Ex(
  1045. IN DEVNODE dnDevInst,
  1046. IN ULONG ulFlags,
  1047. IN HMACHINE hMachine
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This routine uninstalls a device instance (i.e., deletes its registry
  1052. key(s) in the Enum branch). This API can only be called for phantom
  1053. device instances, and the handle supplied is invalid after the call.
  1054. This API does not attempt to delete all possible storage locations
  1055. associated with the device instance. It will do a recursive delete on
  1056. the devnode key, so that any subkeys will be removed. It will also
  1057. delete the devnode key (and any subkeys) located in the Enum branch
  1058. of each hardware profile. It will not delete any software keys or user
  1059. keys (CM_Delete_DevNode_Key must be called to do that before calling
  1060. this API).
  1061. Parameters:
  1062. dnPhantom Handle of a phantom device instance to uninstall. This
  1063. handle is typically retrieved by a call to CM_Locate_DevNode
  1064. or CM_Create_DevNode.
  1065. ulFlags Must be zero.
  1066. Return Value:
  1067. If the function succeeds, the return value is CR_SUCCESS.
  1068. If the function fails, the return value is a CR error code.
  1069. CR_INVALID_DEVNODE,
  1070. CR_INVALID_FLAG,
  1071. CR_REGISTRY_ERROR,
  1072. CR_ACCESS_DENIED, or
  1073. CR_FAILURE.
  1074. --*/
  1075. {
  1076. CONFIGRET Status = CR_SUCCESS;
  1077. PVOID hStringTable = NULL;
  1078. handle_t hBinding = NULL;
  1079. ULONG ulLen = MAX_DEVICE_ID_LEN;
  1080. WCHAR szParentKey[MAX_CM_PATH], szChildKey[MAX_CM_PATH],
  1081. DeviceID[MAX_DEVICE_ID_LEN];
  1082. BOOL Success;
  1083. try {
  1084. //
  1085. // validate parameters
  1086. //
  1087. if (dnDevInst == 0) {
  1088. Status = CR_INVALID_DEVINST;
  1089. goto Clean0;
  1090. }
  1091. if (INVALID_FLAGS(ulFlags, 0)) {
  1092. Status = CR_INVALID_FLAG;
  1093. goto Clean0;
  1094. }
  1095. //
  1096. // setup rpc binding handle and string table handle
  1097. //
  1098. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  1099. Status = CR_FAILURE;
  1100. goto Clean0;
  1101. }
  1102. //
  1103. // retrieve the device instance ID string associated with the devinst
  1104. //
  1105. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  1106. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  1107. Status = CR_INVALID_DEVINST;
  1108. goto Clean0;
  1109. }
  1110. //
  1111. // Special privileges are no longer required by the server.
  1112. //
  1113. // Note that with previous versions of the PlugPlay RPC server,
  1114. // SE_LOAD_DRIVER_PRIVILEGE was required for this operation. We do not
  1115. // need to enable the privilege for local callers, since this version of
  1116. // CFGMGR32 should match a local version of UMPNPMGR that does not
  1117. // require the privilege. For remote calls, it's not always possible
  1118. // for us to enable the privilege anyways, since the client may not have
  1119. // the privilege on the local machine, but may as authenticated on the
  1120. // server. The server typically sees all privileges that a remote
  1121. // caller has as "enabled by default", so we are not required to enable
  1122. // the privilege here either.
  1123. //
  1124. RpcTryExcept {
  1125. //
  1126. // call rpc service entry point
  1127. //
  1128. Status = PNP_UninstallDevInst(
  1129. hBinding, // rpc binding handle
  1130. DeviceID, // device instance to uninstall
  1131. ulFlags); // (unused)
  1132. }
  1133. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1134. KdPrintEx((DPFLTR_PNPMGR_ID,
  1135. DBGF_ERRORS,
  1136. "PNP_UninstallDevInst caused an exception (%d)\n",
  1137. RpcExceptionCode()));
  1138. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1139. }
  1140. RpcEndExcept
  1141. //------------------------------------------------------------------
  1142. // after deleting the main hw key and the config specific hw keys,
  1143. // cleanup the user hw key, which can only be done on the client
  1144. // side.
  1145. //------------------------------------------------------------------
  1146. //
  1147. // form the user hardware registry key path
  1148. //
  1149. // note - in some cases, GetDevNodeKeyPath may call PNP_GetClassInstance
  1150. // or PNP_SetDeviceRegProp to set values on the server, in which case
  1151. // special privileges would be required by the server. the call below,
  1152. // which specifies the flags (CM_REGISTRY_HARDWARE | CM_REGISTRY_USER)
  1153. // is NOT one of those cases, so there is no need to have any privileges
  1154. // enabled during this call.
  1155. //
  1156. Status =
  1157. GetDevNodeKeyPath(
  1158. hBinding,
  1159. DeviceID,
  1160. CM_REGISTRY_HARDWARE | CM_REGISTRY_USER,
  1161. 0,
  1162. szParentKey,
  1163. SIZECHARS(szParentKey),
  1164. szChildKey,
  1165. SIZECHARS(szChildKey),
  1166. FALSE);
  1167. if (Status != CR_SUCCESS) {
  1168. goto Clean0;
  1169. }
  1170. //
  1171. // delete the specified private user key
  1172. //
  1173. Status = DeletePrivateKey(HKEY_CURRENT_USER, szParentKey, szChildKey);
  1174. Clean0:
  1175. NOTHING;
  1176. } except(EXCEPTION_EXECUTE_HANDLER) {
  1177. Status = CR_FAILURE;
  1178. }
  1179. return Status;
  1180. } // CM_Uninstall_DevNode_Ex
  1181. CONFIGRET
  1182. CM_Request_Device_Eject_ExW(
  1183. IN DEVNODE dnDevInst,
  1184. OUT PPNP_VETO_TYPE pVetoType,
  1185. OUT LPWSTR pszVetoName,
  1186. IN ULONG ulNameLength,
  1187. IN ULONG ulFlags,
  1188. IN HMACHINE hMachine
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Parameters:
  1193. dnDevInst Handle of a device instance. This handle is typically
  1194. retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
  1195. ulFlags Must be zero.
  1196. Return Value:
  1197. If the function succeeds, the return value is CR_SUCCESS.
  1198. If the function fails, the return value is a CR error code.
  1199. CR_INVALID_DEVNODE,
  1200. CR_INVALID_FLAG,
  1201. CR_REGISTRY_ERROR,
  1202. CR_ACCESS_DENIED, or
  1203. CR_FAILURE.
  1204. --*/
  1205. {
  1206. CONFIGRET Status = CR_SUCCESS;
  1207. PVOID hStringTable = NULL;
  1208. handle_t hBinding = NULL;
  1209. ULONG ulLen = MAX_DEVICE_ID_LEN;
  1210. WCHAR DeviceID[MAX_DEVICE_ID_LEN];
  1211. BOOL Success;
  1212. HANDLE hToken;
  1213. ULONG ulPrivileges[2];
  1214. try {
  1215. //
  1216. // validate parameters
  1217. //
  1218. if (ulNameLength == 0) {
  1219. pszVetoName = NULL;
  1220. }
  1221. if (pszVetoName != NULL) {
  1222. *pszVetoName = L'\0';
  1223. }
  1224. if (pVetoType != NULL) {
  1225. *pVetoType = PNP_VetoTypeUnknown;
  1226. }
  1227. if (dnDevInst == 0) {
  1228. Status = CR_INVALID_DEVINST;
  1229. goto Clean0;
  1230. }
  1231. //
  1232. // no flags are currently valid
  1233. //
  1234. if (INVALID_FLAGS(ulFlags, 0)) {
  1235. Status = CR_INVALID_FLAG;
  1236. goto Clean0;
  1237. }
  1238. //
  1239. // setup rpc binding handle and string table handle
  1240. //
  1241. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  1242. Status = CR_FAILURE;
  1243. goto Clean0;
  1244. }
  1245. //
  1246. // retrieve the device instance ID string associated with the devinst
  1247. //
  1248. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  1249. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  1250. Status = CR_INVALID_DEVINST;
  1251. goto Clean0;
  1252. }
  1253. //
  1254. // Enable privileges required by the server
  1255. //
  1256. // Note - for most devices, only the SeLoadDriverPrivilege privilege
  1257. // will be required, however if the device being ejected is a dock
  1258. // device, the SeUndockPrivilege privilege will be required instead.
  1259. // Since we don't know if the device the user is requesting to eject is
  1260. // a dock device or not (that is determined on the server-side), we
  1261. // attempt to enable both privileges.
  1262. //
  1263. // ISSUE-2002/03/04-jamesca: Should client perform dock device check?
  1264. // We could avoid enabling one of these two privileges unecessarily
  1265. // if the client checked the capabilities of the device in advance to
  1266. // see if the device was actually a dock or not. In the case of a
  1267. // dock this routine would simply call CM_Request_Eject_PC, which
  1268. // would enable the SeUndockPrivilege. This logic already exists on
  1269. // the server, is it appropriate for the client also/instead?
  1270. //
  1271. ulPrivileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
  1272. ulPrivileges[1] = SE_UNDOCK_PRIVILEGE;
  1273. hToken = PnPEnablePrivileges(ulPrivileges, 2);
  1274. RpcTryExcept {
  1275. //
  1276. // call rpc service entry point
  1277. //
  1278. Status = PNP_RequestDeviceEject(
  1279. hBinding, // rpc binding handle
  1280. DeviceID, // device instance subtree to remove
  1281. pVetoType,
  1282. pszVetoName,
  1283. ulNameLength,
  1284. ulFlags);
  1285. }
  1286. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1287. KdPrintEx((DPFLTR_PNPMGR_ID,
  1288. DBGF_ERRORS,
  1289. "PNP_RequestDeviceEject caused an exception (%d)\n",
  1290. RpcExceptionCode()));
  1291. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1292. }
  1293. RpcEndExcept
  1294. //
  1295. // Restore previous privileges
  1296. //
  1297. PnPRestorePrivileges(hToken);
  1298. Clean0:
  1299. NOTHING;
  1300. } except(EXCEPTION_EXECUTE_HANDLER) {
  1301. Status = CR_FAILURE;
  1302. }
  1303. return Status;
  1304. } // CM_Request_Device_Eject_ExW
  1305. CONFIGRET
  1306. CM_Add_ID_ExW(
  1307. IN DEVINST dnDevInst,
  1308. IN PWSTR pszID,
  1309. IN ULONG ulFlags,
  1310. IN HMACHINE hMachine
  1311. )
  1312. /*++
  1313. Routine Description:
  1314. This routine adds a device ID to a device instance's HardwareID or
  1315. CompatibleIDs list.
  1316. Parameters:
  1317. dnDevInst Handle of a device instance. This handle is typically
  1318. retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
  1319. pszID Supplies a pointer to a NULL-terminated string specifying
  1320. the ID to be added.
  1321. ulFlags Supplies flags for the ID. May be one of the following values:
  1322. ID Type Flags:
  1323. CM_ADD_ID_HARDWARE The specified ID is a hardware ID. Add
  1324. it to the device instance's HardwareID
  1325. list.
  1326. CM_ADD_ID_COMPATIBLE The specified ID is a compatible ID.
  1327. Add it to the device instance's
  1328. CompatibleIDs list.
  1329. Return Value:
  1330. If the function succeeds, the return value is CR_SUCCESS.
  1331. If the function fails, the return value is a CR error code.
  1332. CR_INVALID_DEVNODE,
  1333. CR_INVALID_POINTER,
  1334. CR_INVALID_FLAG,
  1335. CR_ACCESS_DENIED, or
  1336. CR_FAILURE.
  1337. --*/
  1338. {
  1339. CONFIGRET Status = CR_SUCCESS;
  1340. WCHAR DeviceID[MAX_DEVICE_ID_LEN];
  1341. PVOID hStringTable = NULL;
  1342. handle_t hBinding = NULL;
  1343. ULONG ulLen = MAX_DEVICE_ID_LEN;
  1344. BOOL Success;
  1345. try {
  1346. //
  1347. // validate parameters
  1348. //
  1349. if (dnDevInst == 0) {
  1350. Status = CR_INVALID_DEVINST;
  1351. goto Clean0;
  1352. }
  1353. if (!ARGUMENT_PRESENT(pszID)) {
  1354. Status = CR_INVALID_POINTER;
  1355. goto Clean0;
  1356. }
  1357. if (INVALID_FLAGS(ulFlags, CM_ADD_ID_BITS)) {
  1358. Status = CR_INVALID_FLAG;
  1359. goto Clean0;
  1360. }
  1361. //
  1362. // setup rpc binding handle and string table handle
  1363. //
  1364. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  1365. Status = CR_FAILURE;
  1366. goto Clean0;
  1367. }
  1368. //
  1369. // retrieve the device instance ID string associated with the devinst
  1370. //
  1371. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  1372. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  1373. Status = CR_INVALID_DEVINST;
  1374. goto Clean0;
  1375. }
  1376. //
  1377. // Special privileges are no longer required by the server.
  1378. //
  1379. // Note that with previous versions of the PlugPlay RPC server,
  1380. // SE_LOAD_DRIVER_PRIVILEGE was required for this operation. We do not
  1381. // need to enable the privilege for local callers, since this version of
  1382. // CFGMGR32 should match a local version of UMPNPMGR that does not
  1383. // require the privilege. For remote calls, it's not always possible
  1384. // for us to enable the privilege anyways, since the client may not have
  1385. // the privilege on the local machine, but may as authenticated on the
  1386. // server. The server typically sees all privileges that a remote
  1387. // caller has as "enabled by default", so we are not required to enable
  1388. // the privilege here either.
  1389. //
  1390. RpcTryExcept {
  1391. //
  1392. // call rpc service entry point
  1393. //
  1394. Status = PNP_AddID(
  1395. hBinding, // rpc binding handle
  1396. DeviceID, // device instance
  1397. pszID, // id to add
  1398. ulFlags); // hardware or compatible
  1399. }
  1400. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1401. KdPrintEx((DPFLTR_PNPMGR_ID,
  1402. DBGF_ERRORS,
  1403. "PNP_AddID caused an exception (%d)\n",
  1404. RpcExceptionCode()));
  1405. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1406. }
  1407. RpcEndExcept
  1408. Clean0:
  1409. NOTHING;
  1410. } except(EXCEPTION_EXECUTE_HANDLER) {
  1411. Status = CR_FAILURE;
  1412. }
  1413. return Status;
  1414. } // CM_Add_ID_ExW
  1415. CMAPI
  1416. CONFIGRET
  1417. CM_Register_Device_Driver_Ex(
  1418. IN DEVINST dnDevInst,
  1419. IN ULONG ulFlags,
  1420. IN HMACHINE hMachine
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. This routine registers the device driver for the specified device.
  1425. Parameters:
  1426. dnDevInst Handle of a device instance. This handle is typically
  1427. retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
  1428. ulFlags Supplies flags for register the driver. May be one of the
  1429. following values:
  1430. CM_REGISTER_DEVICE_DRIVER_STATIC
  1431. CM_REGISTER_DEVICE_DRIVER_DISABLEABLE
  1432. CM_REGISTER_DEVICE_DRIVER_REMOVABLE
  1433. Return Value:
  1434. If the function succeeds, the return value is CR_SUCCESS.
  1435. If the function fails, the return value is a CR error code.
  1436. CR_INVALID_DEVNODE,
  1437. CR_INVALID_FLAG,
  1438. CR_ACCESS_DENIED, or
  1439. CR_FAILURE.
  1440. --*/
  1441. {
  1442. CONFIGRET Status = CR_SUCCESS;
  1443. WCHAR DeviceID [MAX_DEVICE_ID_LEN];
  1444. PVOID hStringTable = NULL;
  1445. handle_t hBinding = NULL;
  1446. ULONG ulLen = MAX_DEVICE_ID_LEN;
  1447. BOOL Success;
  1448. HANDLE hToken;
  1449. ULONG ulPrivilege;
  1450. try {
  1451. //
  1452. // validate parameters
  1453. //
  1454. if (dnDevInst == 0) {
  1455. Status = CR_INVALID_DEVINST;
  1456. goto Clean0;
  1457. }
  1458. if (INVALID_FLAGS(ulFlags, CM_REGISTER_DEVICE_DRIVER_BITS)) {
  1459. Status = CR_INVALID_FLAG;
  1460. goto Clean0;
  1461. }
  1462. //
  1463. // setup rpc binding handle and string table handle
  1464. //
  1465. if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
  1466. Status = CR_FAILURE;
  1467. goto Clean0;
  1468. }
  1469. //
  1470. // retrieve the device instance ID string associated with the devinst
  1471. //
  1472. Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
  1473. if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
  1474. Status = CR_INVALID_DEVINST;
  1475. goto Clean0;
  1476. }
  1477. //
  1478. // Enable privileges required by the server
  1479. //
  1480. ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
  1481. hToken = PnPEnablePrivileges(&ulPrivilege, 1);
  1482. RpcTryExcept {
  1483. //
  1484. // call rpc service entry point
  1485. //
  1486. Status = PNP_RegisterDriver(
  1487. hBinding, // rpc binding handle
  1488. DeviceID, // device instance
  1489. ulFlags); // hardware or compatible
  1490. }
  1491. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  1492. KdPrintEx((DPFLTR_PNPMGR_ID,
  1493. DBGF_ERRORS,
  1494. "PNP_RegisterDriver caused an exception (%d)\n",
  1495. RpcExceptionCode()));
  1496. Status = MapRpcExceptionToCR(RpcExceptionCode());
  1497. }
  1498. RpcEndExcept
  1499. //
  1500. // Restore previous privileges
  1501. //
  1502. PnPRestorePrivileges(hToken);
  1503. Clean0:
  1504. NOTHING;
  1505. } except(EXCEPTION_EXECUTE_HANDLER) {
  1506. Status = CR_FAILURE;
  1507. }
  1508. return Status;
  1509. } // CM_Register_Device_Driver_Ex
  1510. //-------------------------------------------------------------------
  1511. // Local Stubs
  1512. //-------------------------------------------------------------------
  1513. CONFIGRET
  1514. CM_Create_DevNodeW(
  1515. OUT PDEVINST pdnDevInst,
  1516. IN DEVINSTID_W pDeviceID,
  1517. IN DEVINST dnParent,
  1518. IN ULONG ulFlags
  1519. )
  1520. {
  1521. return CM_Create_DevNode_ExW(pdnDevInst, pDeviceID, dnParent,
  1522. ulFlags, NULL);
  1523. }
  1524. CONFIGRET
  1525. CM_Create_DevNodeA(
  1526. OUT PDEVINST pdnDevInst,
  1527. IN DEVINSTID_A pDeviceID,
  1528. IN DEVINST dnParent,
  1529. IN ULONG ulFlags
  1530. )
  1531. {
  1532. return CM_Create_DevNode_ExA(pdnDevInst, pDeviceID, dnParent,
  1533. ulFlags, NULL);
  1534. }
  1535. CONFIGRET
  1536. CM_Move_DevNode(
  1537. IN DEVINST dnFromDevInst,
  1538. IN DEVINST dnToDevInst,
  1539. IN ULONG ulFlags
  1540. )
  1541. {
  1542. return CM_Move_DevNode_Ex(dnFromDevInst, dnToDevInst, ulFlags, NULL);
  1543. }
  1544. CONFIGRET
  1545. CM_Setup_DevNode(
  1546. IN DEVINST dnDevInst,
  1547. IN ULONG ulFlags
  1548. )
  1549. {
  1550. return CM_Setup_DevNode_Ex(dnDevInst, ulFlags, NULL);
  1551. }
  1552. CONFIGRET
  1553. CM_Disable_DevNode(
  1554. IN DEVINST dnDevInst,
  1555. IN ULONG ulFlags
  1556. )
  1557. {
  1558. return CM_Disable_DevNode_Ex(dnDevInst, ulFlags, NULL);
  1559. }
  1560. CONFIGRET
  1561. CM_Enable_DevNode(
  1562. IN DEVINST dnDevInst,
  1563. IN ULONG ulFlags
  1564. )
  1565. {
  1566. return CM_Enable_DevNode_Ex(dnDevInst, ulFlags, NULL);
  1567. }
  1568. CONFIGRET
  1569. CM_Get_DevNode_Status(
  1570. OUT PULONG pulStatus,
  1571. OUT PULONG pulProblemNumber,
  1572. IN DEVINST dnDevInst,
  1573. IN ULONG ulFlags
  1574. )
  1575. {
  1576. return CM_Get_DevNode_Status_Ex(pulStatus, pulProblemNumber,
  1577. dnDevInst, ulFlags, NULL);
  1578. }
  1579. CONFIGRET
  1580. CM_Set_DevNode_Problem(
  1581. IN DEVINST dnDevInst,
  1582. IN ULONG ulProblem,
  1583. IN ULONG ulFlags
  1584. )
  1585. {
  1586. return CM_Set_DevNode_Problem_Ex(dnDevInst, ulProblem, ulFlags, NULL);
  1587. }
  1588. CONFIGRET
  1589. CM_Reenumerate_DevNode(
  1590. IN DEVINST dnDevInst,
  1591. IN ULONG ulFlags
  1592. )
  1593. {
  1594. return CM_Reenumerate_DevNode_Ex(dnDevInst, ulFlags, NULL);
  1595. }
  1596. CONFIGRET
  1597. CM_Query_And_Remove_SubTree(
  1598. IN DEVINST dnAncestor,
  1599. OUT PPNP_VETO_TYPE pVetoType,
  1600. OUT LPWSTR pszVetoName,
  1601. IN ULONG ulNameLength,
  1602. IN ULONG ulFlags
  1603. )
  1604. {
  1605. return CM_Query_And_Remove_SubTree_Ex( dnAncestor,
  1606. pVetoType,
  1607. pszVetoName,
  1608. ulNameLength,
  1609. ulFlags,
  1610. NULL);
  1611. }
  1612. CONFIGRET
  1613. CM_Query_And_Remove_SubTreeA(
  1614. IN DEVINST dnAncestor,
  1615. OUT PPNP_VETO_TYPE pVetoType,
  1616. OUT LPSTR pszVetoName,
  1617. IN ULONG ulNameLength,
  1618. IN ULONG ulFlags
  1619. )
  1620. {
  1621. return CM_Query_And_Remove_SubTree_ExA( dnAncestor,
  1622. pVetoType,
  1623. pszVetoName,
  1624. ulNameLength,
  1625. ulFlags,
  1626. NULL);
  1627. }
  1628. CONFIGRET
  1629. CM_Remove_SubTree(
  1630. IN DEVINST dnAncestor,
  1631. IN ULONG ulFlags
  1632. )
  1633. {
  1634. return CM_Remove_SubTree_Ex(dnAncestor, ulFlags, NULL);
  1635. }
  1636. CONFIGRET
  1637. CM_Uninstall_DevNode(
  1638. IN DEVNODE dnPhantom,
  1639. IN ULONG ulFlags
  1640. )
  1641. {
  1642. return CM_Uninstall_DevNode_Ex(dnPhantom, ulFlags, NULL);
  1643. }
  1644. CONFIGRET
  1645. CM_Add_IDW(
  1646. IN DEVINST dnDevInst,
  1647. IN PWSTR pszID,
  1648. IN ULONG ulFlags
  1649. )
  1650. {
  1651. return CM_Add_ID_ExW(dnDevInst, pszID, ulFlags, NULL);
  1652. }
  1653. CONFIGRET
  1654. CM_Add_IDA(
  1655. IN DEVINST dnDevInst,
  1656. IN PSTR pszID,
  1657. IN ULONG ulFlags
  1658. )
  1659. {
  1660. return CM_Add_ID_ExA(dnDevInst, pszID, ulFlags, NULL);
  1661. }
  1662. CMAPI
  1663. CONFIGRET
  1664. CM_Register_Device_Driver(
  1665. IN DEVINST dnDevInst,
  1666. IN ULONG ulFlags
  1667. )
  1668. {
  1669. return CM_Register_Device_Driver_Ex(dnDevInst, ulFlags, NULL);
  1670. }
  1671. CONFIGRET
  1672. CM_Query_Remove_SubTree(
  1673. IN DEVINST dnAncestor,
  1674. IN ULONG ulFlags
  1675. )
  1676. {
  1677. return CM_Query_Remove_SubTree_Ex(dnAncestor, ulFlags, NULL);
  1678. }
  1679. CONFIGRET
  1680. CM_Request_Device_EjectW(
  1681. IN DEVINST dnDevInst,
  1682. OUT PPNP_VETO_TYPE pVetoType,
  1683. OUT LPWSTR pszVetoName,
  1684. IN ULONG ulNameLength,
  1685. IN ULONG ulFlags
  1686. )
  1687. {
  1688. return CM_Request_Device_Eject_ExW(dnDevInst,
  1689. pVetoType,
  1690. pszVetoName,
  1691. ulNameLength,
  1692. ulFlags,
  1693. NULL);
  1694. }
  1695. CONFIGRET
  1696. CM_Request_Device_EjectA(
  1697. IN DEVNODE dnDevInst,
  1698. OUT PPNP_VETO_TYPE pVetoType,
  1699. OUT LPSTR pszVetoName,
  1700. IN ULONG ulNameLength,
  1701. IN ULONG ulFlags
  1702. )
  1703. {
  1704. return CM_Request_Device_Eject_ExA( dnDevInst,
  1705. pVetoType,
  1706. pszVetoName,
  1707. ulNameLength,
  1708. ulFlags,
  1709. NULL);
  1710. }
  1711. //-------------------------------------------------------------------
  1712. // ANSI STUBS
  1713. //-------------------------------------------------------------------
  1714. CONFIGRET
  1715. CM_Add_ID_ExA(
  1716. IN DEVINST dnDevInst,
  1717. IN PSTR pszID,
  1718. IN ULONG ulFlags,
  1719. IN HMACHINE hMachine
  1720. )
  1721. {
  1722. CONFIGRET Status = CR_SUCCESS;
  1723. PWSTR pUniID = NULL;
  1724. if (pSetupCaptureAndConvertAnsiArg(pszID, &pUniID) == NO_ERROR) {
  1725. Status = CM_Add_ID_ExW(dnDevInst,
  1726. pUniID,
  1727. ulFlags,
  1728. hMachine);
  1729. pSetupFree(pUniID);
  1730. } else {
  1731. Status = CR_INVALID_POINTER;
  1732. }
  1733. return Status;
  1734. } // CM_Add_ID_ExA
  1735. CONFIGRET
  1736. CM_Create_DevNode_ExA(
  1737. OUT PDEVINST pdnDevInst,
  1738. IN DEVINSTID_A pDeviceID,
  1739. IN DEVINST dnParent,
  1740. IN ULONG ulFlags,
  1741. IN HMACHINE hMachine
  1742. )
  1743. {
  1744. CONFIGRET Status = CR_SUCCESS;
  1745. PWSTR pUniDeviceID = NULL;
  1746. if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) == NO_ERROR) {
  1747. Status = CM_Create_DevNode_ExW(pdnDevInst,
  1748. pUniDeviceID,
  1749. dnParent,
  1750. ulFlags,
  1751. hMachine);
  1752. pSetupFree(pUniDeviceID);
  1753. } else {
  1754. Status = CR_INVALID_DEVICE_ID;
  1755. }
  1756. return Status;
  1757. } // CM_Create_DevNode_ExA
  1758. CONFIGRET
  1759. CM_Query_And_Remove_SubTree_ExA(
  1760. IN DEVINST dnAncestor,
  1761. OUT PPNP_VETO_TYPE pVetoType,
  1762. OUT LPSTR pszVetoName,
  1763. IN ULONG ulNameLength,
  1764. IN ULONG ulFlags,
  1765. IN HMACHINE hMachine
  1766. )
  1767. {
  1768. CONFIGRET Status = CR_SUCCESS, tmpStatus;
  1769. PWSTR pUniVetoName = NULL;
  1770. ULONG ulAnsiBufferLen;
  1771. size_t UniBufferLen = 0;
  1772. //
  1773. // validate essential parameters only
  1774. //
  1775. if ((!ARGUMENT_PRESENT(pszVetoName)) && (ulNameLength != 0)) {
  1776. return CR_INVALID_POINTER;
  1777. }
  1778. if (ulNameLength != 0) {
  1779. //
  1780. // pass a Unicode buffer instead and convert back to caller's
  1781. // ANSI buffer on return
  1782. //
  1783. pUniVetoName = pSetupMalloc(MAX_VETO_NAME_LENGTH*sizeof(WCHAR));
  1784. if (pUniVetoName == NULL) {
  1785. return CR_OUT_OF_MEMORY;
  1786. }
  1787. }
  1788. //
  1789. // call the wide version
  1790. //
  1791. Status = CM_Query_And_Remove_SubTree_ExW(dnAncestor,
  1792. pVetoType,
  1793. pUniVetoName,
  1794. MAX_VETO_NAME_LENGTH,
  1795. ulFlags,
  1796. hMachine);
  1797. //
  1798. // We should never return a veto name longer than MAX_VETO_NAME_LENGTH.
  1799. //
  1800. ASSERT(Status != CR_BUFFER_SMALL);
  1801. if ((Status == CR_REMOVE_VETOED) && (ARGUMENT_PRESENT(pszVetoName))) {
  1802. //
  1803. // convert the unicode buffer to an ANSI string and copy to the caller's
  1804. // buffer
  1805. //
  1806. ASSERT(pUniVetoName != NULL);
  1807. if (FAILED(StringCchLength(
  1808. pUniVetoName,
  1809. MAX_VETO_NAME_LENGTH,
  1810. &UniBufferLen))) {
  1811. //
  1812. // the returned veto name is not a valid length (shouldn't happen),
  1813. // but still return that a veto occurred.
  1814. //
  1815. return CR_REMOVE_VETOED;
  1816. }
  1817. ulAnsiBufferLen = ulNameLength;
  1818. tmpStatus =
  1819. PnPUnicodeToMultiByte(
  1820. pUniVetoName,
  1821. (ULONG)((UniBufferLen + 1)*sizeof(WCHAR)),
  1822. pszVetoName,
  1823. &ulAnsiBufferLen);
  1824. //
  1825. // if conversion was unsuccessful, return that status instead
  1826. //
  1827. if (tmpStatus != CR_SUCCESS) {
  1828. Status = tmpStatus;
  1829. }
  1830. }
  1831. if (pUniVetoName != NULL) {
  1832. pSetupFree(pUniVetoName);
  1833. }
  1834. return Status;
  1835. } // CM_Query_And_Remove_SubTree_ExA
  1836. CONFIGRET
  1837. CM_Request_Device_Eject_ExA(
  1838. IN DEVNODE dnDevInst,
  1839. OUT PPNP_VETO_TYPE pVetoType,
  1840. OUT LPSTR pszVetoName,
  1841. IN ULONG ulNameLength,
  1842. IN ULONG ulFlags,
  1843. IN HMACHINE hMachine
  1844. )
  1845. {
  1846. CONFIGRET Status = CR_SUCCESS, tmpStatus;
  1847. PWSTR pUniVetoName = NULL;
  1848. ULONG ulAnsiBufferLen;
  1849. size_t UniBufferLen = 0;
  1850. //
  1851. // validate essential parameters only
  1852. //
  1853. if ((!ARGUMENT_PRESENT(pszVetoName)) && (ulNameLength != 0)) {
  1854. return CR_INVALID_POINTER;
  1855. }
  1856. if (ulNameLength != 0) {
  1857. //
  1858. // pass a Unicode buffer instead and convert back to caller's
  1859. // ANSI buffer on return
  1860. //
  1861. pUniVetoName = pSetupMalloc(MAX_VETO_NAME_LENGTH*sizeof(WCHAR));
  1862. if (pUniVetoName == NULL) {
  1863. return CR_OUT_OF_MEMORY;
  1864. }
  1865. }
  1866. //
  1867. // call the wide version
  1868. //
  1869. Status = CM_Request_Device_Eject_ExW(dnDevInst,
  1870. pVetoType,
  1871. pUniVetoName,
  1872. MAX_VETO_NAME_LENGTH,
  1873. ulFlags,
  1874. hMachine);
  1875. //
  1876. // We should never return a veto name longer than MAX_VETO_NAME_LENGTH.
  1877. //
  1878. ASSERT(Status != CR_BUFFER_SMALL);
  1879. if ((Status == CR_REMOVE_VETOED) && (ARGUMENT_PRESENT(pszVetoName))) {
  1880. //
  1881. // convert the unicode buffer to an ANSI string and copy to the caller's
  1882. // buffer
  1883. //
  1884. ASSERT(pUniVetoName != NULL);
  1885. if (FAILED(StringCchLength(
  1886. pUniVetoName,
  1887. MAX_VETO_NAME_LENGTH,
  1888. &UniBufferLen))) {
  1889. //
  1890. // the returned veto name is not a valid length (shouldn't happen),
  1891. // but still return that a veto occurred.
  1892. //
  1893. return CR_REMOVE_VETOED;
  1894. }
  1895. ulAnsiBufferLen = ulNameLength;
  1896. tmpStatus =
  1897. PnPUnicodeToMultiByte(
  1898. pUniVetoName,
  1899. (ULONG)((UniBufferLen + 1)*sizeof(WCHAR)),
  1900. pszVetoName,
  1901. &ulAnsiBufferLen);
  1902. //
  1903. // if conversion was unsuccessful, return that status instead
  1904. //
  1905. if (tmpStatus != CR_SUCCESS) {
  1906. Status = tmpStatus;
  1907. }
  1908. }
  1909. if (pUniVetoName != NULL) {
  1910. pSetupFree(pUniVetoName);
  1911. }
  1912. return Status;
  1913. } // CM_Request_Device_Eject_ExA
  1914.