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.

3652 lines
101 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. rdevnode.c
  5. Abstract:
  6. This module contains the server-side device node APIs.
  7. PNP_CreateDevInst
  8. PNP_DeviceInstanceAction
  9. PNP_GetDeviceStatus
  10. PNP_SetDeviceProblem
  11. PNP_UninstallDevInst
  12. PNP_AddID
  13. PNP_RegisterDriver
  14. PNP_QueryRemove
  15. PNP_DisableDevInst
  16. PNP_RequestDeviceEject
  17. Author:
  18. Paula Tomlinson (paulat) 7-11-1995
  19. Environment:
  20. User-mode only.
  21. Revision History:
  22. 11-July-1995 paulat
  23. Creation and initial implementation.
  24. --*/
  25. //
  26. // includes
  27. //
  28. #include "precomp.h"
  29. #pragma hdrstop
  30. #include "umpnpi.h"
  31. #include "umpnpdat.h"
  32. //
  33. // private prototypes
  34. //
  35. CONFIGRET
  36. SetupDevInst(
  37. IN PCWSTR pszDeviceID,
  38. IN ULONG ulFlags
  39. );
  40. CONFIGRET
  41. CreateDefaultDeviceInstance(
  42. IN PCWSTR pszDeviceID,
  43. IN PCWSTR pszParentID,
  44. IN BOOL bPhantom,
  45. IN BOOL bMigrated
  46. );
  47. ULONG
  48. GetCurrentConfigFlag(
  49. IN PCWSTR pDeviceID
  50. );
  51. BOOL
  52. MarkDevicePhantom(
  53. IN HKEY hKey,
  54. IN ULONG ulValue
  55. );
  56. CONFIGRET
  57. GenerateDeviceInstance(
  58. OUT LPWSTR pszFullDeviceID,
  59. IN LPWSTR pszDeviceID,
  60. IN ULONG ulDevId
  61. );
  62. BOOL
  63. IsDeviceRegistered(
  64. IN LPCWSTR pszDeviceID,
  65. IN LPCWSTR pszService
  66. );
  67. BOOL
  68. IsPrivatePhantomFromFirmware(
  69. IN HKEY hKey
  70. );
  71. typedef struct {
  72. LIST_ENTRY ListEntry;
  73. WCHAR DevInst[ANYSIZE_ARRAY];
  74. } ENUM_ELEMENT, *PENUM_ELEMENT;
  75. CONFIGRET
  76. EnumerateSubTreeTopDownBreadthFirstWorker(
  77. IN handle_t BindingHandle,
  78. IN LPCWSTR DevInst,
  79. IN OUT PLIST_ENTRY ListHead
  80. );
  81. //
  82. // global data
  83. //
  84. extern HKEY ghEnumKey; // Key to HKLM\CCC\System\Enum - DO NOT MODIFY
  85. extern HKEY ghServicesKey; // Key to HKLM\CCC\System\Services - DO NOT MODIFY
  86. CONFIGRET
  87. PNP_CreateDevInst(
  88. IN handle_t hBinding,
  89. IN OUT LPWSTR pszDeviceID,
  90. IN LPWSTR pszParentDeviceID,
  91. IN ULONG ulLength,
  92. IN ULONG ulFlags
  93. )
  94. /*++
  95. Routine Description:
  96. This is the RPC server entry point for the CM_Create_DevNode routine.
  97. Arguments:
  98. hBinding RPC binding handle.
  99. pszDeviceID Device instance to create.
  100. pszParentDeviceID Parent of the new device.
  101. ulLength Max length of pszDeviceID on input and output.
  102. ulFlags Supplies flags specifying options for the creation of the
  103. device instance. May be one of the following values:
  104. CM_CREATE_DEVNODE_NORMAL
  105. Create the device instance now, and perform installation
  106. for it at a later time.
  107. CM_CREATE_DEVNODE_PHANTOM
  108. Create a phantom device instance (i.e., a handle to a
  109. device instance that is not alive as far as the ConfigMgr
  110. APIs are concerned). This may be used for CM APIs that
  111. require a devnode handle, but for which no real devnode
  112. currently exists (e.g., registry property APIs). This
  113. flag may not be specified with CR_CREATE_DEVNODE_NORMAL.
  114. CM_CREATE_DEVNODE_GENERATE_ID
  115. Create a Root-enumerated devnode using a unique device
  116. instance ID generated from the supplied device ID in
  117. pszDeviceID. If this flag is set, then pszDeviceID is
  118. assumed to contain simply a device ID (i.e., no enumerator
  119. key prefix, and no device instance suffix). A unique
  120. 4-digit, base-10 identifier string will be created under
  121. Enum\Root\<pszDeviceID>, and the devnode will be created
  122. based on that device instance ID. For instance, to add a
  123. new legacy COM port devnode, this API would be called with
  124. a pszDeviceID of *PNP0500. Assuming there was already one
  125. COM port instance in the registry (instance 0000), the new
  126. device instance ID would be: Root\*PNP0500\0001 The caller
  127. may find out what device instance name was generated by
  128. calling CM_Get_Device_ID with the devnode returned from
  129. this API.
  130. CM_CREATE_DEVNODE_DO_NOT_INSTALL
  131. If this flag is set, the device will be registered as
  132. controlled by the Service currently specified for the
  133. device, by the CM_DRP_SERVICE device registry property.
  134. Return Value:
  135. If the function succeeds, the return value is CR_SUCCESS. Otherwise it
  136. returns a CR_ error code.
  137. --*/
  138. {
  139. CONFIGRET Status = CR_SUCCESS;
  140. ULONG RegStatus = ERROR_SUCCESS;
  141. HKEY hKey = NULL;
  142. WCHAR szFullDeviceID[MAX_DEVICE_ID_LEN];
  143. ULONG ulStatusFlag=0, ulConfigFlag=0, ulCSConfigFlag=0, ulProblem=0;
  144. ULONG ulPhantom = 0, ulMigrated = 0;
  145. ULONG ulSize=0;
  146. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  147. WCHAR szService[MAX_PATH];
  148. NTSTATUS ntStatus;
  149. HRESULT hr;
  150. size_t DeviceIDLen = 0;
  151. try {
  152. //
  153. // Verify client "write" access.
  154. //
  155. if (!VerifyClientAccess(hBinding,
  156. PLUGPLAY_WRITE)) {
  157. Status = CR_ACCESS_DENIED;
  158. goto Clean0;
  159. }
  160. //
  161. // validate parameters
  162. //
  163. if (INVALID_FLAGS(ulFlags, CM_CREATE_DEVNODE_BITS)) {
  164. Status = CR_INVALID_FLAG;
  165. goto Clean0;
  166. }
  167. if (!ARGUMENT_PRESENT(pszDeviceID)) {
  168. Status = CR_INVALID_POINTER;
  169. goto Clean0;
  170. }
  171. ASSERT(ARGUMENT_PRESENT(pszParentDeviceID));
  172. if (!ARGUMENT_PRESENT(pszParentDeviceID)) {
  173. Status = CR_INVALID_POINTER;
  174. goto Clean0;
  175. }
  176. //
  177. // Additionally, Windows NT does not support the
  178. // CM_CREATE_DEVNODE_NO_WAIT_INSTALL flag.
  179. //
  180. if (ulFlags & CM_CREATE_DEVNODE_NO_WAIT_INSTALL) {
  181. Status = CR_INVALID_FLAG;
  182. goto Clean0;
  183. }
  184. //
  185. // Validate that parent is the root devnode. This routine only allows
  186. // the creation of root-enumerated devices.
  187. //
  188. if (!IsRootDeviceID(pszParentDeviceID)) {
  189. Status = CR_INVALID_DEVINST;
  190. goto Clean0;
  191. }
  192. //
  193. // create a unique instance value if requested
  194. //
  195. if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID) {
  196. Status =
  197. GenerateDeviceInstance(
  198. szFullDeviceID,
  199. pszDeviceID,
  200. MAX_DEVICE_ID_LEN);
  201. if (Status != CR_SUCCESS) {
  202. goto Clean0;
  203. }
  204. if (FAILED(StringCchLength(
  205. szFullDeviceID,
  206. MAX_DEVICE_ID_LEN,
  207. &DeviceIDLen))) {
  208. Status = CR_INVALID_DEVICE_ID;
  209. goto Clean0;
  210. }
  211. ASSERT(DeviceIDLen > 0);
  212. ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
  213. if (((ULONG)(DeviceIDLen + 1)) > ulLength) {
  214. Status = CR_BUFFER_SMALL;
  215. goto Clean0;
  216. }
  217. hr = StringCchCopyEx(pszDeviceID,
  218. ulLength,
  219. szFullDeviceID,
  220. NULL, NULL,
  221. STRSAFE_NULL_ON_FAILURE);
  222. ASSERT(HRESULT_CODE(hr) != ERROR_INSUFFICIENT_BUFFER);
  223. if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
  224. Status = CR_BUFFER_SMALL;
  225. goto Clean0;
  226. } else if (FAILED(hr)) {
  227. Status = CR_FAILURE;
  228. goto Clean0;
  229. }
  230. }
  231. //
  232. // try opening the registry key for this device instance
  233. //
  234. RegStatus = RegOpenKeyEx(ghEnumKey, pszDeviceID, 0,
  235. KEY_READ | KEY_WRITE, &hKey);
  236. KdPrintEx((DPFLTR_PNPMGR_ID,
  237. DBGF_REGISTRY,
  238. "UMPNPMGR: PNP_CreateDevInst opened key %ws\n",
  239. pszDeviceID));
  240. //
  241. // if the key already exists, check if it is marked as "Migrated".
  242. //
  243. if (RegStatus == ERROR_SUCCESS) {
  244. ulSize = sizeof(ULONG);
  245. if (RegQueryValueEx(hKey,
  246. pszRegValueMigrated,
  247. NULL,
  248. NULL,
  249. (LPBYTE)&ulMigrated,
  250. &ulSize) != ERROR_SUCCESS) {
  251. ulMigrated = 0;
  252. } else {
  253. //
  254. // if the value exists at all, be paranoid and check that it's 1
  255. //
  256. ASSERT(ulMigrated == 1);
  257. }
  258. }
  259. //
  260. // first handle phantom devnode case
  261. //
  262. if (ulFlags & CM_CREATE_DEVNODE_PHANTOM) {
  263. //
  264. // for a phantom devnode, it must not already exist in the registry
  265. // unless it's an unregistered firmware mapper device instance.
  266. //
  267. if (RegStatus == ERROR_SUCCESS) {
  268. ASSERT(hKey != NULL);
  269. //
  270. // Check to see if the device is migrated, or is a firmware
  271. // mapper-created phantom--if so, it's OK to allow the create to
  272. // succeed.
  273. //
  274. if (ulMigrated != 0) {
  275. //
  276. // this key was specifically request (not generated) so it
  277. // will be used -- remove the migrated value.
  278. //
  279. RegDeleteValue(hKey, pszRegValueMigrated);
  280. Status = CR_SUCCESS;
  281. } else if (IsPrivatePhantomFromFirmware(hKey)) {
  282. Status = CR_SUCCESS;
  283. } else {
  284. Status = CR_ALREADY_SUCH_DEVINST;
  285. }
  286. goto Clean0;
  287. }
  288. //
  289. // it doesn't exist in the registry so create a phantom devnode
  290. //
  291. CreateDefaultDeviceInstance(pszDeviceID,
  292. pszParentDeviceID,
  293. TRUE,
  294. FALSE);
  295. goto Clean0;
  296. }
  297. //
  298. // for a normal devnode, fail if the device is already present in the
  299. // registry and alive, and not migrated
  300. //
  301. if ((RegStatus == ERROR_SUCCESS) &&
  302. (IsDeviceIdPresent(pszDeviceID)) &&
  303. (ulMigrated == 0)) {
  304. //
  305. // Set status to NEEDS ENUM and fail the create call.
  306. //
  307. Status = CR_ALREADY_SUCH_DEVINST;
  308. goto Clean0;
  309. }
  310. //
  311. // if couldn't open the device instance, or the key was migrated, then
  312. // most likely the key doesn't exist yet, or should be treated as if it
  313. // doesn't exist yet, so create a device instance key with default
  314. // values.
  315. //
  316. if ((RegStatus != ERROR_SUCCESS) || (ulMigrated != 0)) {
  317. //
  318. // this key will be used -- remove the migrated value
  319. // and close the key.
  320. //
  321. if (ulMigrated != 0) {
  322. ASSERT(RegStatus == ERROR_SUCCESS);
  323. ASSERT(hKey != NULL);
  324. RegDeleteValue(hKey, pszRegValueMigrated);
  325. RegCloseKey(hKey);
  326. hKey = NULL;
  327. }
  328. //
  329. // create the default device instance, finding and unused instance
  330. // if necessary. if the key was migrated, a new key will not be
  331. // created, but the default instance data will be added to the
  332. // existing key.
  333. //
  334. CreateDefaultDeviceInstance(pszDeviceID,
  335. pszParentDeviceID,
  336. FALSE,
  337. (ulMigrated != 0));
  338. KdPrintEx((DPFLTR_PNPMGR_ID,
  339. DBGF_REGISTRY,
  340. "UMPNPMGR: PNP_CreateDevInst opened key %ws\n",
  341. pszDeviceID));
  342. RegStatus = RegOpenKeyEx(ghEnumKey, pszDeviceID, 0,
  343. KEY_READ | KEY_WRITE, &hKey);
  344. if (RegStatus != ERROR_SUCCESS) {
  345. Status = CR_REGISTRY_ERROR;
  346. goto Clean0;
  347. }
  348. }
  349. //
  350. // retrieve flags
  351. //
  352. ulConfigFlag = GetDeviceConfigFlags(pszDeviceID, hKey);
  353. ulCSConfigFlag = GetCurrentConfigFlag(pszDeviceID);
  354. //
  355. // check if the device is blocked
  356. //
  357. if ((ulCSConfigFlag & CSCONFIGFLAG_DO_NOT_CREATE) ||
  358. (ulConfigFlag & CONFIGFLAG_REMOVED) ||
  359. (ulConfigFlag & CONFIGFLAG_NET_BOOT)) {
  360. Status = CR_CREATE_BLOCKED;
  361. goto Clean0;
  362. }
  363. //
  364. // Call kernel-mode to create the device node
  365. //
  366. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  367. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  368. ControlData.Flags = 0;
  369. ntStatus = NtPlugPlayControl(PlugPlayControlInitializeDevice,
  370. &ControlData,
  371. sizeof(ControlData));
  372. if (!NT_SUCCESS(ntStatus)) {
  373. Status = CR_FAILURE;
  374. goto Clean0;
  375. }
  376. //
  377. // Retrieve devnode status
  378. //
  379. GetDeviceStatus(pszDeviceID, &ulStatusFlag, &ulProblem);
  380. //
  381. // Are we converting a phantom into a real devnode?
  382. //
  383. ulSize = sizeof(ULONG);
  384. if (RegQueryValueEx(hKey, pszRegValuePhantom, NULL, NULL,
  385. (LPBYTE)&ulPhantom, &ulSize) != ERROR_SUCCESS) {
  386. ulPhantom = 0;
  387. }
  388. if (ulPhantom) {
  389. //
  390. // If we're turning a phantom into a real devnode, suppress the found new
  391. // hardware popup for this device, then clear the phantom flag.
  392. //
  393. RegDeleteValue(hKey, pszRegValuePhantom);
  394. } else {
  395. //
  396. // if device not installed, set a problem
  397. //
  398. if (ulConfigFlag & CONFIGFLAG_REINSTALL ||
  399. ulConfigFlag & CONFIGFLAG_FAILEDINSTALL) {
  400. SetDeviceStatus(pszDeviceID, DN_HAS_PROBLEM, CM_PROB_NOT_CONFIGURED);
  401. }
  402. }
  403. if (ulFlags & CM_CREATE_DEVNODE_DO_NOT_INSTALL) {
  404. //
  405. // If the device has a service, register it
  406. //
  407. ulSize = MAX_PATH * sizeof(WCHAR);
  408. if (RegQueryValueEx(hKey, pszRegValueService, NULL, NULL,
  409. (LPBYTE)szService, &ulSize) == ERROR_SUCCESS) {
  410. if (szService[0] != L'\0') {
  411. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  412. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  413. ControlData.Flags = 0;
  414. NtPlugPlayControl(PlugPlayControlRegisterNewDevice,
  415. &ControlData,
  416. sizeof(ControlData));
  417. }
  418. }
  419. }
  420. Clean0:
  421. NOTHING;
  422. } except(EXCEPTION_EXECUTE_HANDLER) {
  423. Status = CR_FAILURE;
  424. }
  425. if (hKey != NULL) {
  426. RegCloseKey(hKey);
  427. }
  428. return Status;
  429. } // PNP_CreateDevInst
  430. CONFIGRET
  431. PNP_DeviceInstanceAction(
  432. IN handle_t hBinding,
  433. IN ULONG ulAction,
  434. IN ULONG ulFlags,
  435. IN PCWSTR pszDeviceInstance1,
  436. IN PCWSTR pszDeviceInstance2
  437. )
  438. /*++
  439. Routine Description:
  440. This is the RPC server entry point for the ConfigManager routines that
  441. perform some operation on DevNodes (such as create, setup, disable,
  442. and enable, etc). It handles various routines in this one routine by
  443. accepting a major and minor action value.
  444. Arguments:
  445. hBinding RPC binding handle.
  446. ulMajorAction Specifies the requested action to perform (one of the
  447. PNP_DEVINST_* values)
  448. ulFlags This value depends on the value of the ulMajorAction and
  449. further defines the specific action to perform
  450. pszDeviceInstance1 This is a device instance string to be used in
  451. performing the specified action, it's value depends on
  452. the ulMajorAction value.
  453. pszDeviceInstance2 Not used, must be NULL.
  454. Return Value:
  455. If the function succeeds, the return value is CR_SUCCESS.
  456. If the function fails, the return value is one of the following:
  457. CR_ALREADY_SUCH_DEVNODE,
  458. CR_INVALID_DEVICE_ID,
  459. CR_INVALID_DEVNODE,
  460. CR_INVALID_FLAG,
  461. CR_FAILURE,
  462. CR_NOT_DISABLEABLE,
  463. CR_INVALID_POINTER, or
  464. CR_OUT_OF_MEMORY.
  465. --*/
  466. {
  467. CONFIGRET Status = CR_SUCCESS;
  468. BOOL Locked = FALSE;
  469. PWSTR PrivilegedServiceAction = NULL;
  470. //
  471. // Verify client "execute" access
  472. //
  473. if (!VerifyClientAccess(hBinding,
  474. PLUGPLAY_EXECUTE)) {
  475. return CR_ACCESS_DENIED;
  476. }
  477. //
  478. // Verify client privilege
  479. //
  480. switch (ulAction) {
  481. case PNP_DEVINST_SETUP:
  482. PrivilegedServiceAction = L"Device Action (setup device)";
  483. break;
  484. case PNP_DEVINST_ENABLE:
  485. PrivilegedServiceAction = L"Device Action (enable device)";
  486. break;
  487. case PNP_DEVINST_REENUMERATE:
  488. PrivilegedServiceAction = L"Device Action (re-enumerate device)";
  489. break;
  490. case PNP_DEVINST_DISABLE:
  491. case PNP_DEVINST_QUERYREMOVE:
  492. case PNP_DEVINST_REMOVESUBTREE:
  493. case PNP_DEVINST_REQUEST_EJECT:
  494. case PNP_DEVINST_MOVE:
  495. PrivilegedServiceAction = L"Device Action (action not implemented)";
  496. break;
  497. default:
  498. PrivilegedServiceAction = L"Device Action (unknown action)";
  499. break;
  500. }
  501. if (!VerifyClientPrivilege(
  502. hBinding,
  503. SE_LOAD_DRIVER_PRIVILEGE,
  504. PrivilegedServiceAction)) {
  505. return CR_ACCESS_DENIED;
  506. }
  507. //
  508. // NOTE: We enter a critical section here to guard against concurrent
  509. // read/write operations to the "DisableCount" registry value of any
  510. // single device instance by SetupDevInst, EnableDevInst (called by this
  511. // routine, below), and DisableDevInst.
  512. //
  513. PNP_ENTER_SYNCHRONOUS_CALL();
  514. Locked = TRUE;
  515. try {
  516. //
  517. // Validate parameters.
  518. //
  519. if (ARGUMENT_PRESENT(pszDeviceInstance2)) {
  520. Status = CR_INVALID_POINTER;
  521. goto Clean0;
  522. }
  523. //
  524. // pass the request on to a private routine that handles each major
  525. // device instance action request
  526. //
  527. switch (ulAction) {
  528. case PNP_DEVINST_SETUP:
  529. if (IsLegalDeviceId(pszDeviceInstance1)) {
  530. Status = SetupDevInst(pszDeviceInstance1, ulFlags);
  531. } else {
  532. Status = CR_INVALID_DEVNODE;
  533. }
  534. break;
  535. case PNP_DEVINST_ENABLE:
  536. if (IsLegalDeviceId(pszDeviceInstance1)) {
  537. Status = EnableDevInst(pszDeviceInstance1, TRUE);
  538. } else {
  539. Status = CR_INVALID_DEVNODE;
  540. }
  541. break;
  542. case PNP_DEVINST_REENUMERATE:
  543. if (IsLegalDeviceId(pszDeviceInstance1)) {
  544. Status = ReenumerateDevInst(pszDeviceInstance1, TRUE, ulFlags);
  545. } else {
  546. Status = CR_INVALID_DEVNODE;
  547. }
  548. break;
  549. case PNP_DEVINST_DISABLE:
  550. Status = CR_CALL_NOT_IMPLEMENTED;
  551. break;
  552. case PNP_DEVINST_QUERYREMOVE:
  553. Status = CR_CALL_NOT_IMPLEMENTED;
  554. break;
  555. case PNP_DEVINST_REMOVESUBTREE:
  556. Status = CR_CALL_NOT_IMPLEMENTED;
  557. break;
  558. case PNP_DEVINST_REQUEST_EJECT:
  559. Status = CR_CALL_NOT_IMPLEMENTED;
  560. break;
  561. case PNP_DEVINST_MOVE:
  562. Status = CR_CALL_NOT_IMPLEMENTED;
  563. break;
  564. default:
  565. Status = CR_INVALID_FLAG;
  566. break;
  567. }
  568. Clean0:
  569. NOTHING;
  570. } except(EXCEPTION_EXECUTE_HANDLER) {
  571. Status = CR_FAILURE;
  572. //
  573. // Reference the following variables so the compiler will respect
  574. // statement ordering w.r.t. their assignment.
  575. //
  576. Locked = Locked;
  577. }
  578. if (Locked) {
  579. PNP_LEAVE_SYNCHRONOUS_CALL();
  580. }
  581. return Status;
  582. } // PNP_DeviceInstanceAction
  583. CONFIGRET
  584. PNP_GetDeviceStatus(
  585. IN handle_t hBinding,
  586. IN LPCWSTR pDeviceID,
  587. OUT PULONG pulStatus,
  588. OUT PULONG pulProblem,
  589. IN ULONG ulFlags
  590. )
  591. /*++
  592. Routine Description:
  593. This is the RPC server entry point for the ConfigManager
  594. CM_Get_DevNode_Status routines. It retrieves device instance specific
  595. status information.
  596. Arguments:
  597. hBinding RPC binding handle.
  598. pDeviceID This is a device instance string to retrieve status
  599. information for.
  600. pulStatus Pointer to ULONG variable to return Status Flags in
  601. pulProblem Pointer to ULONG variable to return Problem in
  602. ulFlags Not used, must be zero.
  603. Return Value:
  604. If the function succeeds, the return value is CR_SUCCESS.
  605. If the function fails, the return value is one of the following:
  606. CR_INVALID_DEVNODE,
  607. CR_INVALID_FLAG, or
  608. CR_INVALID_POINTER.
  609. --*/
  610. {
  611. CONFIGRET Status = CR_SUCCESS;
  612. ULONG PropertyData, DataSize, DataTransferLen, DataType;
  613. size_t DeviceIDLen = 0;
  614. UNREFERENCED_PARAMETER(hBinding);
  615. try {
  616. //
  617. // Validate parameters.
  618. //
  619. if (INVALID_FLAGS(ulFlags, 0)) {
  620. Status = CR_INVALID_FLAG;
  621. goto Clean0;
  622. }
  623. if ((!ARGUMENT_PRESENT(pulStatus)) ||
  624. (!ARGUMENT_PRESENT(pulProblem))) {
  625. Status = CR_INVALID_POINTER;
  626. goto Clean0;
  627. }
  628. *pulStatus = 0;
  629. *pulProblem = 0;
  630. if (FAILED(StringCchLength(
  631. pDeviceID,
  632. MAX_DEVICE_ID_LEN,
  633. &DeviceIDLen))) {
  634. Status = CR_INVALID_DEVNODE;
  635. goto Clean0;
  636. }
  637. ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
  638. if (DeviceIDLen == 0) {
  639. Status = CR_INVALID_DEVNODE;
  640. goto Clean0;
  641. }
  642. if (!IsLegalDeviceId(pDeviceID)) {
  643. Status = CR_INVALID_DEVNODE;
  644. goto Clean0;
  645. }
  646. //
  647. // Retrieve the Flags information from the DeviceNode (which is then
  648. // mapped into status and problem values).
  649. //
  650. Status = GetDeviceStatus(pDeviceID, pulStatus, pulProblem);
  651. if (Status != CR_SUCCESS) {
  652. goto Clean0;
  653. }
  654. //
  655. // Map special flags that aren't stored in the DeviceNode Flags field
  656. //
  657. //
  658. // DN_ROOT_ENUMERATED?
  659. //
  660. if (IsDeviceRootEnumerated(pDeviceID)) {
  661. //
  662. // Do not mark PnP BIOS enumerated as ROOT enumerated
  663. //
  664. // Bios enumerated devices look like:
  665. // Root\*aaannnn\PnPBIOS_n
  666. //
  667. if ((DeviceIDLen < (4 + 1 + 8 + 1 + 8)) ||
  668. (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE,
  669. &pDeviceID[14], 8,
  670. TEXT("PnPBIOS__"), 8) != CSTR_EQUAL)) {
  671. *pulStatus |= DN_ROOT_ENUMERATED;
  672. }
  673. }
  674. //
  675. // DN_REMOVABLE?
  676. //
  677. DataSize = DataTransferLen = sizeof(ULONG);
  678. if (CR_SUCCESS == PNP_GetDeviceRegProp(NULL,
  679. pDeviceID,
  680. CM_DRP_CAPABILITIES,
  681. &DataType,
  682. (LPBYTE)&PropertyData,
  683. &DataTransferLen,
  684. &DataSize,
  685. 0)) {
  686. if (PropertyData & CM_DEVCAP_REMOVABLE) {
  687. *pulStatus |= DN_REMOVABLE;
  688. }
  689. }
  690. //
  691. // DN_MANUAL?
  692. //
  693. DataSize = DataTransferLen = sizeof(ULONG);
  694. if (CR_SUCCESS != PNP_GetDeviceRegProp(NULL,
  695. pDeviceID,
  696. CM_DRP_CONFIGFLAGS,
  697. &DataType,
  698. (LPBYTE)&PropertyData,
  699. &DataTransferLen,
  700. &DataSize,
  701. 0)) {
  702. PropertyData = 0;
  703. }
  704. if (PropertyData & CONFIGFLAG_MANUAL_INSTALL) {
  705. *pulStatus |= DN_MANUAL;
  706. }
  707. //
  708. // If there isn't already a problem, check to see if the config flags indicate this
  709. // was a failed installation.
  710. //
  711. if (!(*pulStatus & DN_HAS_PROBLEM) && (PropertyData & CONFIGFLAG_FAILEDINSTALL)) {
  712. *pulStatus |= DN_HAS_PROBLEM;
  713. *pulProblem = CM_PROB_FAILED_INSTALL;
  714. }
  715. Clean0:
  716. NOTHING;
  717. } except(EXCEPTION_EXECUTE_HANDLER) {
  718. Status = CR_FAILURE;
  719. }
  720. return Status;
  721. } // PNP_GetDeviceStatus
  722. CONFIGRET
  723. PNP_SetDeviceProblem(
  724. IN handle_t hBinding,
  725. IN LPCWSTR pDeviceID,
  726. IN ULONG ulProblem,
  727. IN ULONG ulFlags
  728. )
  729. /*++
  730. Routine Description:
  731. This is the RPC server entry point for the ConfigManager
  732. CM_Set_DevNode_Problem routines. It set device instance specific
  733. problem information.
  734. Arguments:
  735. hBinding RPC binding handle.
  736. pDeviceID This is a device instance string to retrieve status
  737. information for.
  738. ulProblem A ULONG variable that specifies the Problem
  739. ulFlags May be one of the following two values:
  740. CM_SET_DEVNODE_PROBLEM_NORMAL -- only set problem
  741. if currently no problem
  742. CM_SET_DEVNODE_PROBLEM_OVERRIDE -- override current
  743. problem with new problem
  744. Return Value:
  745. If the function succeeds, the return value is CR_SUCCESS.
  746. If the function fails, the return value is one of the following:
  747. CR_INVALID_DEVNODE,
  748. CR_INVALID_FLAG.
  749. --*/
  750. {
  751. CONFIGRET Status = CR_SUCCESS;
  752. ULONG ulCurrentProblem = 0, ulCurrentStatus = 0;
  753. try {
  754. //
  755. // Verify client "execute" access
  756. //
  757. if (!VerifyClientAccess(hBinding,
  758. PLUGPLAY_EXECUTE)) {
  759. Status = CR_ACCESS_DENIED;
  760. goto Clean0;
  761. }
  762. //
  763. // Verify client privilege
  764. //
  765. if (!VerifyClientPrivilege(hBinding,
  766. SE_LOAD_DRIVER_PRIVILEGE,
  767. L"Device Action (set device problem code)")) {
  768. Status = CR_ACCESS_DENIED;
  769. goto Clean0;
  770. }
  771. //
  772. // Validate parameters
  773. //
  774. if (INVALID_FLAGS(ulFlags, CM_SET_DEVNODE_PROBLEM_BITS)) {
  775. Status = CR_INVALID_FLAG;
  776. goto Clean0;
  777. }
  778. if (!IsLegalDeviceId(pDeviceID)) {
  779. Status = CR_INVALID_DEVNODE;
  780. goto Clean0;
  781. }
  782. //
  783. // If there's already a problem, do nothing unless CM_SET_DEVNODE_PROBLEM_OVERRIDE
  784. // is specified.
  785. //
  786. Status = GetDeviceStatus(pDeviceID, &ulCurrentStatus, &ulCurrentProblem);
  787. if (Status != CR_SUCCESS) {
  788. goto Clean0;
  789. }
  790. if (ulProblem) {
  791. //
  792. // The caller is wanting to set a problem. Make sure that if the device
  793. // already has a problem, it's the same one as we're trying to set (unless
  794. // we're overriding the current problem).
  795. //
  796. if ((ulCurrentStatus & DN_HAS_PROBLEM) &&
  797. (ulCurrentProblem != ulProblem) &&
  798. ((ulFlags & CM_SET_DEVNODE_PROBLEM_BITS) != CM_SET_DEVNODE_PROBLEM_OVERRIDE)) {
  799. Status = CR_FAILURE;
  800. goto Clean0;
  801. }
  802. }
  803. if (!ulProblem) {
  804. Status = ClearDeviceStatus(pDeviceID, DN_HAS_PROBLEM, ulCurrentProblem);
  805. } else {
  806. Status = SetDeviceStatus(pDeviceID, DN_HAS_PROBLEM, ulProblem);
  807. }
  808. Clean0:
  809. NOTHING;
  810. } except(EXCEPTION_EXECUTE_HANDLER) {
  811. Status = CR_FAILURE;
  812. }
  813. return Status;
  814. } // PNP_SetDeviceProblem
  815. CONFIGRET
  816. PNP_UninstallDevInst(
  817. IN handle_t hBinding,
  818. IN LPCWSTR pDeviceID,
  819. IN ULONG ulFlags
  820. )
  821. /*++
  822. Routine Description:
  823. This is the RPC server entry point for the ConfigManager
  824. CM_Deinstall_DevNode routine. It removes the device instance
  825. registry key and any subkeys (only for phantoms).
  826. Arguments:
  827. hBinding RPC binding handle.
  828. pDeviceID The device instance to deinstall.
  829. ulFlags Not used, must be zero.
  830. Return Value:
  831. If the function succeeds, the return value is CR_SUCCESS.
  832. Otherwise it returns one of the CR_ERROR codes.
  833. --*/
  834. {
  835. CONFIGRET Status = CR_SUCCESS;
  836. ULONG ulStatus, ulProblem;
  837. try {
  838. //
  839. // Verify client "write" access
  840. //
  841. if (!VerifyClientAccess(hBinding,
  842. PLUGPLAY_WRITE)) {
  843. Status = CR_ACCESS_DENIED;
  844. goto Clean0;
  845. }
  846. //
  847. // Validate parameters
  848. //
  849. if (INVALID_FLAGS(ulFlags, 0)) {
  850. Status = CR_INVALID_FLAG;
  851. goto Clean0;
  852. }
  853. if (!IsLegalDeviceId(pDeviceID)) {
  854. Status = CR_INVALID_DEVNODE;
  855. goto Clean0;
  856. }
  857. //------------------------------------------------------------------
  858. // Uninstall deletes instance key (and all subkeys) for all
  859. // the hardware keys (this means the main Enum branch, the
  860. // config specific keys under HKLM, and the Enum branch under
  861. // HKCU). In the case of the user hardware keys (under HKCU),
  862. // I delete those whether it's a phantom or not, but since
  863. // I can't access the user key from the service side, I have
  864. // to do that part on the client side. For the main hw Enum key
  865. // and the config specific hw keys, I only delete them outright
  866. // if they are phantoms. If not a phantom, then I just make the
  867. // device instance volatile (by saving the original key, deleting
  868. // old key, creating new volatile key and restoring the old
  869. // contents) so at least it will go away during the next boot
  870. //------------------------------------------------------------------
  871. if ((GetDeviceStatus(pDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) &&
  872. (ulStatus & DN_DRIVER_LOADED)) {
  873. //-------------------------------------------------------------
  874. // device is not a phantom
  875. //-------------------------------------------------------------
  876. if ((ulStatus & DN_ROOT_ENUMERATED)!=0 &&
  877. (ulStatus & DN_DISABLEABLE)==0) {
  878. //
  879. // if a device is root enumerated, but not disableable, it is not uninstallable
  880. // return status is CR_NOT_DISABLEABLE, as that is why it cannot be uninstalled
  881. //
  882. KdPrintEx((DPFLTR_PNPMGR_ID,
  883. DBGF_REGISTRY,
  884. "UMPNPMGR: PNP_UninstallDevInst failed uninstall of %ws (this root device is not disableable)\n",
  885. pDeviceID));
  886. Status = CR_NOT_DISABLEABLE;
  887. } else {
  888. //
  889. // do the volatile-copy-thing
  890. //
  891. KdPrintEx((DPFLTR_PNPMGR_ID,
  892. DBGF_REGISTRY,
  893. "UMPNPMGR: PNP_UninstallDevInst doing volatile key thing on %ws\n",
  894. pDeviceID));
  895. Status = UninstallRealDevice(pDeviceID);
  896. }
  897. } else {
  898. //-------------------------------------------------------------
  899. // device is a phantom
  900. //-------------------------------------------------------------
  901. //
  902. // deregister the device, and delete the registry keys.
  903. //
  904. Status = UninstallPhantomDevice(pDeviceID);
  905. if (Status != CR_SUCCESS) {
  906. goto Clean0;
  907. }
  908. //
  909. // if it is a root enumerated device, we need to reenumerate the
  910. // root so that the PDO will go away, otherwise a new device could
  911. // be created and the root enumerator would get very confused.
  912. //
  913. if (IsDeviceRootEnumerated(pDeviceID)) {
  914. ReenumerateDevInst(pszRegRootEnumerator, FALSE, 0);
  915. }
  916. }
  917. Clean0:
  918. NOTHING;
  919. } except(EXCEPTION_EXECUTE_HANDLER) {
  920. Status = CR_FAILURE;
  921. }
  922. return Status;
  923. } // PNP_UninstallDevInst
  924. CONFIGRET
  925. PNP_AddID(
  926. IN handle_t hBinding,
  927. IN LPCWSTR pszDeviceID,
  928. IN LPCWSTR pszID,
  929. IN ULONG ulFlags
  930. )
  931. /*++
  932. Routine Description:
  933. This is the RPC server entry point for the ConfigManager
  934. CM_Add_ID routine. It adds a hardware or compatible ID to
  935. the registry for this device instance.
  936. Arguments:
  937. hBinding RPC binding handle.
  938. pszDeviceID The device instance to add an ID for.
  939. pszID The hardware or compatible ID to add.
  940. ulFlags Specifies the type of ID to add.
  941. May be one of the following two values:
  942. CM_ADD_ID_HARDWARE -- add hardware ID
  943. CM_ADD_ID_COMPATIBLE -- add compatible ID
  944. Return Value:
  945. If the function succeeds, the return value is CR_SUCCESS.
  946. Otherwise it returns one of the CR_ERROR codes.
  947. --*/
  948. {
  949. CONFIGRET Status = CR_SUCCESS;
  950. WCHAR szCurrentID[REGSTR_VAL_MAX_HCID_LEN];
  951. ULONG ulLength = 0, transferLength, type;
  952. size_t IDLen = 0;
  953. try {
  954. //
  955. // Verify client "write" access
  956. //
  957. if (!VerifyClientAccess(hBinding,
  958. PLUGPLAY_WRITE)) {
  959. Status = CR_ACCESS_DENIED;
  960. goto Clean0;
  961. }
  962. //
  963. // Validate parameters
  964. //
  965. if (INVALID_FLAGS(ulFlags, CM_ADD_ID_BITS)) {
  966. Status = CR_INVALID_FLAG;
  967. goto Clean0;
  968. }
  969. if (!ARGUMENT_PRESENT(pszID)) {
  970. Status = CR_INVALID_POINTER;
  971. goto Clean0;
  972. }
  973. //
  974. // Make sure the NULL-terminated ID, plus the double-NULL terminating
  975. // character is not larger than the max size for a multi-sz hardware or
  976. // compatible id.
  977. //
  978. if (FAILED(StringCchLength(
  979. pszID,
  980. REGSTR_VAL_MAX_HCID_LEN - 1,
  981. &IDLen))) {
  982. Status = CR_INVALID_POINTER;
  983. goto Clean0;
  984. }
  985. ASSERT((IDLen + 2) <= REGSTR_VAL_MAX_HCID_LEN);
  986. szCurrentID[0] = L'\0';
  987. ulLength = REGSTR_VAL_MAX_HCID_LEN * sizeof(WCHAR);
  988. transferLength = ulLength;
  989. Status = PNP_GetDeviceRegProp(hBinding,
  990. pszDeviceID,
  991. (ulFlags == CM_ADD_ID_HARDWARE)? CM_DRP_HARDWAREID : CM_DRP_COMPATIBLEIDS,
  992. &type,
  993. (LPBYTE)szCurrentID,
  994. &transferLength,
  995. &ulLength,
  996. 0);
  997. if (Status == CR_SUCCESS) {
  998. if (!MultiSzSearchStringW(szCurrentID, pszID)) {
  999. //
  1000. // This ID is not already in the list, so append the new ID
  1001. // to the end of the existing IDs and write it back to the
  1002. // registry
  1003. //
  1004. ulLength = REGSTR_VAL_MAX_HCID_LEN*sizeof(WCHAR);
  1005. if (MultiSzAppendW(szCurrentID,
  1006. &ulLength,
  1007. pszID)) {
  1008. Status = PNP_SetDeviceRegProp(hBinding,
  1009. pszDeviceID,
  1010. (ulFlags == CM_ADD_ID_HARDWARE)? CM_DRP_HARDWAREID : CM_DRP_COMPATIBLEIDS,
  1011. REG_MULTI_SZ,
  1012. (LPBYTE)szCurrentID,
  1013. ulLength,
  1014. 0);
  1015. } else {
  1016. //
  1017. // Couldn't append the new ID to the multi-sz.
  1018. //
  1019. Status = CR_FAILURE;
  1020. goto Clean0;
  1021. }
  1022. }
  1023. } else {
  1024. //
  1025. // write out the id with a double null terminator
  1026. //
  1027. PWCHAR pszDestEnd = NULL;
  1028. size_t cchRemaining = 0;
  1029. if (FAILED(StringCchCopyEx(
  1030. szCurrentID,
  1031. SIZECHARS(szCurrentID),
  1032. pszID,
  1033. &pszDestEnd,
  1034. &cchRemaining,
  1035. STRSAFE_NULL_ON_FAILURE))) {
  1036. Status = CR_FAILURE;
  1037. goto Clean0;
  1038. }
  1039. ASSERT(pszDestEnd != NULL);
  1040. ASSERT(cchRemaining > 0);
  1041. if (cchRemaining < 2) {
  1042. Status = CR_FAILURE;
  1043. goto Clean0;
  1044. }
  1045. pszDestEnd[0] = L'\0';
  1046. pszDestEnd[1] = L'\0';
  1047. if (FAILED(StringCchLength(
  1048. szCurrentID,
  1049. REGSTR_VAL_MAX_HCID_LEN - 1,
  1050. &IDLen))) {
  1051. Status = CR_FAILURE;
  1052. goto Clean0;
  1053. }
  1054. ASSERT((IDLen + 1) < REGSTR_VAL_MAX_HCID_LEN);
  1055. Status = PNP_SetDeviceRegProp(hBinding,
  1056. pszDeviceID,
  1057. (ulFlags == CM_ADD_ID_HARDWARE)? CM_DRP_HARDWAREID : CM_DRP_COMPATIBLEIDS,
  1058. REG_MULTI_SZ,
  1059. (LPBYTE)szCurrentID,
  1060. (ULONG)((IDLen+2)*sizeof(WCHAR)),
  1061. 0);
  1062. }
  1063. Clean0:
  1064. NOTHING;
  1065. } except(EXCEPTION_EXECUTE_HANDLER) {
  1066. Status = CR_FAILURE;
  1067. }
  1068. return Status;
  1069. } // PNP_AddID
  1070. CONFIGRET
  1071. PNP_RegisterDriver(
  1072. IN handle_t hBinding,
  1073. IN LPCWSTR pszDeviceID,
  1074. IN ULONG ulFlags
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This is the RPC server entry point for the ConfigManager
  1079. CM_Register_Device_Driver routine. It setups flags for the
  1080. driver/device and enumerates it.
  1081. Arguments:
  1082. hBinding RPC binding handle.
  1083. pszDeviceID The device instance to register the driver for.
  1084. ulFlags Flags associated with the driver.
  1085. Return Value:
  1086. If the function succeeds, the return value is CR_SUCCESS.
  1087. Otherwise it returns one of the CR_ERROR codes.
  1088. --*/
  1089. {
  1090. CONFIGRET Status = CR_SUCCESS;
  1091. ULONG ulStatusFlag = 0;
  1092. try {
  1093. //
  1094. // Verify client "execute" access
  1095. //
  1096. if (!VerifyClientAccess(hBinding,
  1097. PLUGPLAY_EXECUTE)) {
  1098. Status = CR_ACCESS_DENIED;
  1099. goto Clean0;
  1100. }
  1101. //
  1102. // Verify client privilege
  1103. //
  1104. if (!VerifyClientPrivilege(hBinding,
  1105. SE_LOAD_DRIVER_PRIVILEGE,
  1106. L"Device Action (register device driver)")) {
  1107. Status = CR_ACCESS_DENIED;
  1108. goto Clean0;
  1109. }
  1110. //
  1111. // Validate parameters
  1112. //
  1113. if (INVALID_FLAGS(ulFlags, CM_REGISTER_DEVICE_DRIVER_BITS)) {
  1114. Status = CR_INVALID_FLAG;
  1115. goto Clean0;
  1116. }
  1117. if (!IsLegalDeviceId(pszDeviceID)) {
  1118. Status = CR_INVALID_DEVNODE;
  1119. goto Clean0;
  1120. }
  1121. SetDeviceStatus(pszDeviceID, ulStatusFlag, 0);
  1122. Clean0:
  1123. NOTHING;
  1124. } except(EXCEPTION_EXECUTE_HANDLER) {
  1125. Status = CR_FAILURE;
  1126. }
  1127. return Status;
  1128. } // PNP_RegisterDriver
  1129. CONFIGRET
  1130. PNP_QueryRemove(
  1131. IN handle_t hBinding,
  1132. IN LPCWSTR pszDeviceID,
  1133. OUT PPNP_VETO_TYPE pVetoType,
  1134. OUT LPWSTR pszVetoName,
  1135. IN ULONG ulNameLength,
  1136. IN ULONG ulFlags
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This is the RPC server entry point for the CM_Query_And_Remove_SubTree
  1141. routine.
  1142. Arguments:
  1143. hBinding RPC binding handle.
  1144. pszDeviceID Device instance to query and remove.
  1145. ulFlags Specifies flags describing how the query removal
  1146. should be processed.
  1147. Currently, the following flags are defined:
  1148. CM_REMOVE_UI_OK
  1149. CM_REMOVE_UI_NOT_OK,
  1150. CM_REMOVE_NO_RESTART,
  1151. Return Value:
  1152. If the function succeeds, the return value is CR_SUCCESS. Otherwise it
  1153. returns a CR_ error code.
  1154. Note:
  1155. Note that this routine actually checks for presence of the CM_REMOVE_* flags,
  1156. not the CR_QUERY_REMOVE_* flags. Note that currently the following
  1157. CM_QUERY_REMOVE_* and CM_REMOVE_* flags are defined:
  1158. CM_QUERY_REMOVE_UI_OK, == CM_REMOVE_UI_OK
  1159. CM_QUERY_REMOVE_UI_NOT_OK == CM_REMOVE_UI_NOT_OK
  1160. CM_REMOVE_NO_RESTART
  1161. Which is why we can simply check for the CM_REMOVE_* flags.
  1162. Also, note that currently the CM_REMOVE_UI_OK and CM_REMOVE_UI_NOT_OK flags
  1163. are ignored here on the server side. User interface dialogs are displayed
  1164. based on whether veto type and veto name buffers are supplied, so the client
  1165. has used these flags to determine whether a buffer was to be supplied or not.
  1166. --*/
  1167. {
  1168. CONFIGRET Status = CR_SUCCESS;
  1169. try {
  1170. //
  1171. // Verify client "execute" access
  1172. //
  1173. if (!VerifyClientAccess(hBinding,
  1174. PLUGPLAY_EXECUTE)) {
  1175. Status = CR_ACCESS_DENIED;
  1176. goto Clean0;
  1177. }
  1178. //
  1179. // Verify client privilege
  1180. //
  1181. if (!VerifyClientPrivilege(hBinding,
  1182. SE_LOAD_DRIVER_PRIVILEGE,
  1183. L"Device Action (query-remove and remove device)")) {
  1184. Status = CR_ACCESS_DENIED;
  1185. goto Clean0;
  1186. }
  1187. //
  1188. // Validate parameters
  1189. //
  1190. if (INVALID_FLAGS(ulFlags, CM_REMOVE_BITS)) {
  1191. Status = CR_INVALID_FLAG;
  1192. goto Clean0;
  1193. }
  1194. if (!IsLegalDeviceId(pszDeviceID) ||
  1195. IsRootDeviceID(pszDeviceID)) {
  1196. Status = CR_INVALID_DEVINST;
  1197. goto Clean0;
  1198. }
  1199. Status = QueryAndRemoveSubTree(pszDeviceID,
  1200. pVetoType,
  1201. pszVetoName,
  1202. ulNameLength,
  1203. (ulFlags & CM_REMOVE_NO_RESTART) ?
  1204. PNP_QUERY_AND_REMOVE_NO_RESTART :
  1205. 0);
  1206. Clean0:
  1207. NOTHING;
  1208. } except(EXCEPTION_EXECUTE_HANDLER) {
  1209. Status = CR_FAILURE;
  1210. }
  1211. return Status;
  1212. } // PNP_QueryRemove
  1213. CONFIGRET
  1214. PNP_DisableDevInst(
  1215. IN handle_t hBinding,
  1216. IN LPCWSTR pszDeviceID,
  1217. OUT PPNP_VETO_TYPE pVetoType,
  1218. OUT LPWSTR pszVetoName,
  1219. IN ULONG ulNameLength,
  1220. IN ULONG ulFlags
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. This is the RPC server entry point for the CM_Disable_DevNode_Ex routine.
  1225. Arguments:
  1226. hBinding RPC binding handle.
  1227. pszDeviceID Device instance to disable.
  1228. ulFlags May specify CM_DISABLE_BITS.
  1229. Return Value:
  1230. If the function succeeds, the return value is CR_SUCCESS. Otherwise it
  1231. returns a CR_ error code.
  1232. Note:
  1233. Note that although the client may supply flags to this routine, they are not
  1234. used.
  1235. --*/
  1236. {
  1237. CONFIGRET Status = CR_SUCCESS;
  1238. try {
  1239. //
  1240. // Verify client "execute" access
  1241. //
  1242. if (!VerifyClientAccess(hBinding,
  1243. PLUGPLAY_EXECUTE)) {
  1244. Status = CR_ACCESS_DENIED;
  1245. goto Clean0;
  1246. }
  1247. //
  1248. // Verify client privilege
  1249. //
  1250. if (!VerifyClientPrivilege(hBinding,
  1251. SE_LOAD_DRIVER_PRIVILEGE,
  1252. L"Device Action (disable device)")) {
  1253. Status = CR_ACCESS_DENIED;
  1254. goto Clean0;
  1255. }
  1256. //
  1257. // Validate parameters
  1258. //
  1259. if (INVALID_FLAGS(ulFlags, CM_DISABLE_BITS)) {
  1260. Status = CR_INVALID_FLAG;
  1261. goto Clean0;
  1262. }
  1263. if (!IsLegalDeviceId(pszDeviceID) ||
  1264. IsRootDeviceID(pszDeviceID)) {
  1265. Status = CR_INVALID_DEVINST;
  1266. goto Clean0;
  1267. }
  1268. //
  1269. // NOTE: We enter a critical section here to guard against concurrent
  1270. // read/write operations to the "DisableCount" registry value of any
  1271. // single device instance by DisableDevInst (below), and SetupDevInst,
  1272. // EnableDevInst (called by PNP_DeviceInstanceAction).
  1273. //
  1274. PNP_ENTER_SYNCHRONOUS_CALL();
  1275. Status = DisableDevInst(pszDeviceID,
  1276. pVetoType,
  1277. pszVetoName,
  1278. ulNameLength,
  1279. TRUE);
  1280. PNP_LEAVE_SYNCHRONOUS_CALL();
  1281. Clean0:
  1282. NOTHING;
  1283. } except(EXCEPTION_EXECUTE_HANDLER) {
  1284. Status = CR_FAILURE;
  1285. }
  1286. return Status;
  1287. } // PNP_DisableDevInst
  1288. CONFIGRET
  1289. PNP_RequestDeviceEject(
  1290. IN handle_t hBinding,
  1291. IN LPCWSTR pszDeviceID,
  1292. OUT PPNP_VETO_TYPE pVetoType,
  1293. OUT LPWSTR pszVetoName,
  1294. IN ULONG ulNameLength,
  1295. IN ULONG ulFlags
  1296. )
  1297. {
  1298. CONFIGRET Status = CR_SUCCESS;
  1299. ULONG ulPropertyData, ulDataSize, ulTransferLen, ulDataType;
  1300. BOOL bDockDevice = FALSE;
  1301. try {
  1302. //
  1303. // Validate parameters
  1304. //
  1305. if (INVALID_FLAGS(ulFlags, 0)) {
  1306. Status = CR_INVALID_FLAG;
  1307. goto Clean0;
  1308. }
  1309. if (!IsLegalDeviceId(pszDeviceID)) {
  1310. Status = CR_INVALID_DEVNODE;
  1311. goto Clean0;
  1312. }
  1313. //
  1314. // Do the appropriate security test
  1315. //
  1316. ulDataSize = ulTransferLen = sizeof(ULONG);
  1317. if (CR_SUCCESS == PNP_GetDeviceRegProp(NULL,
  1318. pszDeviceID,
  1319. CM_DRP_CAPABILITIES,
  1320. &ulDataType,
  1321. (LPBYTE)&ulPropertyData,
  1322. &ulTransferLen,
  1323. &ulDataSize,
  1324. 0)) {
  1325. if (ulPropertyData & CM_DEVCAP_DOCKDEVICE) {
  1326. bDockDevice = TRUE;
  1327. }
  1328. }
  1329. if (bDockDevice) {
  1330. //
  1331. // Ejecting a dock via the CM APIs always requires the undock
  1332. // privilege (hardware-initiated ejects are handled a little
  1333. // differently, as they may be affected by policy).
  1334. //
  1335. //
  1336. // Verify client "execute" access
  1337. //
  1338. if (!VerifyClientAccess(hBinding,
  1339. PLUGPLAY_EXECUTE)) {
  1340. Status = CR_ACCESS_DENIED;
  1341. goto Clean0;
  1342. }
  1343. //
  1344. // Verify client "undock" privilege
  1345. //
  1346. if (!VerifyClientPrivilege(hBinding,
  1347. SE_UNDOCK_PRIVILEGE,
  1348. L"UNDOCK: EJECT DOCK DEVICE")) {
  1349. Status = CR_ACCESS_DENIED;
  1350. goto Clean0;
  1351. }
  1352. } else {
  1353. //
  1354. // If the client is not interactive, or is not using the active
  1355. // console session, we require the special load-driver privilege.
  1356. //
  1357. if ((!IsClientUsingLocalConsole(hBinding)) ||
  1358. (!IsClientInteractive(hBinding))) {
  1359. //
  1360. // Verify client "execute" access
  1361. //
  1362. if (!VerifyClientAccess(hBinding,
  1363. PLUGPLAY_EXECUTE)) {
  1364. Status = CR_ACCESS_DENIED;
  1365. goto Clean0;
  1366. }
  1367. //
  1368. // Verify client "load driver" privilege
  1369. //
  1370. if (!VerifyClientPrivilege(hBinding,
  1371. SE_LOAD_DRIVER_PRIVILEGE,
  1372. L"Device Action (eject device)")) {
  1373. Status = CR_ACCESS_DENIED;
  1374. goto Clean0;
  1375. }
  1376. }
  1377. }
  1378. //
  1379. // Call kernel-mode to eject the device node
  1380. //
  1381. Status = QueryAndRemoveSubTree(pszDeviceID,
  1382. pVetoType,
  1383. pszVetoName,
  1384. ulNameLength,
  1385. PNP_QUERY_AND_REMOVE_EJECT_DEVICE);
  1386. Clean0:
  1387. NOTHING;
  1388. } except(EXCEPTION_EXECUTE_HANDLER) {
  1389. Status = CR_FAILURE;
  1390. }
  1391. return Status;
  1392. } // PNP_RequestDeviceEject
  1393. //-------------------------------------------------------------------
  1394. // Private functions
  1395. //-------------------------------------------------------------------
  1396. CONFIGRET
  1397. SetupDevInst(
  1398. IN PCWSTR pszDeviceID,
  1399. IN ULONG ulFlags
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. Arguments:
  1404. Return value:
  1405. The return value is CR_SUCCESS if the function suceeds and one of the
  1406. CR_* values if it fails.
  1407. --*/
  1408. {
  1409. CONFIGRET Status = CR_SUCCESS;
  1410. HKEY hKey = NULL;
  1411. ULONG ulStatusFlag=0, ulProblem=0, ulDisableCount=0, ulSize=0;
  1412. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  1413. NTSTATUS ntStatus = STATUS_SUCCESS;
  1414. try {
  1415. //
  1416. // Validate parameters
  1417. //
  1418. if (IsRootDeviceID(pszDeviceID)) {
  1419. goto Clean0;
  1420. }
  1421. if (INVALID_FLAGS(ulFlags, CM_SETUP_BITS)) {
  1422. Status = CR_INVALID_FLAG;
  1423. goto Clean0;
  1424. }
  1425. switch(ulFlags) {
  1426. case CM_SETUP_DOWNLOAD:
  1427. case CM_SETUP_WRITE_LOG_CONFS:
  1428. //
  1429. // On NT, these values are a no-op.
  1430. //
  1431. break;
  1432. case CM_SETUP_DEVNODE_READY:
  1433. case CM_SETUP_DEVNODE_RESET:
  1434. ulDisableCount = 0;
  1435. if (RegOpenKeyEx(ghEnumKey, pszDeviceID, 0, KEY_READ | KEY_WRITE,
  1436. &hKey) == ERROR_SUCCESS) {
  1437. //
  1438. // Check the disable count, if greater than zero, do nothing
  1439. //
  1440. ulSize = sizeof(ulDisableCount);
  1441. RegQueryValueEx(hKey, pszRegValueDisableCount, NULL, NULL,
  1442. (LPBYTE)&ulDisableCount, &ulSize);
  1443. }
  1444. if (ulDisableCount > 0) {
  1445. break;
  1446. }
  1447. GetDeviceStatus(pszDeviceID, &ulStatusFlag, &ulProblem);
  1448. //
  1449. // If there's no problem or if install was done already
  1450. // (immediately) then there's nothing more to do
  1451. //
  1452. if (ulStatusFlag & DN_STARTED) {
  1453. break;
  1454. }
  1455. if (ulStatusFlag & DN_HAS_PROBLEM) {
  1456. //
  1457. // reset the problem and set status to need to enum
  1458. //
  1459. Status = ClearDeviceStatus(pszDeviceID, DN_HAS_PROBLEM, ulProblem);
  1460. }
  1461. if (Status == CR_SUCCESS) {
  1462. //
  1463. // Have kernel-mode pnp manager start the driver/device now.
  1464. // If kernel-mode doesn't have a pdo for this device then it's
  1465. // probably either a Win32 service or a phantom devnode.
  1466. //
  1467. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1468. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1469. ControlData.Flags = 0;
  1470. if (ulFlags == CM_SETUP_DEVNODE_READY) {
  1471. ntStatus = NtPlugPlayControl(PlugPlayControlStartDevice,
  1472. &ControlData,
  1473. sizeof(ControlData));
  1474. } else {
  1475. ntStatus = NtPlugPlayControl(PlugPlayControlResetDevice,
  1476. &ControlData,
  1477. sizeof(ControlData));
  1478. }
  1479. }
  1480. break;
  1481. case CM_SETUP_PROP_CHANGE:
  1482. //
  1483. // Not sure what Win9x does with this, but it ain't implemented on
  1484. // NT. Let fall through to the default (invalid flag) case...
  1485. //
  1486. default:
  1487. Status = CR_INVALID_FLAG;
  1488. }
  1489. Clean0:
  1490. NOTHING;
  1491. } except(EXCEPTION_EXECUTE_HANDLER) {
  1492. Status = CR_FAILURE;
  1493. }
  1494. if (hKey != NULL) {
  1495. RegCloseKey(hKey);
  1496. }
  1497. return Status;
  1498. } // SetupDevInst
  1499. CONFIGRET
  1500. EnableDevInst(
  1501. IN PCWSTR pszDeviceID,
  1502. IN BOOL UseDisableCount
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. This routine performs the server-side work for CM_Enable_DevNode. It
  1507. disables the specified device ID
  1508. Arguments:
  1509. pszDeviceID String that contains the device id to enable
  1510. Return value:
  1511. The return value is CR_SUCCESS if the function suceeds and one of the
  1512. CR_* values if it fails.
  1513. --*/
  1514. {
  1515. CONFIGRET Status = CR_SUCCESS;
  1516. HKEY hKey = NULL;
  1517. WCHAR RegStr[MAX_PATH];
  1518. ULONG ulDisableCount, ulProblem = 0, ulStatus = 0, ulSize;
  1519. try {
  1520. //
  1521. // Verify it isn't the root, can't disable/enable the root. We can
  1522. // probably get rid of this test once we're sure that the root
  1523. // devnode is always marded as not disablable.
  1524. //
  1525. if (IsRootDeviceID(pszDeviceID)) {
  1526. Status = CR_INVALID_DEVINST;
  1527. goto Clean0;
  1528. }
  1529. //
  1530. // Open a key to the specified device instances volatile control key.
  1531. // This is also a partial check whether the device is really present
  1532. // (if so then it has a Control key).
  1533. //
  1534. if (FAILED(StringCchPrintf(
  1535. RegStr,
  1536. SIZECHARS(RegStr),
  1537. L"%s\\%s",
  1538. pszDeviceID,
  1539. pszRegKeyDeviceControl))) {
  1540. Status = CR_FAILURE;
  1541. goto Clean0;
  1542. }
  1543. if (RegOpenKeyEx(ghEnumKey, RegStr, 0, KEY_READ | KEY_WRITE,
  1544. &hKey) != ERROR_SUCCESS) {
  1545. //
  1546. // NTRAID #174944-2000/08/30-jamesca:
  1547. // Remove dependence on the presence of volatile Control subkey
  1548. // for present devices.
  1549. //
  1550. Status = CR_INVALID_DEVINST;
  1551. goto Clean0;
  1552. }
  1553. //
  1554. // Check the current DisableCount, if we're supposed to.
  1555. //
  1556. if (UseDisableCount) {
  1557. //
  1558. // Get the current disable count from the registry
  1559. //
  1560. ulSize = sizeof(ulDisableCount);
  1561. if (RegQueryValueEx(hKey, pszRegValueDisableCount, NULL, NULL,
  1562. (LPBYTE)&ulDisableCount, &ulSize) != ERROR_SUCCESS) {
  1563. //
  1564. // disable count not set yet, assume zero
  1565. //
  1566. ulDisableCount = 0;
  1567. }
  1568. //
  1569. // if the DisableCount is zero, then we're already enabled
  1570. //
  1571. if (ulDisableCount > 0) {
  1572. //
  1573. // Decrement disable count. If the disable count is greater than one,
  1574. // then just return (disable count must drop to zero in order to
  1575. // actually reenable)
  1576. //
  1577. ulDisableCount--;
  1578. RegSetValueEx(hKey, pszRegValueDisableCount, 0, REG_DWORD,
  1579. (LPBYTE)&ulDisableCount, sizeof(ulDisableCount));
  1580. if (ulDisableCount > 0) {
  1581. goto Clean0; // success
  1582. }
  1583. }
  1584. }
  1585. //
  1586. // Retrieve the problem and status values
  1587. //
  1588. if (GetDeviceStatus(pszDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) {
  1589. //
  1590. // If the problem is only that the device instance is disabled,
  1591. // then reenable it now
  1592. //
  1593. if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_DISABLED)) {
  1594. Status = SetupDevInst(pszDeviceID, CM_SETUP_DEVNODE_READY);
  1595. }
  1596. } else {
  1597. //
  1598. // The device isn't currently active or it is a service.
  1599. //
  1600. Status = CR_SUCCESS;
  1601. }
  1602. //
  1603. // For now I'm not doing anything if there was a problem other than
  1604. // not being enabled.
  1605. //
  1606. Clean0:
  1607. NOTHING;
  1608. } except(EXCEPTION_EXECUTE_HANDLER) {
  1609. Status = CR_FAILURE;
  1610. }
  1611. if (hKey != NULL) {
  1612. RegCloseKey(hKey);
  1613. }
  1614. return Status;
  1615. } // EnableDevInst
  1616. CONFIGRET
  1617. DisableDevInst(
  1618. IN PCWSTR pszDeviceID,
  1619. OUT PPNP_VETO_TYPE pVetoType,
  1620. OUT LPWSTR pszVetoName,
  1621. IN ULONG ulNameLength,
  1622. IN BOOL UseDisableCount
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. This routine performs the server-side work for CM_Disable_DevNode. It
  1627. disables the specified device ID.
  1628. Arguments:
  1629. pszDeviceID String that contains the device id to disable
  1630. Return value:
  1631. The return value is CR_SUCCESS if the function suceeds and one of the
  1632. CR_* values if it fails.
  1633. Note:
  1634. This routine does not verify that a client is granted the pre-requisite
  1635. access, or possesses the required privilege(s) to perform this operation.
  1636. It is the caller's responsibility to perform these checks prior to calling
  1637. this routine.
  1638. --*/
  1639. {
  1640. CONFIGRET Status = CR_SUCCESS;
  1641. HKEY hKey = NULL;
  1642. WCHAR RegStr[MAX_PATH];
  1643. ULONG ulDisableCount=0, ulProblem=0, ulStatus=0, ulSize=0;
  1644. PNP_VETO_TYPE VetoType;
  1645. try {
  1646. //
  1647. // Verify it isn't the root, can't disable/enable the root. We can
  1648. // probably get rid of this test once we're sure that the root
  1649. // devnode is always marked as not disablable.
  1650. //
  1651. if (IsRootDeviceID(pszDeviceID)) {
  1652. Status = CR_INVALID_DEVINST;
  1653. goto Clean0;
  1654. }
  1655. //
  1656. // Open a key to the specified device instances volatile control key.
  1657. // This is also a partial check whether the device is really present
  1658. // (if so then it has a Control key).
  1659. //
  1660. if (FAILED(StringCchPrintf(
  1661. RegStr,
  1662. SIZECHARS(RegStr),
  1663. L"%s\\%s",
  1664. pszDeviceID,
  1665. pszRegKeyDeviceControl))) {
  1666. Status = CR_FAILURE;
  1667. goto Clean0;
  1668. }
  1669. if (RegOpenKeyEx(ghEnumKey, RegStr, 0, KEY_READ | KEY_WRITE,
  1670. &hKey) != ERROR_SUCCESS) {
  1671. //
  1672. // NTRAID #174944-2000/08/30-jamesca:
  1673. // Remove dependence on the presence of volatile Control subkey
  1674. // for present devices.
  1675. //
  1676. Status = CR_INVALID_DEVINST;
  1677. goto Clean0;
  1678. }
  1679. //
  1680. // Check the current DisableCount, if we're supposed to.
  1681. //
  1682. if (UseDisableCount) {
  1683. //
  1684. // Get the current disable count from the registry.
  1685. //
  1686. ulSize = sizeof(ulDisableCount);
  1687. if (RegQueryValueEx(hKey, pszRegValueDisableCount, NULL, NULL,
  1688. (LPBYTE)&ulDisableCount, &ulSize) != ERROR_SUCCESS) {
  1689. //
  1690. // disable count not set yet, assume zero
  1691. //
  1692. ulDisableCount = 0;
  1693. }
  1694. }
  1695. //
  1696. // If the disable count is currently zero (or we're not using it at
  1697. // all), then this is the first disable, so there's work to do.
  1698. // Otherwise, we just increment the disable count and resave it in the
  1699. // registry.
  1700. //
  1701. if ((!UseDisableCount) || (ulDisableCount == 0)) {
  1702. //
  1703. // determine if the device instance is stopable
  1704. //
  1705. if (GetDeviceStatus(pszDeviceID, &ulStatus, &ulProblem) == CR_SUCCESS) {
  1706. if (!(ulStatus & DN_DISABLEABLE)) {
  1707. Status = CR_NOT_DISABLEABLE;
  1708. goto Clean0;
  1709. }
  1710. //
  1711. // Attempt to query remove and remove this device instance.
  1712. //
  1713. VetoType = PNP_VetoTypeUnknown;
  1714. Status = QueryAndRemoveSubTree(pszDeviceID,
  1715. &VetoType,
  1716. pszVetoName,
  1717. ulNameLength,
  1718. PNP_QUERY_AND_REMOVE_DISABLE);
  1719. if(pVetoType != NULL) {
  1720. *pVetoType = VetoType;
  1721. }
  1722. if (Status != CR_SUCCESS) {
  1723. if (VetoType == PNP_VetoNonDisableable) {
  1724. //
  1725. // specially handle this Veto case
  1726. // this case is unlikely to occur unless something becomes
  1727. // non-disableable between the status-check and when we
  1728. // try to remove it
  1729. //
  1730. Status = CR_NOT_DISABLEABLE;
  1731. }
  1732. goto Clean0;
  1733. }
  1734. } else {
  1735. //
  1736. // The device isn't active or it is a service.
  1737. //
  1738. Status = CR_SUCCESS;
  1739. }
  1740. }
  1741. if (UseDisableCount) {
  1742. //
  1743. // update and save the disable count
  1744. //
  1745. ulDisableCount++;
  1746. RegSetValueEx(hKey, pszRegValueDisableCount, 0, REG_DWORD,
  1747. (LPBYTE)&ulDisableCount, sizeof(ulDisableCount));
  1748. }
  1749. Clean0:
  1750. NOTHING;
  1751. } except(EXCEPTION_EXECUTE_HANDLER) {
  1752. Status = CR_FAILURE;
  1753. }
  1754. if (hKey != NULL) {
  1755. RegCloseKey(hKey);
  1756. }
  1757. return Status;
  1758. } // DisableDevInst
  1759. CONFIGRET
  1760. ReenumerateDevInst(
  1761. IN PCWSTR pszDeviceID,
  1762. IN BOOL EnumSubTree,
  1763. IN ULONG ulFlags
  1764. )
  1765. /*++
  1766. Routine Description:
  1767. This routine performs the server-side work for CM_Reenumerate_DevNode. It
  1768. reenumerates the specified device instance.
  1769. Arguments:
  1770. pszDeviceID String that contains the device id to reenumerate.
  1771. EnumSubTree Specifies whether to reenumerate the entire device subtree.
  1772. ulFlags Any enumeration control flags.
  1773. Return value:
  1774. The return value is CR_SUCCESS if the function suceeds and one of the
  1775. CR_* values if it fails.
  1776. --*/
  1777. {
  1778. CONFIGRET Status = CR_SUCCESS;
  1779. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  1780. NTSTATUS ntStatus = STATUS_SUCCESS;
  1781. ULONG ulEnumFlags = 0;
  1782. QI_CONTEXT qiContext;
  1783. //
  1784. // NOTE: For Windows 95, the devnode is marked as needing to be
  1785. // reenumerating (by or'ing StatusFlags with DN_NEED_TO_ENUM), then
  1786. // sometime later, after the initial flurry of reenumeration requests,
  1787. // the whole tree is processed
  1788. //
  1789. if (INVALID_FLAGS(ulFlags, CM_REENUMERATE_BITS)) {
  1790. return CR_INVALID_FLAG;
  1791. }
  1792. try {
  1793. //
  1794. // Attempt to handle this via kernel-mode, if kernel-mode
  1795. // doesn't have a pdo for this device then it's probably either a
  1796. // Win32 service or a phantom devnode.
  1797. //
  1798. if (!EnumSubTree) {
  1799. ulEnumFlags |= PNP_ENUMERATE_DEVICE_ONLY;
  1800. }
  1801. if (ulFlags & CM_REENUMERATE_ASYNCHRONOUS) {
  1802. ulEnumFlags |= PNP_ENUMERATE_ASYNCHRONOUS;
  1803. }
  1804. if (ulFlags & CM_REENUMERATE_RETRY_INSTALLATION) {
  1805. qiContext.HeadNodeSeen = FALSE;
  1806. qiContext.SingleLevelEnumOnly = !EnumSubTree;
  1807. qiContext.Status = CR_SUCCESS;
  1808. Status = EnumerateSubTreeTopDownBreadthFirst(
  1809. NULL,
  1810. pszDeviceID,
  1811. QueueInstallationCallback,
  1812. (PVOID) &qiContext
  1813. );
  1814. if (Status != CR_SUCCESS) {
  1815. return Status;
  1816. }
  1817. if (qiContext.Status != CR_SUCCESS) {
  1818. return qiContext.Status;
  1819. }
  1820. }
  1821. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  1822. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1823. ControlData.Flags = ulEnumFlags;
  1824. ntStatus = NtPlugPlayControl(PlugPlayControlEnumerateDevice,
  1825. &ControlData,
  1826. sizeof(ControlData));
  1827. if (!NT_SUCCESS(ntStatus)) {
  1828. if (ntStatus == STATUS_NO_SUCH_DEVICE) {
  1829. Status = CR_INVALID_DEVNODE; // probably a win32 service
  1830. } else {
  1831. Status = MapNtStatusToCmError(ntStatus);
  1832. }
  1833. }
  1834. } except(EXCEPTION_EXECUTE_HANDLER) {
  1835. Status = CR_FAILURE;
  1836. }
  1837. return Status;
  1838. } // ReenumerateDevInst
  1839. CONFIGRET
  1840. QueryAndRemoveSubTree(
  1841. IN PCWSTR pszDeviceID,
  1842. OUT PPNP_VETO_TYPE pVetoType,
  1843. OUT LPWSTR pszVetoName,
  1844. IN ULONG ulNameLength,
  1845. IN ULONG ulFlags
  1846. )
  1847. /*++
  1848. Routine Description:
  1849. This routine performs the server-side work for CM_Query_Remove_Subtree. It
  1850. determines whether subtree can be removed.
  1851. Arguments:
  1852. pszDeviceID String that contains the device id to query remove
  1853. ulFlags Specifies flags for PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA
  1854. May be one of:
  1855. PNP_QUERY_AND_REMOVE_NO_RESTART
  1856. PNP_QUERY_AND_REMOVE_DISABLE
  1857. PNP_QUERY_AND_REMOVE_UNINSTALL
  1858. PNP_QUERY_AND_REMOVE_EJECT_DEVICE
  1859. Return value:
  1860. The return value is CR_SUCCESS if the function suceeds and one of the
  1861. CR_* values if it fails.
  1862. --*/
  1863. {
  1864. CONFIGRET Status = CR_SUCCESS;
  1865. PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA ControlData;
  1866. NTSTATUS ntStatus = STATUS_SUCCESS;
  1867. if (ARGUMENT_PRESENT(pVetoType)) {
  1868. *pVetoType = 0;
  1869. }
  1870. if (ARGUMENT_PRESENT(pszVetoName) && (ulNameLength > 0)) {
  1871. *pszVetoName = L'\0';
  1872. }
  1873. //---------------------------------------------------------------------
  1874. // Attempt to handle this via kernel-mode first, if kernel-mode
  1875. // doesn't have a pdo for this device then it's probably either a
  1876. // Win32 service or a phantom devnode, so we'll do the old default
  1877. // Windows NT 4.0 behaviour for now.
  1878. //---------------------------------------------------------------------
  1879. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA));
  1880. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  1881. ControlData.Flags = ulFlags;
  1882. ControlData.VetoType = PNP_VetoTypeUnknown;
  1883. ControlData.VetoName = pszVetoName;
  1884. ControlData.VetoNameLength = ulNameLength;
  1885. ntStatus = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
  1886. &ControlData,
  1887. sizeof(ControlData));
  1888. if (!NT_SUCCESS(ntStatus)) {
  1889. if (ntStatus == STATUS_NO_SUCH_DEVICE) {
  1890. Status = CR_INVALID_DEVNODE; // probably a win32 service or legacy driver
  1891. } else if (ntStatus == STATUS_PLUGPLAY_QUERY_VETOED) {
  1892. KdPrintEx((DPFLTR_PNPMGR_ID,
  1893. DBGF_WARNINGS,
  1894. "Query vetoed: Type = %d, Name = %ws\n",
  1895. ControlData.VetoType,
  1896. ControlData.VetoName));
  1897. if (pVetoType != NULL) {
  1898. *pVetoType = ControlData.VetoType;
  1899. }
  1900. if (ARGUMENT_PRESENT(pszVetoName) &&
  1901. (ulNameLength > ControlData.VetoNameLength)) {
  1902. pszVetoName[ControlData.VetoNameLength] = L'\0';
  1903. }
  1904. Status = CR_REMOVE_VETOED;
  1905. } else {
  1906. Status = MapNtStatusToCmError(ntStatus);
  1907. }
  1908. }
  1909. return Status;
  1910. } // QueryRemoveSubTree
  1911. CONFIGRET
  1912. CreateDefaultDeviceInstance(
  1913. IN PCWSTR pszDeviceID,
  1914. IN PCWSTR pszParentID,
  1915. IN BOOL bPhantom,
  1916. IN BOOL bMigrated
  1917. )
  1918. {
  1919. CONFIGRET Status = CR_SUCCESS;
  1920. LONG RegStatus = ERROR_SUCCESS;
  1921. HKEY hKey1 = NULL, hKey2 = NULL;
  1922. WCHAR szBase[MAX_DEVICE_ID_LEN];
  1923. WCHAR szDevice[MAX_DEVICE_ID_LEN];
  1924. WCHAR szInstance[MAX_DEVICE_ID_LEN];
  1925. WCHAR RegStr[MAX_DEVICE_ID_LEN];
  1926. ULONG ulDisposition=0, i=0;
  1927. UNREFERENCED_PARAMETER(pszParentID);
  1928. //
  1929. // make sure we were specified a valid instance path.
  1930. //
  1931. if (!IsLegalDeviceId(pszDeviceID)) {
  1932. Status = CR_INVALID_DEVNODE;
  1933. goto Clean0;
  1934. }
  1935. //
  1936. // split the supplied instance path into enumerator, device, and instance
  1937. //
  1938. SplitDeviceInstanceString(pszDeviceID, szBase, szDevice, szInstance);
  1939. //
  1940. // open a key to base enumerator (create if doesn't already exist)
  1941. //
  1942. RegStatus = RegCreateKeyEx(ghEnumKey, szBase, 0, NULL,
  1943. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1944. NULL, &hKey2, NULL);
  1945. if (RegStatus != ERROR_SUCCESS) {
  1946. Status = CR_REGISTRY_ERROR;
  1947. goto Clean0;
  1948. }
  1949. //
  1950. // open a key to device (create if doesn't already exist)
  1951. //
  1952. RegStatus = RegCreateKeyEx(hKey2, szDevice, 0, NULL,
  1953. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1954. NULL, &hKey1, NULL);
  1955. if (RegStatus != ERROR_SUCCESS) {
  1956. Status = CR_REGISTRY_ERROR;
  1957. goto CleanupOnFailure;
  1958. }
  1959. RegCloseKey(hKey2); // done with Base Key
  1960. hKey2 = NULL;
  1961. //
  1962. // open a key to instance (if already exists)
  1963. //
  1964. RegStatus = RegOpenKeyEx(hKey1, szInstance, 0, KEY_SET_VALUE, &hKey2);
  1965. //
  1966. // if the key was migrated, an existing instance id should have been
  1967. // supplied. for non-migrated instances, the key should not exist yet.
  1968. //
  1969. if (bMigrated) {
  1970. ASSERT(RegStatus == ERROR_SUCCESS);
  1971. } else {
  1972. ASSERT(RegStatus != ERROR_SUCCESS);
  1973. }
  1974. //
  1975. // if the specified key exists, but the instance is not migrated, find an
  1976. // unused instance value. if a migrated instance was specified, don't
  1977. // bother finding an unused instance - we can just use this one.
  1978. //
  1979. if ((RegStatus == ERROR_SUCCESS) && (!bMigrated)) {
  1980. //
  1981. // find a new instance id to use
  1982. //
  1983. RegCloseKey(hKey2); // done with Instance key
  1984. hKey2 = NULL;
  1985. for (i=0; i <= 9999; i++) {
  1986. if (SUCCEEDED(StringCchPrintf(
  1987. szInstance,
  1988. SIZECHARS(szInstance),
  1989. L"%04u",
  1990. i))) {
  1991. //
  1992. // attemnpt to open this instance key
  1993. //
  1994. RegStatus =
  1995. RegOpenKeyEx(
  1996. hKey1,
  1997. szInstance,
  1998. 0,
  1999. KEY_SET_VALUE,
  2000. &hKey2);
  2001. if (RegStatus != ERROR_SUCCESS) {
  2002. //
  2003. // instance key does not exist, use this instance
  2004. //
  2005. break;
  2006. }
  2007. //
  2008. // instance key exists, try next one
  2009. //
  2010. RegCloseKey(hKey2);
  2011. hKey2 = NULL;
  2012. }
  2013. }
  2014. if (i > 9999) {
  2015. Status = CR_FAILURE; // we ran out of instances (unlikely)
  2016. goto CleanupOnFailure;
  2017. }
  2018. }
  2019. if (hKey2 == NULL) {
  2020. //
  2021. // open the device instance key, if we haven't already.
  2022. //
  2023. RegStatus = RegCreateKeyEx(hKey1, szInstance, 0, NULL,
  2024. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  2025. NULL, &hKey2, &ulDisposition);
  2026. if (RegStatus != ERROR_SUCCESS) {
  2027. Status = CR_REGISTRY_ERROR;
  2028. goto CleanupOnFailure;
  2029. }
  2030. ASSERT(ulDisposition == REG_CREATED_NEW_KEY);
  2031. } else {
  2032. //
  2033. // We already opened the instance key above.
  2034. //
  2035. ASSERT(RegStatus == ERROR_SUCCESS);
  2036. }
  2037. RegCloseKey(hKey1); // done with device key
  2038. hKey1 = NULL;
  2039. //
  2040. // set the default device instance values
  2041. //
  2042. if (bPhantom) {
  2043. //
  2044. // phantoms are not present by definition
  2045. //
  2046. MarkDevicePhantom(hKey2, TRUE);
  2047. }
  2048. //
  2049. // go ahead and create the volatile Control key at this point.
  2050. //
  2051. RegCreateKeyEx(hKey2, pszRegKeyDeviceControl, 0, NULL,
  2052. REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
  2053. NULL, &hKey1, &ulDisposition);
  2054. ASSERT(ulDisposition == REG_CREATED_NEW_KEY);
  2055. RegCloseKey(hKey2); // done with instance key
  2056. hKey2 = NULL;
  2057. goto Clean0; // success
  2058. CleanupOnFailure:
  2059. //
  2060. // attempt to cleanup the device instance (don't delete device or base if
  2061. // other subkeys under it).
  2062. //
  2063. RegDeleteKey(ghEnumKey, pszDeviceID); // delete instance
  2064. if (SUCCEEDED(StringCchPrintf(
  2065. RegStr,
  2066. SIZECHARS(RegStr),
  2067. L"%s\\%s",
  2068. szBase,
  2069. szDevice))) {
  2070. RegDeleteKey(ghEnumKey, RegStr);
  2071. }
  2072. Clean0:
  2073. if (hKey1 != NULL) {
  2074. RegCloseKey(hKey1);
  2075. }
  2076. if (hKey2 != NULL) {
  2077. RegCloseKey(hKey2);
  2078. }
  2079. return Status;
  2080. } // CreateDefaultDeviceInstance
  2081. ULONG
  2082. GetCurrentConfigFlag(
  2083. IN PCWSTR pDeviceID
  2084. )
  2085. {
  2086. HKEY hKey;
  2087. WCHAR RegStr[MAX_PATH];
  2088. ULONG ulSize = 0, ulCSConfigFlag = 0;
  2089. //
  2090. // open a key to the current hardware profile for this device instance
  2091. // System\CCS\Hardware Profiles\Current\System\Enum
  2092. //
  2093. if (FAILED(StringCchPrintf(
  2094. RegStr,
  2095. SIZECHARS(RegStr),
  2096. L"%s\\%s\\%s\\%s",
  2097. pszRegPathHwProfiles,
  2098. pszRegKeyCurrent,
  2099. pszRegPathEnum,
  2100. pDeviceID))) {
  2101. return 0;
  2102. }
  2103. if (RegOpenKeyEx(
  2104. HKEY_LOCAL_MACHINE, RegStr, 0, KEY_QUERY_VALUE, &hKey)
  2105. != ERROR_SUCCESS) {
  2106. return 0;
  2107. }
  2108. //
  2109. // retrieve the config specific flag
  2110. //
  2111. ulSize = sizeof(ulCSConfigFlag);
  2112. if (RegQueryValueEx(
  2113. hKey, pszRegValueCSConfigFlags, NULL, NULL,
  2114. (LPBYTE)&ulCSConfigFlag, &ulSize) != ERROR_SUCCESS) {
  2115. //
  2116. // status flags not set yet, assume zero
  2117. //
  2118. ulCSConfigFlag = 0;
  2119. }
  2120. RegCloseKey(hKey);
  2121. return ulCSConfigFlag;
  2122. } // GetCurrentConfigFlag
  2123. BOOL
  2124. MarkDevicePhantom(
  2125. IN HKEY hKey,
  2126. IN ULONG ulValue
  2127. )
  2128. {
  2129. //
  2130. // a phantom device should have a Phantom value of TRUE
  2131. //
  2132. RegSetValueEx(
  2133. hKey, pszRegValuePhantom, 0, REG_DWORD,
  2134. (LPBYTE)&ulValue, sizeof(ULONG));
  2135. return TRUE;
  2136. } // MarkDevicePhantom
  2137. CONFIGRET
  2138. GenerateDeviceInstance(
  2139. OUT LPWSTR pszFullDeviceID,
  2140. IN LPWSTR pszDeviceID,
  2141. IN ULONG ulDevIdLen
  2142. )
  2143. {
  2144. LONG RegStatus = ERROR_SUCCESS;
  2145. WCHAR RegStr[MAX_PATH];
  2146. HKEY hKey;
  2147. ULONG ulInstanceID = 0;
  2148. LPWSTR p;
  2149. //
  2150. // validate the device id component (can't have invalid character or a
  2151. // backslash)
  2152. //
  2153. for (p = pszDeviceID; *p; p++) {
  2154. if (*p <= TEXT(' ') ||
  2155. *p > (WCHAR)0x7F ||
  2156. *p == TEXT('\\')) {
  2157. return CR_INVALID_DEVICE_ID;
  2158. }
  2159. }
  2160. //
  2161. // make sure the supplied buffer is large enough to hold the name of the ROOT
  2162. // enumerator, the supplied device id, a generated instance id ('0000'), two
  2163. // path separator characters, plus a terminating NULL character.
  2164. //
  2165. if (FAILED(StringCchCopyEx(
  2166. pszFullDeviceID,
  2167. ulDevIdLen,
  2168. pszRegKeyRootEnum,
  2169. NULL, NULL,
  2170. STRSAFE_NULL_ON_FAILURE))) {
  2171. return CR_BUFFER_SMALL;
  2172. }
  2173. CharUpper(pszFullDeviceID);
  2174. if (FAILED(StringCchCatEx(pszFullDeviceID,
  2175. ulDevIdLen,
  2176. L"\\",
  2177. NULL, NULL,
  2178. STRSAFE_NULL_ON_FAILURE))) {
  2179. return CR_BUFFER_SMALL;
  2180. }
  2181. if (FAILED(StringCchCatEx(pszFullDeviceID,
  2182. ulDevIdLen,
  2183. pszDeviceID,
  2184. NULL, NULL,
  2185. STRSAFE_NULL_ON_FAILURE))) {
  2186. return CR_BUFFER_SMALL;
  2187. }
  2188. //
  2189. // try opening instance ids until we find one that doesn't already exist
  2190. //
  2191. for (ulInstanceID = 0; ulInstanceID <= 9999; ulInstanceID++) {
  2192. if (SUCCEEDED(StringCchPrintf(
  2193. RegStr,
  2194. SIZECHARS(RegStr),
  2195. L"%s\\%04u",
  2196. pszFullDeviceID,
  2197. ulInstanceID))) {
  2198. //
  2199. // attemnpt to open this instance key
  2200. //
  2201. RegStatus =
  2202. RegOpenKeyEx(
  2203. ghEnumKey,
  2204. RegStr,
  2205. 0,
  2206. KEY_QUERY_VALUE,
  2207. &hKey);
  2208. if (RegStatus != ERROR_SUCCESS) {
  2209. //
  2210. // instance key does not exist, use this instance
  2211. //
  2212. break;
  2213. }
  2214. //
  2215. // instance key exists, try next one
  2216. //
  2217. RegCloseKey(hKey);
  2218. hKey = NULL;
  2219. }
  2220. }
  2221. if (ulInstanceID > 9999) {
  2222. return CR_FAILURE; // instances all used up, seems unlikely
  2223. }
  2224. if (FAILED(StringCchCopyEx(
  2225. pszFullDeviceID,
  2226. ulDevIdLen,
  2227. RegStr,
  2228. NULL, NULL,
  2229. STRSAFE_NULL_ON_FAILURE))) {
  2230. return CR_FAILURE;
  2231. }
  2232. return CR_SUCCESS;
  2233. } // GenerateDeviceInstance
  2234. CONFIGRET
  2235. UninstallRealDevice(
  2236. IN LPCWSTR pszDeviceID
  2237. )
  2238. {
  2239. CONFIGRET Status = CR_SUCCESS;
  2240. LONG RegStatus;
  2241. WCHAR RegStr[MAX_CM_PATH];
  2242. WCHAR szProfile[MAX_PROFILE_ID_LEN];
  2243. ULONG ulLen = 0, ulIndex = 0;
  2244. HKEY hKeyHwProfiles = NULL;
  2245. //---------------------------------------------------------------------
  2246. // This is the case where a real device id couldn't be stopped, so we
  2247. // cannot really safely delete the device id at this point since the
  2248. // service may still try to use it. Instead, I'll make this device
  2249. // id registry key volatile so that it will eventually go away when
  2250. // the system is shutdown. To make the key volatile, I have to copy
  2251. // it to a temporary spot, delete the original key and recreate it
  2252. // as a volatile key and copy everything back.
  2253. //---------------------------------------------------------------------
  2254. //
  2255. // first, convert the device instance key under the main Enum
  2256. // branch to volatile
  2257. //
  2258. Status = MakeKeyVolatile(pszRegPathEnum, pszDeviceID);
  2259. if (Status != CR_SUCCESS) {
  2260. goto Clean0;
  2261. }
  2262. //
  2263. // next, check each hardware profile and delete any entries for this
  2264. // device instance.
  2265. //
  2266. RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszRegPathHwProfiles,
  2267. 0, KEY_READ,
  2268. &hKeyHwProfiles);
  2269. if (RegStatus == ERROR_SUCCESS) {
  2270. //
  2271. // Enumerate all existing profile-specific Enum branches.
  2272. //
  2273. ulIndex = 0;
  2274. for ( ; ; ) {
  2275. ulLen = SIZECHARS(szProfile);
  2276. RegStatus = RegEnumKeyEx(hKeyHwProfiles, ulIndex++,
  2277. szProfile, &ulLen,
  2278. NULL, NULL, NULL, NULL);
  2279. if (RegStatus == ERROR_NO_MORE_ITEMS) {
  2280. //
  2281. // No more keys to enumerate, stop enumerating.
  2282. //
  2283. break;
  2284. } else if (RegStatus == ERROR_MORE_DATA) {
  2285. //
  2286. // Key is not a valid profile key, skip to the next.
  2287. //
  2288. continue;
  2289. } else if (RegStatus != ERROR_SUCCESS) {
  2290. //
  2291. // Some other error, stop enumerating.
  2292. //
  2293. break;
  2294. } else {
  2295. //
  2296. // Form the profile-specific Enum key path.
  2297. //
  2298. if (SUCCEEDED(StringCchPrintf(
  2299. RegStr,
  2300. SIZECHARS(RegStr),
  2301. L"%s\\%s\\%s",
  2302. pszRegPathHwProfiles,
  2303. szProfile,
  2304. pszRegPathEnum))) {
  2305. //
  2306. // Attempt to make the profile-specific device instance key
  2307. // volatile. Ignore the status for profile-specific keys since
  2308. // they may not exist.
  2309. //
  2310. MakeKeyVolatile(RegStr, pszDeviceID);
  2311. }
  2312. }
  2313. }
  2314. RegCloseKey(hKeyHwProfiles);
  2315. }
  2316. //
  2317. // finally, mark the device as being removed
  2318. //
  2319. SetDeviceStatus(pszDeviceID, DN_WILL_BE_REMOVED, 0);
  2320. Clean0:
  2321. return Status;
  2322. } // UninstallRealDevice
  2323. CONFIGRET
  2324. UninstallPhantomDevice(
  2325. IN LPCWSTR pszDeviceID
  2326. )
  2327. {
  2328. CONFIGRET Status = CR_SUCCESS;
  2329. LONG RegStatus;
  2330. NTSTATUS NtStatus = STATUS_SUCCESS;
  2331. PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
  2332. WCHAR szEnumerator[MAX_DEVICE_ID_LEN],
  2333. szDevice[MAX_DEVICE_ID_LEN],
  2334. szInstance[MAX_DEVICE_ID_LEN];
  2335. WCHAR RegStr[MAX_CM_PATH];
  2336. WCHAR szProfile[MAX_PROFILE_ID_LEN];
  2337. ULONG ulIndex = 0, ulLen = 0;
  2338. HKEY hKeyHwProfiles = NULL;
  2339. //
  2340. // 1. Deregister the original device id (only on phantoms)
  2341. //
  2342. memset(&ControlData, 0, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
  2343. RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
  2344. ControlData.Flags = 0;
  2345. NtStatus = NtPlugPlayControl(PlugPlayControlDeregisterDevice,
  2346. &ControlData,
  2347. sizeof(ControlData));
  2348. //
  2349. // Don't bother with the status here, the device might not have
  2350. // been registered which would cause the previous call to fail.
  2351. // Keep trying to clean (uninstall) this device instance.
  2352. //
  2353. //
  2354. // 2. Remove the instance under the main enum branch. If this is the
  2355. // only instance, then the device will be removed as well. The parent
  2356. // key to DeletePrivateKey is the registry path up to the enumerator
  2357. // and the child key is the device and instance.
  2358. //
  2359. //
  2360. // Get the device id's component parts.
  2361. //
  2362. if (!SplitDeviceInstanceString(
  2363. pszDeviceID,
  2364. szEnumerator,
  2365. szDevice,
  2366. szInstance)) {
  2367. Status = CR_FAILURE;
  2368. goto Clean0;
  2369. }
  2370. if (FAILED(StringCchPrintf(
  2371. RegStr,
  2372. SIZECHARS(RegStr),
  2373. L"%s\\%s",
  2374. pszRegPathEnum,
  2375. szEnumerator))) {
  2376. Status = CR_FAILURE;
  2377. goto Clean0;
  2378. }
  2379. if (FAILED(StringCchCat(
  2380. szDevice,
  2381. SIZECHARS(szDevice),
  2382. L"\\"))) {
  2383. Status = CR_FAILURE;
  2384. goto Clean0;
  2385. }
  2386. if (FAILED(StringCchCat(
  2387. szDevice,
  2388. SIZECHARS(szDevice),
  2389. szInstance))) {
  2390. Status = CR_FAILURE;
  2391. goto Clean0;
  2392. }
  2393. //
  2394. // delete the device instance key
  2395. //
  2396. Status = DeletePrivateKey(HKEY_LOCAL_MACHINE, RegStr, szDevice);
  2397. if (Status != CR_SUCCESS) {
  2398. goto Clean0;
  2399. }
  2400. //
  2401. // 3. Now check each hardware profile and delete any entries for this
  2402. // device instance.
  2403. //
  2404. RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszRegPathHwProfiles,
  2405. 0, KEY_READ,
  2406. &hKeyHwProfiles);
  2407. if (RegStatus == ERROR_SUCCESS) {
  2408. //
  2409. // Enumerate all existing profile-specific Enum branches.
  2410. //
  2411. ulIndex = 0;
  2412. for ( ; ; ) {
  2413. ulLen = SIZECHARS(szProfile);
  2414. RegStatus = RegEnumKeyEx(hKeyHwProfiles, ulIndex++,
  2415. szProfile, &ulLen,
  2416. NULL, NULL, NULL, NULL);
  2417. if (RegStatus == ERROR_NO_MORE_ITEMS) {
  2418. //
  2419. // No more keys to enumerate, stop enumerating.
  2420. //
  2421. break;
  2422. } else if (RegStatus == ERROR_MORE_DATA) {
  2423. //
  2424. // Key is not a valid profile key, skip to the next.
  2425. //
  2426. continue;
  2427. } else if (RegStatus != ERROR_SUCCESS) {
  2428. //
  2429. // Some other error, stop enumerating.
  2430. //
  2431. break;
  2432. } else {
  2433. //
  2434. // Form the profile-specific registry key path.
  2435. //
  2436. if (SUCCEEDED(StringCchPrintf(
  2437. RegStr,
  2438. SIZECHARS(RegStr),
  2439. L"%s\\%s\\%s\\%s",
  2440. pszRegPathHwProfiles,
  2441. szProfile,
  2442. pszRegPathEnum,
  2443. szEnumerator))) {
  2444. //
  2445. // Attempt to delete the profile-specific key for this device.
  2446. // Ignore the status for profile-specific keys since they may not
  2447. // exist. DeletePrivateKey() will remove the instance and the
  2448. // device, if this is the only instance.
  2449. //
  2450. DeletePrivateKey(HKEY_LOCAL_MACHINE, RegStr, szDevice);
  2451. }
  2452. }
  2453. }
  2454. RegCloseKey(hKeyHwProfiles);
  2455. }
  2456. Clean0:
  2457. return Status;
  2458. } // UninstallPhantomDevice
  2459. BOOL
  2460. IsDeviceRootEnumerated(
  2461. IN LPCWSTR pszDeviceID
  2462. )
  2463. {
  2464. WCHAR szEnumerator[MAX_DEVICE_ID_LEN],
  2465. szDevice[MAX_DEVICE_ID_LEN],
  2466. szInstance[MAX_DEVICE_ID_LEN];
  2467. if (!SplitDeviceInstanceString(pszDeviceID,
  2468. szEnumerator,
  2469. szDevice,
  2470. szInstance)) {
  2471. return FALSE;
  2472. }
  2473. if (CompareString(LOCALE_INVARIANT,
  2474. NORM_IGNORECASE,
  2475. szEnumerator,
  2476. -1,
  2477. pszRegKeyRootEnum,
  2478. -1) == CSTR_EQUAL) {
  2479. return TRUE;
  2480. }
  2481. return FALSE;
  2482. } // IsDeviceRootEnumerated
  2483. BOOL
  2484. IsDeviceRegistered(
  2485. IN LPCWSTR pszDeviceID,
  2486. IN LPCWSTR pszService
  2487. )
  2488. {
  2489. WCHAR RegStr[MAX_PATH], szData[MAX_DEVICE_ID_LEN], szValue[MAX_PATH];
  2490. HKEY hKey = NULL;
  2491. LONG RegStatus = ERROR_SUCCESS;
  2492. ULONG ulIndex = 0, ulDataSize = 0, ulValueSize = 0, i = 0;
  2493. BOOL Status = FALSE;
  2494. //
  2495. // open the service's volatile enum registry key
  2496. //
  2497. if (FAILED(StringCchPrintf(
  2498. RegStr,
  2499. SIZECHARS(RegStr),
  2500. L"%s\\%s",
  2501. pszService,
  2502. pszRegKeyEnum))) {
  2503. return FALSE;
  2504. }
  2505. RegStatus =
  2506. RegOpenKeyEx(
  2507. ghServicesKey,
  2508. RegStr,
  2509. 0,
  2510. KEY_READ,
  2511. &hKey);
  2512. if (RegStatus != ERROR_SUCCESS) {
  2513. return FALSE;
  2514. }
  2515. //
  2516. // Enumerate all the values under this key
  2517. //
  2518. while (RegStatus == ERROR_SUCCESS) {
  2519. ulDataSize = MAX_DEVICE_ID_LEN * sizeof(WCHAR);
  2520. ulValueSize = MAX_PATH;
  2521. RegStatus = RegEnumValue(hKey, ulIndex, szValue, &ulValueSize,
  2522. NULL, &i, (LPBYTE)szData, &ulDataSize);
  2523. if (RegStatus == ERROR_SUCCESS) {
  2524. ulIndex++;
  2525. if (CompareString(LOCALE_INVARIANT,
  2526. NORM_IGNORECASE,
  2527. pszDeviceID,
  2528. -1,
  2529. szData,
  2530. -1) == CSTR_EQUAL) {
  2531. Status = TRUE;
  2532. break;
  2533. }
  2534. }
  2535. }
  2536. RegCloseKey(hKey);
  2537. return Status;
  2538. } // IsDeviceRegistered
  2539. BOOL
  2540. IsPrivatePhantomFromFirmware(
  2541. IN HKEY hKey
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. This routine checks to see if the supplied device instance registry key is
  2546. for a firmware mapper-created private phantom.
  2547. Arguments:
  2548. hKey - Supplied the handle to the registry key for the device instance to
  2549. be examined.
  2550. Return value:
  2551. If the device instance registry key represents a firmware mapper-reported
  2552. phantom, the return value is TRUE. Otherwise, it is FALSE.
  2553. --*/
  2554. {
  2555. ULONG ValueSize, Value;
  2556. HKEY hControlKey;
  2557. BOOL b = FALSE;
  2558. //
  2559. // First, make sure that this is indeed a phantom
  2560. //
  2561. ValueSize = sizeof(Value);
  2562. Value = 0;
  2563. if((ERROR_SUCCESS != RegQueryValueEx(hKey,
  2564. pszRegValuePhantom,
  2565. NULL,
  2566. NULL,
  2567. (LPBYTE)&Value,
  2568. &ValueSize))
  2569. || !Value)
  2570. {
  2571. //
  2572. // Not a phantom
  2573. //
  2574. goto clean0;
  2575. }
  2576. //
  2577. // OK, we have a phantom--did it come from the firmware mapper?
  2578. //
  2579. ValueSize = sizeof(Value);
  2580. Value = 0;
  2581. if((ERROR_SUCCESS != RegQueryValueEx(hKey,
  2582. pszRegValueFirmwareIdentified,
  2583. NULL,
  2584. NULL,
  2585. (LPBYTE)&Value,
  2586. &ValueSize))
  2587. || !Value)
  2588. {
  2589. //
  2590. // This phantom didn't come from the firmware mapper.
  2591. //
  2592. goto clean0;
  2593. }
  2594. //
  2595. // Finally, we need to check to see whether the device is actually present
  2596. // on this boot. If not, we want to return FALSE, because we don't want
  2597. // detection modules to be registering devnodes for non-existent hardware.
  2598. //
  2599. if(ERROR_SUCCESS == RegOpenKeyEx(hKey,
  2600. pszRegKeyDeviceControl,
  2601. 0,
  2602. KEY_READ,
  2603. &hControlKey)) {
  2604. ValueSize = sizeof(Value);
  2605. Value = 0;
  2606. if((ERROR_SUCCESS == RegQueryValueEx(hControlKey,
  2607. pszRegValueFirmwareMember,
  2608. NULL,
  2609. NULL,
  2610. (LPBYTE)&Value,
  2611. &ValueSize))
  2612. && Value)
  2613. {
  2614. b = TRUE;
  2615. }
  2616. RegCloseKey(hControlKey);
  2617. }
  2618. clean0:
  2619. return b;
  2620. } // IsPrivatePhantomFromFirmware
  2621. CONFIGRET
  2622. EnumerateSubTreeTopDownBreadthFirst(
  2623. IN handle_t BindingHandle,
  2624. IN LPCWSTR DevInst,
  2625. IN PFN_ENUMTREE CallbackFunction,
  2626. IN OUT PVOID Context
  2627. )
  2628. /*++
  2629. Routine Description:
  2630. This routine walks a subtree in a breadth-first nonrecursive manner.
  2631. Arguments:
  2632. BindingHandle RPC Binding handle
  2633. DevInst InstancePath of device to begin with. It is assumed
  2634. that this InstancePath is valid.
  2635. CallbackFunction Function to call for each node in the subtree (DevInst
  2636. included)
  2637. Context Context information to pass to the callback function.
  2638. Return Value:
  2639. CONFIGRET (Success if walk progressed through every node specified by the
  2640. CallbackFunction, failure due to low memory, bad instance path,
  2641. or other problems)
  2642. --*/
  2643. {
  2644. CONFIGRET Status = CR_SUCCESS;
  2645. PENUM_ELEMENT enumElement;
  2646. ENUM_ACTION enumAction;
  2647. LIST_ENTRY subTreeHead;
  2648. PLIST_ENTRY listEntry;
  2649. size_t DeviceIDLen = 0;
  2650. //
  2651. // This algorithm is a nonrecursive tree walk. It works by building a list.
  2652. // Parents are removed from the head of the list and their children are
  2653. // added to the end of the list. This enforces a breadth-first downward
  2654. // tree walk.
  2655. //
  2656. InitializeListHead(&subTreeHead);
  2657. //
  2658. // This walk includes the head node as well, so insert it into the list.
  2659. //
  2660. if (!ARGUMENT_PRESENT(DevInst)) {
  2661. return CR_INVALID_POINTER;
  2662. }
  2663. if (FAILED(StringCchLength(
  2664. DevInst,
  2665. MAX_DEVICE_ID_LEN,
  2666. &DeviceIDLen))) {
  2667. return CR_INVALID_DEVICE_ID;
  2668. }
  2669. ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
  2670. enumElement = (PENUM_ELEMENT)
  2671. HeapAlloc(ghPnPHeap, 0,
  2672. sizeof(ENUM_ELEMENT) + (DeviceIDLen * sizeof(WCHAR)));
  2673. if (enumElement == NULL) {
  2674. return CR_OUT_OF_MEMORY;
  2675. }
  2676. if (FAILED(StringCchCopyEx(
  2677. enumElement->DevInst,
  2678. DeviceIDLen + 1,
  2679. DevInst,
  2680. NULL, NULL,
  2681. STRSAFE_NULL_ON_FAILURE))) {
  2682. HeapFree(ghPnPHeap, 0, enumElement);
  2683. return CR_FAILURE;
  2684. }
  2685. InsertTailList(&subTreeHead, &enumElement->ListEntry);
  2686. //
  2687. // Remove each entry from the head of the list on downwards.
  2688. //
  2689. while(!IsListEmpty(&subTreeHead)) {
  2690. listEntry = RemoveHeadList(&subTreeHead);
  2691. enumElement = CONTAINING_RECORD(listEntry, ENUM_ELEMENT, ListEntry);
  2692. enumAction = CallbackFunction(enumElement->DevInst, Context);
  2693. if (enumAction == EA_STOP_ENUMERATION) {
  2694. HeapFree(ghPnPHeap, 0, enumElement);
  2695. break;
  2696. }
  2697. if (enumAction != EA_SKIP_SUBTREE) {
  2698. Status = EnumerateSubTreeTopDownBreadthFirstWorker(
  2699. BindingHandle,
  2700. enumElement->DevInst,
  2701. &subTreeHead
  2702. );
  2703. if (Status != CR_SUCCESS) {
  2704. HeapFree(ghPnPHeap, 0, enumElement);
  2705. break;
  2706. }
  2707. }
  2708. HeapFree(ghPnPHeap, 0, enumElement);
  2709. }
  2710. //
  2711. // There might be entries left in the list if we bailed prematurely. Clean
  2712. // them out here.
  2713. //
  2714. while(!IsListEmpty(&subTreeHead)) {
  2715. listEntry = RemoveHeadList(&subTreeHead);
  2716. enumElement = CONTAINING_RECORD(listEntry, ENUM_ELEMENT, ListEntry);
  2717. HeapFree(ghPnPHeap, 0, enumElement);
  2718. }
  2719. return Status;
  2720. } // EnumerateSubTreeTopDownBreadthFirst
  2721. CONFIGRET
  2722. EnumerateSubTreeTopDownBreadthFirstWorker(
  2723. IN handle_t BindingHandle,
  2724. IN LPCWSTR DevInst,
  2725. IN OUT PLIST_ENTRY ListHead
  2726. )
  2727. /*++
  2728. Routine Description:
  2729. This routine inserts all the child relations of DevInst onto the passed in
  2730. list.
  2731. Arguments:
  2732. BindingHandle RPC Binding handle
  2733. DevInst InstancePath to enumerate.
  2734. ListHead List to append children to.
  2735. Return Value:
  2736. CONFIGRET
  2737. --*/
  2738. {
  2739. CONFIGRET Status = CR_SUCCESS;
  2740. ULONG ulLen;
  2741. LPWSTR pszRelations, pszCurEntry;
  2742. PENUM_ELEMENT enumElement;
  2743. size_t DeviceIDLen = 0;
  2744. //
  2745. // Get the size required for the list of all bus relations
  2746. //
  2747. Status = PNP_GetDeviceListSize(
  2748. BindingHandle,
  2749. DevInst,
  2750. &ulLen,
  2751. CM_GETIDLIST_FILTER_BUSRELATIONS);
  2752. if ((Status != CR_SUCCESS) || (ulLen == 0)) {
  2753. return Status;
  2754. }
  2755. //
  2756. // Allocate an element for the first entry.
  2757. //
  2758. pszRelations = (LPWSTR)
  2759. HeapAlloc(ghPnPHeap, HEAP_ZERO_MEMORY,
  2760. ((ulLen + 2)*sizeof(WCHAR)));
  2761. if (pszRelations == NULL) {
  2762. return CR_OUT_OF_MEMORY;
  2763. }
  2764. //
  2765. // Get the list of all bus relations
  2766. //
  2767. Status = PNP_GetDeviceList(
  2768. BindingHandle,
  2769. DevInst,
  2770. pszRelations,
  2771. &ulLen,
  2772. CM_GETIDLIST_FILTER_BUSRELATIONS);
  2773. if (Status != CR_SUCCESS) {
  2774. HeapFree(ghPnPHeap, 0, pszRelations);
  2775. return Status;
  2776. }
  2777. //
  2778. // Insert each related device into the list
  2779. //
  2780. for (pszCurEntry = pszRelations;
  2781. *pszCurEntry != L'\0';
  2782. pszCurEntry = pszCurEntry + lstrlen(pszCurEntry)+1) {
  2783. if (FAILED(StringCchLength(
  2784. pszCurEntry,
  2785. MAX_DEVICE_ID_LEN,
  2786. &DeviceIDLen))) {
  2787. continue;
  2788. }
  2789. ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
  2790. enumElement = (PENUM_ELEMENT)
  2791. HeapAlloc(ghPnPHeap, 0,
  2792. sizeof(ENUM_ELEMENT) +
  2793. ((DeviceIDLen + 1 - ANYSIZE_ARRAY) * sizeof(WCHAR)));
  2794. if (enumElement == NULL) {
  2795. HeapFree(ghPnPHeap, 0, pszRelations);
  2796. return CR_OUT_OF_MEMORY;
  2797. }
  2798. if (FAILED(StringCchCopy(
  2799. enumElement->DevInst,
  2800. DeviceIDLen + 1,
  2801. pszCurEntry))) {
  2802. HeapFree(ghPnPHeap, 0, enumElement);
  2803. continue;
  2804. }
  2805. //
  2806. // Insert it into the end of the tree.
  2807. //
  2808. InsertTailList(ListHead, &enumElement->ListEntry);
  2809. }
  2810. HeapFree(ghPnPHeap, 0, pszRelations);
  2811. return CR_SUCCESS;
  2812. } // EnumerateSubTreeTopDownBreadthFirstWorker
  2813.