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.

1219 lines
34 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. cutil.c
  5. Abstract:
  6. This module contains general utility routines used by both cfgmgr32
  7. and umpnpmgr.
  8. IsLegalDeviceId
  9. SplitString
  10. SplitDeviceInstanceString
  11. SplitClassInstanceString
  12. DeletePrivateKey
  13. RegDeleteNode
  14. GetDevNodeKeyPath
  15. MapRpcExceptionToCR
  16. Author:
  17. Paula Tomlinson (paulat) 7-12-1995
  18. Environment:
  19. User mode only.
  20. Revision History:
  21. 12-July-1995 paulat
  22. Creation and initial implementation.
  23. --*/
  24. //
  25. // includes
  26. //
  27. #include "precomp.h"
  28. #pragma hdrstop
  29. #include "umpnplib.h"
  30. //
  31. // Common private utility routines (used by client and server)
  32. //
  33. BOOL
  34. IsLegalDeviceId(
  35. IN LPCWSTR pszDeviceInstance
  36. )
  37. /*++
  38. Routine Description:
  39. This routine parses the device instance string and validates whether it
  40. conforms to the appropriate rules, including:
  41. - Total length of the device instance path must not be longer than
  42. MAX_DEVICE_ID_LEN characters.
  43. - The device instance path must contain exactly 3 non-empty path components.
  44. - The device instance path string must not contain any "invalid characters".
  45. Invalid characters are:
  46. c <= 0x20 (' ')
  47. c > 0x7F
  48. c == 0x2C (',')
  49. Arguments:
  50. pszDeviceInstance - Device instance path.
  51. Return value:
  52. The return value is TRUE if the device instance path string conforms to the
  53. rules.
  54. --*/
  55. {
  56. BOOL Status;
  57. LPCWSTR p;
  58. ULONG ulComponentLength = 0, ulComponents = 1;
  59. HRESULT hr;
  60. size_t len;
  61. try {
  62. //
  63. // A NULL or empty string is used for an optional device instance path.
  64. //
  65. // NOTE - Callers must explicitly check for this case themselves if it
  66. // is not valid for a particular scenario.
  67. //
  68. if ((!ARGUMENT_PRESENT(pszDeviceInstance)) ||
  69. (*pszDeviceInstance == L'\0')) {
  70. Status = TRUE;
  71. goto Clean0;
  72. }
  73. //
  74. // Make sure the device instance path isn't too long.
  75. //
  76. hr = StringCchLength(pszDeviceInstance,
  77. MAX_DEVICE_ID_LEN,
  78. &len);
  79. if (FAILED(hr)) {
  80. Status = FALSE;
  81. goto Clean0;
  82. }
  83. //
  84. // Walk over the entire device instance path, counting individual path
  85. // component lengths, and checking for the presence of invalid
  86. // characters.
  87. //
  88. for (p = pszDeviceInstance; *p; p++) {
  89. //
  90. // Check for the presence of invalid characters.
  91. //
  92. if ((*p <= L' ') || (*p > (WCHAR)0x7F) || (*p == L',')) {
  93. Status = FALSE;
  94. goto Clean0;
  95. }
  96. //
  97. // Check the length of individual path components.
  98. //
  99. if (*p == L'\\') {
  100. //
  101. // It is illegal for a device instance path to have multiple
  102. // consecutive path separators, or to start with one.
  103. //
  104. if (ulComponentLength == 0) {
  105. Status = FALSE;
  106. goto Clean0;
  107. }
  108. ulComponentLength = 0;
  109. ulComponents++;
  110. } else {
  111. //
  112. // Count the length of this path component to verify it's not empty.
  113. //
  114. ulComponentLength++;
  115. }
  116. }
  117. //
  118. // It is illegal for a device instance path to end with a path separator
  119. // character.
  120. //
  121. if (ulComponentLength == 0) {
  122. Status = FALSE;
  123. goto Clean0;
  124. }
  125. //
  126. // A valid device instance path must contain exactly 3 path components:
  127. // an enumerator id, a device id, and an instance id.
  128. //
  129. if (ulComponents != 3) {
  130. Status = FALSE;
  131. goto Clean0;
  132. }
  133. //
  134. // Success.
  135. //
  136. Status = TRUE;
  137. Clean0:
  138. NOTHING;
  139. } except(EXCEPTION_EXECUTE_HANDLER) {
  140. Status = FALSE;
  141. }
  142. return Status;
  143. } // IsLegalDeviceId
  144. BOOL
  145. SplitString(
  146. IN LPCWSTR SourceString,
  147. IN WCHAR SearchChar,
  148. IN ULONG nOccurrence,
  149. OUT LPWSTR String1,
  150. IN ULONG Length1,
  151. OUT LPWSTR String2,
  152. IN ULONG Length2
  153. )
  154. /*++
  155. Routine Description:
  156. Splits a string into two substring parts, occuring at at the specified
  157. instance of the specified search charatcter.
  158. Arguments:
  159. SourceString - Specifies the string to be split.
  160. SearchChar - Specifies the character to search for.
  161. nOccurrence - Specifies the instance of the search character in the source
  162. string to split the string at.
  163. String1 - Specifies a buffer to receive the first substring component.
  164. Length1 - Specifies the length, in characters of the buffer specified
  165. by String1.
  166. String2 - Specifies a buffer to receive the second substring component.
  167. Length2 - Specifies the length, in characters of the buffer specified
  168. by String2.
  169. Return Value:
  170. The return value is TRUE if the function suceeds and FALSE if it fails.
  171. Notes:
  172. The buffers specified by String1 and String2 should be large enough to hold
  173. the SourceString.
  174. --*/
  175. {
  176. BOOL Status = TRUE;
  177. HRESULT hr;
  178. LPWSTR p;
  179. ULONG i;
  180. try {
  181. //
  182. // make sure valid buffers were supplied
  183. //
  184. if ((SourceString == NULL) ||
  185. (String1 == NULL) || (Length1 == 0) ||
  186. (String2 == NULL) || (Length2 == 0)) {
  187. Status = FALSE;
  188. goto Clean0;
  189. }
  190. //
  191. // initialize the output strings
  192. //
  193. *String1 = L'\0';
  194. *String2 = L'\0';
  195. //
  196. // copy the entire source string to String1
  197. //
  198. hr = StringCchCopyEx(String1,
  199. Length1,
  200. SourceString,
  201. NULL, NULL,
  202. STRSAFE_NULL_ON_FAILURE);
  203. if (FAILED(hr)) {
  204. Status = FALSE;
  205. goto Clean0;
  206. }
  207. //
  208. // if splitting at the zero'th occurrence of a character, return the
  209. // entire source string as String1.
  210. //
  211. if (nOccurrence == 0) {
  212. Status = TRUE;
  213. goto Clean0;
  214. }
  215. //
  216. // Special case the NULL search character.
  217. //
  218. if (SearchChar == L'\0') {
  219. if (nOccurrence == 1) {
  220. //
  221. // since the source string must be NULL terminated, splitting at
  222. // the first occurrence of a NULL character returns the source
  223. // string as String1, and an empty string as String2.
  224. //
  225. Status = TRUE;
  226. } else {
  227. //
  228. // requesting any other instance of a NULL character returns an
  229. // error, and no strings.
  230. //
  231. *String1 = L'\0';
  232. Status = FALSE;
  233. }
  234. goto Clean0;
  235. }
  236. //
  237. // find the nth instance of the delimiter character. note that we know
  238. // the buffer is NULL terminated before Length1 characters, so we can
  239. // walk the string safely, all the to the end if necessary.
  240. //
  241. p = String1;
  242. i = 0;
  243. for (i = 0; i < nOccurrence; i++) {
  244. //
  245. // search for the nth occurrence of the search character
  246. //
  247. p = wcschr(p, SearchChar);
  248. //
  249. // if we're reached the end of the string, we're done.
  250. //
  251. if (p == NULL) {
  252. break;
  253. }
  254. //
  255. // start the next search immediately following this occurrence of
  256. // the search character
  257. //
  258. p++;
  259. }
  260. if (p == NULL) {
  261. //
  262. // there's no such occurance of the delimeter character in the
  263. // string. return an error, but return the entire string in
  264. // String1 so the caller knows why the failure occured..
  265. //
  266. Status = FALSE;
  267. goto Clean0;
  268. }
  269. ASSERT(p != String1);
  270. ASSERT((*(p - 1)) == SearchChar);
  271. //
  272. // separate the first string from the rest of the string by NULL'ing out
  273. // this occurance the search character.
  274. //
  275. *(p - 1) = L'\0';
  276. //
  277. // if there's nothing left, we're done.
  278. //
  279. if (*p == L'\0') {
  280. Status = TRUE;
  281. goto Clean0;
  282. }
  283. //
  284. // copy the remainder of the string to string2.
  285. //
  286. hr = StringCchCopyEx(String2,
  287. Length2,
  288. p,
  289. NULL, NULL,
  290. STRSAFE_NULL_ON_FAILURE);
  291. ASSERT(SUCCEEDED(hr));
  292. if (FAILED(hr)) {
  293. *String1 = L'\0';
  294. Status = FALSE;
  295. goto Clean0;
  296. }
  297. //
  298. // Success
  299. //
  300. Status = TRUE;
  301. Clean0:
  302. NOTHING;
  303. } except(EXCEPTION_EXECUTE_HANDLER) {
  304. Status = FALSE;
  305. }
  306. return Status;
  307. } // SplitString
  308. BOOL
  309. SplitDeviceInstanceString(
  310. IN LPCWSTR pszDeviceInstance,
  311. OUT LPWSTR pszEnumerator,
  312. OUT LPWSTR pszDeviceID,
  313. OUT LPWSTR pszInstanceID
  314. )
  315. /*++
  316. Routine Description:
  317. This routine parses a device instance string into it's three component
  318. parts. This routine assumes that the specified device instance is a valid
  319. device instance path, whose length is no more than MAX_DEVICE_ID_LEN
  320. characters, including the NULL terminating character.
  321. This routine assumes that each of the buffers supplied to receive the device
  322. instance path components are each at least MAX_DEVICE_ID_LEN characters in
  323. length.
  324. Arguments:
  325. pszDeviceInstance - Specifies a complete device instance path to separate
  326. into it's constituent parts.
  327. pszEnumerator - Specifies a buffer to receive the Enumerator component
  328. of the device instance path.
  329. pszDeviceID - Specifies a buffer to receive the Device ID component
  330. of the device instance path.
  331. pszInstanceID - Specifies a buffer to receive the Instance ID component
  332. of the device instance path.
  333. Return value:
  334. The return value is TRUE if the function suceeds and FALSE if it fails.
  335. --*/
  336. {
  337. BOOL Status;
  338. WCHAR szTempString[MAX_DEVICE_ID_LEN];
  339. //
  340. // initialize the output strings
  341. //
  342. *pszEnumerator = L'\0';
  343. *pszDeviceID = L'\0';
  344. *pszInstanceID = L'\0';
  345. //
  346. // Split off the enumerator component.
  347. //
  348. Status =
  349. SplitString(
  350. pszDeviceInstance,
  351. L'\\',
  352. 1,
  353. pszEnumerator,
  354. MAX_DEVICE_ID_LEN,
  355. szTempString,
  356. MAX_DEVICE_ID_LEN
  357. );
  358. if (Status) {
  359. //
  360. // Split off the device id component. Consider the rest to be the
  361. // instance id. The device instance id should have been previously
  362. // validated to ensure that it has exactly thee components.
  363. //
  364. Status =
  365. SplitString(
  366. szTempString,
  367. L'\\',
  368. 1,
  369. pszDeviceID,
  370. MAX_DEVICE_ID_LEN,
  371. pszInstanceID,
  372. MAX_DEVICE_ID_LEN
  373. );
  374. }
  375. return Status;
  376. } // SplitDeviceInstanceString
  377. BOOL
  378. SplitClassInstanceString(
  379. IN LPCWSTR pszClassInstance,
  380. OUT LPWSTR pszClass,
  381. OUT LPWSTR pszInstance
  382. )
  383. /*++
  384. Routine Description:
  385. This routine parses a class instance string into it's two component
  386. parts. This routine assumes that the specified device instance is a valid
  387. class instance path, whose length is no more than MAX_GUID_STRING_LEN + 5
  388. characters, including the NULL terminating character.
  389. This routine assumes that each of the buffers supplied to receive the device
  390. instance path components are each at least MAX_GUID_STRING_LEN + 5
  391. characters in length.
  392. Arguments:
  393. pszClassInstance - Specifies a complete class instance path to separate
  394. into it's constituent parts.
  395. pszClass - Specifies a buffer to receive the ClassGUID component
  396. of the class instance path.
  397. pszInstance - Specifies a buffer to receive the Instance component
  398. of the class instance path.
  399. Return value:
  400. The return value is TRUE if the function suceeds and FALSE if it fails.
  401. --*/
  402. {
  403. BOOL Status;
  404. //
  405. // initialize the output strings
  406. //
  407. *pszClass = L'\0';
  408. *pszInstance = L'\0';
  409. //
  410. // Split off the class and instance components.
  411. //
  412. Status =
  413. SplitString(
  414. pszClassInstance,
  415. L'\\',
  416. 1,
  417. pszClass,
  418. MAX_GUID_STRING_LEN + 5,
  419. pszInstance,
  420. MAX_GUID_STRING_LEN + 5
  421. );
  422. return Status;
  423. } // SplitClassInstanceString
  424. CONFIGRET
  425. DeletePrivateKey(
  426. IN HKEY hBranchKey,
  427. IN LPCWSTR pszParentKey,
  428. IN LPCWSTR pszChildKey
  429. )
  430. {
  431. CONFIGRET Status = CR_SUCCESS;
  432. LONG RegStatus = ERROR_SUCCESS;
  433. WCHAR RegStr[2 * MAX_CM_PATH];
  434. WCHAR szKey1[MAX_CM_PATH], szKey2[MAX_CM_PATH];
  435. HKEY hKey = NULL;
  436. ULONG ulSubKeys = 0;
  437. HRESULT hr;
  438. size_t ParentKeyLen = 0, ChildKeyLen = 0;
  439. try {
  440. //
  441. // Make sure the specified registry key paths are valid.
  442. //
  443. if ((!ARGUMENT_PRESENT(pszParentKey)) ||
  444. (!ARGUMENT_PRESENT(pszChildKey))) {
  445. Status = CR_INVALID_POINTER;
  446. goto Clean0;
  447. }
  448. hr = StringCchLength(pszParentKey,
  449. MAX_CM_PATH,
  450. &ParentKeyLen);
  451. if (FAILED(hr) || (ParentKeyLen == 0)) {
  452. Status = CR_INVALID_POINTER;
  453. goto Clean0;
  454. }
  455. hr = StringCchLength(pszChildKey,
  456. MAX_CM_PATH,
  457. &ChildKeyLen);
  458. if (FAILED(hr) || (ChildKeyLen == 0)) {
  459. Status = CR_INVALID_POINTER;
  460. goto Clean0;
  461. }
  462. //
  463. // is the specified child key a compound registry key?
  464. //
  465. if (!SplitString(pszChildKey,
  466. L'\\',
  467. 1,
  468. szKey1,
  469. SIZECHARS(szKey1),
  470. szKey2,
  471. SIZECHARS(szKey2))) {
  472. //------------------------------------------------------------------
  473. // If unable to split the string, assume only a single child key
  474. // was specified, so just open the parent registry key and delete
  475. // the child (and any of its subkeys)
  476. //------------------------------------------------------------------
  477. if (RegOpenKeyEx(hBranchKey, pszParentKey, 0,
  478. KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS) {
  479. goto Clean0; // no error, nothing to delete
  480. }
  481. if (!RegDeleteNode(hKey, pszChildKey)) {
  482. Status = CR_REGISTRY_ERROR;
  483. goto Clean0;
  484. }
  485. } else {
  486. //------------------------------------------------------------------
  487. // if a compound registry path was passed in, such as key1\key2
  488. // then always delete key2 but delete key1 only if it has no other
  489. // subkeys besides key2.
  490. //------------------------------------------------------------------
  491. //
  492. // open the first level key
  493. //
  494. hr = StringCchPrintf(RegStr,
  495. SIZECHARS(RegStr),
  496. L"%s\\%s",
  497. pszParentKey,
  498. szKey1);
  499. ASSERT(SUCCEEDED(hr));
  500. if (FAILED(hr)) {
  501. Status = CR_FAILURE;
  502. goto Clean0;
  503. }
  504. RegStatus = RegOpenKeyEx(
  505. hBranchKey, RegStr, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
  506. &hKey);
  507. if (RegStatus != ERROR_SUCCESS) {
  508. goto Clean0; // no error, nothing to delete
  509. }
  510. //
  511. // try to delete the second level key
  512. //
  513. if (!RegDeleteNode(hKey, szKey2)) {
  514. goto Clean0; // no error, nothing to delete
  515. }
  516. //
  517. // How many subkeys are remaining?
  518. //
  519. RegStatus = RegQueryInfoKey(
  520. hKey, NULL, NULL, NULL, &ulSubKeys,
  521. NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  522. if (RegStatus != ERROR_SUCCESS) {
  523. goto Clean0; // nothing to delete
  524. }
  525. //
  526. // if no more subkeys, then delete the first level key
  527. //
  528. if (ulSubKeys == 0) {
  529. RegCloseKey(hKey);
  530. hKey = NULL;
  531. RegStatus = RegOpenKeyEx(
  532. hBranchKey, pszParentKey, 0,
  533. KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey);
  534. if (RegStatus != ERROR_SUCCESS) {
  535. goto Clean0; // no error, nothing to delete
  536. }
  537. if (!RegDeleteNode(hKey, szKey1)) {
  538. Status = CR_REGISTRY_ERROR;
  539. goto Clean0;
  540. }
  541. }
  542. }
  543. Clean0:
  544. NOTHING;
  545. } except(EXCEPTION_EXECUTE_HANDLER) {
  546. Status = CR_FAILURE;
  547. //
  548. // Reference the following variables so the compiler will respect
  549. // statement ordering w.r.t. their assignment.
  550. //
  551. hKey = hKey;
  552. }
  553. if (hKey != NULL) {
  554. RegCloseKey(hKey);
  555. }
  556. return Status;
  557. } // DeletePrivateKey
  558. BOOL
  559. RegDeleteNode(
  560. HKEY hParentKey,
  561. LPCWSTR szKey
  562. )
  563. {
  564. ULONG ulSize = 0;
  565. LONG RegStatus = ERROR_SUCCESS;
  566. HKEY hKey = NULL;
  567. WCHAR szSubKey[MAX_PATH];
  568. //
  569. // attempt to delete the key
  570. //
  571. if (RegDeleteKey(hParentKey, szKey) != ERROR_SUCCESS) {
  572. //
  573. // If we couldn't delete the key itself, delete any subkeys it may have.
  574. // In case the specified key is actually a registry link, always open it
  575. // directly, rather than the target of the link. The target may point
  576. // outside this subtree, and we're only looking to delete subkeys.
  577. //
  578. RegStatus = RegOpenKeyEx(
  579. hParentKey, szKey,
  580. REG_OPTION_OPEN_LINK,
  581. KEY_ALL_ACCESS, &hKey);
  582. //
  583. // enumerate subkeys and delete those nodes
  584. //
  585. while (RegStatus == ERROR_SUCCESS) {
  586. //
  587. // enumerate the first level children under the profile key
  588. // (always use index 0, enumeration looses track when a key
  589. // is added or deleted)
  590. //
  591. ulSize = MAX_PATH;
  592. RegStatus = RegEnumKeyEx(
  593. hKey, 0, szSubKey, &ulSize, NULL, NULL, NULL, NULL);
  594. if (RegStatus == ERROR_SUCCESS) {
  595. RegDeleteNode(hKey, szSubKey);
  596. }
  597. }
  598. //
  599. // either an error occured that prevents me from deleting the
  600. // keys (like the key doesn't exist in the first place or an
  601. // access violation) or the subkeys have been deleted, try
  602. // deleting the top level key again
  603. //
  604. RegCloseKey(hKey);
  605. RegDeleteKey(hParentKey, szKey);
  606. }
  607. return TRUE;
  608. } // RegDeleteNode
  609. CONFIGRET
  610. GetDevNodeKeyPath(
  611. IN handle_t hBinding,
  612. IN LPCWSTR pDeviceID,
  613. IN ULONG ulFlags,
  614. IN ULONG ulHardwareProfile,
  615. OUT LPWSTR pszBaseKey,
  616. IN ULONG ulBaseKeyLength,
  617. OUT LPWSTR pszPrivateKey,
  618. IN ULONG ulPrivateKeyLength,
  619. IN BOOL bCreateAlways
  620. )
  621. {
  622. CONFIGRET Status = CR_SUCCESS;
  623. WCHAR szClassInstance[MAX_PATH], szEnumerator[MAX_DEVICE_ID_LEN];
  624. WCHAR szTemp[MAX_PATH];
  625. ULONG ulSize, ulDataType = 0;
  626. ULONG ulTransferLen;
  627. HRESULT hr;
  628. if (ulFlags & CM_REGISTRY_SOFTWARE) {
  629. //-------------------------------------------------------------
  630. // form the key for the software branch case
  631. //-------------------------------------------------------------
  632. //
  633. // retrieve the class name and instance ordinal by calling
  634. // the server's reg prop routine
  635. //
  636. ulSize = ulTransferLen = sizeof(szClassInstance);
  637. szClassInstance[0] = L'\0';
  638. RpcTryExcept {
  639. //
  640. // call rpc service entry point
  641. //
  642. // if calling from the client-side, this is a call to the rpc client
  643. // stub, resulting in an rpc call to the server. if calling from
  644. // the server-side, this is simply a call to the server routine
  645. // directly.
  646. //
  647. Status = PNP_GetDeviceRegProp(
  648. hBinding,
  649. pDeviceID,
  650. CM_DRP_DRIVER,
  651. &ulDataType,
  652. (LPBYTE)szClassInstance,
  653. &ulTransferLen,
  654. &ulSize,
  655. 0);
  656. }
  657. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  658. KdPrintEx((DPFLTR_PNPMGR_ID,
  659. DBGF_ERRORS,
  660. "PNP_GetDeviceRegProp caused an exception (%d)\n",
  661. RpcExceptionCode()));
  662. Status = MapRpcExceptionToCR(RpcExceptionCode());
  663. }
  664. RpcEndExcept
  665. if (((Status != CR_SUCCESS) ||
  666. (szClassInstance[0] == L'\0')) && (bCreateAlways)) {
  667. //
  668. // no Driver (class instance) value yet so ask the server to
  669. // create a new unique one
  670. //
  671. ulSize = sizeof(szClassInstance);
  672. RpcTryExcept {
  673. //
  674. // call rpc service entry point
  675. //
  676. // if calling from the client-side, this is a call to the rpc client
  677. // stub, resulting in an rpc call to the server. if calling from
  678. // the server-side, this is simply a call to the server routine
  679. // directly.
  680. //
  681. Status = PNP_GetClassInstance(
  682. hBinding,
  683. pDeviceID,
  684. szClassInstance,
  685. ulSize);
  686. }
  687. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  688. KdPrintEx((DPFLTR_PNPMGR_ID,
  689. DBGF_ERRORS,
  690. "PNP_GetClassInstance caused an exception (%d)\n",
  691. RpcExceptionCode()));
  692. Status = MapRpcExceptionToCR(RpcExceptionCode());
  693. }
  694. RpcEndExcept
  695. }
  696. if (Status != CR_SUCCESS) {
  697. //
  698. // If the CM_DRP_DRIVER did not exist and we were not to create it, or
  699. // the attempt to create one was unsuccessful, return the error.
  700. //
  701. goto Clean0;
  702. }
  703. //
  704. // the <instance> part of the class instance is the private part
  705. //
  706. if (!SplitString(szClassInstance,
  707. L'\\',
  708. 1,
  709. szTemp,
  710. SIZECHARS(szTemp),
  711. pszPrivateKey,
  712. ulPrivateKeyLength)) {
  713. ASSERT(0);
  714. Status = CR_FAILURE;
  715. goto Clean0;
  716. }
  717. hr = StringCchCopy(szClassInstance,
  718. SIZECHARS(szClassInstance),
  719. szTemp);
  720. ASSERT(SUCCEEDED(hr));
  721. if (FAILED(hr)) {
  722. Status = CR_FAILURE;
  723. goto Clean0;
  724. }
  725. if (ulFlags & CM_REGISTRY_CONFIG) {
  726. //
  727. // config-specific software branch case
  728. //
  729. if (ulHardwareProfile == 0) {
  730. //
  731. // curent config
  732. //
  733. // System\CCC\Hardware Profiles\Current
  734. // \System\CCC\Control\Class\<DevNodeClassInstance>
  735. //
  736. hr = StringCchPrintfEx(pszBaseKey,
  737. ulBaseKeyLength,
  738. NULL, NULL,
  739. STRSAFE_NULL_ON_FAILURE,
  740. L"%s\\%s\\%s\\%s",
  741. REGSTR_PATH_HWPROFILES,
  742. REGSTR_KEY_CURRENT,
  743. REGSTR_PATH_CLASS_NT,
  744. szClassInstance);
  745. } else if (ulHardwareProfile == 0xFFFFFFFF) {
  746. //
  747. // all configs, use substitute string for profile id
  748. //
  749. hr = StringCchPrintfEx(pszBaseKey,
  750. ulBaseKeyLength,
  751. NULL, NULL,
  752. STRSAFE_NULL_ON_FAILURE,
  753. L"%s\\%s\\%s\\%s",
  754. REGSTR_PATH_HWPROFILES,
  755. L"%s",
  756. REGSTR_PATH_CLASS_NT,
  757. szClassInstance);
  758. } else {
  759. //
  760. // specific profile specified
  761. //
  762. // System\CCC\Hardware Profiles\<profile>
  763. // \System\CCC\Control\Class\<DevNodeClassInstance>
  764. //
  765. hr = StringCchPrintfEx(pszBaseKey,
  766. ulBaseKeyLength,
  767. NULL, NULL,
  768. STRSAFE_NULL_ON_FAILURE,
  769. L"%s\\%04u\\%s\\%s",
  770. REGSTR_PATH_HWPROFILES,
  771. ulHardwareProfile,
  772. REGSTR_PATH_CLASS_NT,
  773. szClassInstance);
  774. }
  775. } else {
  776. //
  777. // not config-specific
  778. // System\CCC\Control\Class\<DevNodeClassInstance>
  779. //
  780. hr = StringCchPrintfEx(pszBaseKey,
  781. ulBaseKeyLength,
  782. NULL, NULL,
  783. STRSAFE_NULL_ON_FAILURE,
  784. L"%s\\%s",
  785. REGSTR_PATH_CLASS_NT,
  786. szClassInstance);
  787. }
  788. ASSERT(SUCCEEDED(hr));
  789. if (FAILED(hr)) {
  790. Status = CR_FAILURE;
  791. goto Clean0;
  792. }
  793. } else {
  794. //-------------------------------------------------------------
  795. // form the key for the hardware branch case
  796. //-------------------------------------------------------------
  797. if (ulFlags & CM_REGISTRY_CONFIG) {
  798. //
  799. // config-specific hardware branch case
  800. //
  801. //
  802. // for profile specific, the <device>\<instance> part of
  803. // the device id is the private part
  804. //
  805. if (!SplitString(pDeviceID,
  806. L'\\',
  807. 1,
  808. szEnumerator,
  809. SIZECHARS(szEnumerator),
  810. pszPrivateKey,
  811. ulPrivateKeyLength)) {
  812. ASSERT(0);
  813. Status = CR_FAILURE;
  814. goto Clean0;
  815. }
  816. if (ulHardwareProfile == 0) {
  817. //
  818. // curent config
  819. //
  820. hr = StringCchPrintfEx(pszBaseKey,
  821. ulBaseKeyLength,
  822. NULL, NULL,
  823. STRSAFE_NULL_ON_FAILURE,
  824. L"%s\\%s\\%s\\%s",
  825. REGSTR_PATH_HWPROFILES,
  826. REGSTR_KEY_CURRENT,
  827. REGSTR_PATH_SYSTEMENUM,
  828. szEnumerator);
  829. } else if (ulHardwareProfile == 0xFFFFFFFF) {
  830. //
  831. // all configs, use replacement symbol for profile id
  832. //
  833. hr = StringCchPrintfEx(pszBaseKey,
  834. ulBaseKeyLength,
  835. NULL, NULL,
  836. STRSAFE_NULL_ON_FAILURE,
  837. L"%s\\%s\\%s\\%s",
  838. REGSTR_PATH_HWPROFILES,
  839. L"%s",
  840. REGSTR_PATH_SYSTEMENUM,
  841. szEnumerator);
  842. } else {
  843. //
  844. // specific profile specified
  845. //
  846. hr = StringCchPrintfEx(pszBaseKey,
  847. ulBaseKeyLength,
  848. NULL, NULL,
  849. STRSAFE_NULL_ON_FAILURE,
  850. L"%s\\%04u\\%s\\%s",
  851. REGSTR_PATH_HWPROFILES,
  852. ulHardwareProfile,
  853. REGSTR_PATH_SYSTEMENUM,
  854. szEnumerator);
  855. }
  856. } else if (ulFlags & CM_REGISTRY_USER) {
  857. //
  858. // for hardware user key, the <device>\<instance> part of
  859. // the device id is the private part
  860. //
  861. if (!SplitString(pDeviceID,
  862. L'\\',
  863. 1,
  864. szEnumerator,
  865. SIZECHARS(szEnumerator),
  866. pszPrivateKey,
  867. ulPrivateKeyLength)) {
  868. Status = CR_FAILURE;
  869. goto Clean0;
  870. }
  871. hr = StringCchPrintfEx(pszBaseKey,
  872. ulBaseKeyLength,
  873. NULL, NULL,
  874. STRSAFE_NULL_ON_FAILURE,
  875. L"%s\\%s",
  876. REGSTR_PATH_SYSTEMENUM,
  877. szEnumerator);
  878. } else {
  879. //
  880. // not config-specific
  881. //
  882. hr = StringCchPrintfEx(pszBaseKey,
  883. ulBaseKeyLength,
  884. NULL, NULL,
  885. STRSAFE_NULL_ON_FAILURE,
  886. L"%s\\%s",
  887. REGSTR_PATH_SYSTEMENUM,
  888. pDeviceID);
  889. ASSERT(SUCCEEDED(hr));
  890. if (SUCCEEDED(hr)) {
  891. hr = StringCchCopyEx(pszPrivateKey,
  892. ulPrivateKeyLength,
  893. REGSTR_KEY_DEVICEPARAMETERS,
  894. NULL, NULL,
  895. STRSAFE_NULL_ON_FAILURE);
  896. }
  897. }
  898. ASSERT(SUCCEEDED(hr));
  899. if (FAILED(hr)) {
  900. Status = CR_FAILURE;
  901. goto Clean0;
  902. }
  903. }
  904. Clean0:
  905. return Status;
  906. } // GetDevNodeKeyPath
  907. CONFIGRET
  908. MapRpcExceptionToCR(
  909. ULONG ulRpcExceptionCode
  910. )
  911. /*++
  912. Routine Description:
  913. This routine takes an rpc exception code (typically received by
  914. calling RpcExceptionCode) and returns a corresponding CR_ error
  915. code.
  916. Arguments:
  917. ulRpcExceptionCode An RPC_S_ or RPC_X_ exception error code.
  918. Return Value:
  919. Return value is one of the CR_ error codes.
  920. --*/
  921. {
  922. CONFIGRET Status = CR_FAILURE;
  923. switch(ulRpcExceptionCode) {
  924. //
  925. // binding or machine name errors
  926. //
  927. case RPC_S_INVALID_STRING_BINDING: // 1700L
  928. case RPC_S_WRONG_KIND_OF_BINDING: // 1701L
  929. case RPC_S_INVALID_BINDING: // 1702L
  930. case RPC_S_PROTSEQ_NOT_SUPPORTED: // 1703L
  931. case RPC_S_INVALID_RPC_PROTSEQ: // 1704L
  932. case RPC_S_INVALID_STRING_UUID: // 1705L
  933. case RPC_S_INVALID_ENDPOINT_FORMAT: // 1706L
  934. case RPC_S_INVALID_NET_ADDR: // 1707L
  935. case RPC_S_NO_ENDPOINT_FOUND: // 1708L
  936. case RPC_S_NO_MORE_BINDINGS: // 1806L
  937. case RPC_S_CANT_CREATE_ENDPOINT: // 1720L
  938. Status = CR_INVALID_MACHINENAME;
  939. break;
  940. //
  941. // general rpc communication failure
  942. //
  943. case RPC_S_INVALID_NETWORK_OPTIONS: // 1724L
  944. case RPC_S_CALL_FAILED: // 1726L
  945. case RPC_S_CALL_FAILED_DNE: // 1727L
  946. case RPC_S_PROTOCOL_ERROR: // 1728L
  947. case RPC_S_UNSUPPORTED_TRANS_SYN: // 1730L
  948. Status = CR_REMOTE_COMM_FAILURE;
  949. break;
  950. //
  951. // couldn't make connection to that machine
  952. //
  953. case RPC_S_SERVER_UNAVAILABLE: // 1722L
  954. case RPC_S_SERVER_TOO_BUSY: // 1723L
  955. Status = CR_MACHINE_UNAVAILABLE;
  956. break;
  957. //
  958. // server doesn't exist or not right version
  959. //
  960. case RPC_S_INVALID_VERS_OPTION: // 1756L
  961. case RPC_S_INTERFACE_NOT_FOUND: // 1759L
  962. case RPC_S_UNKNOWN_IF: // 1717L
  963. Status = CR_NO_CM_SERVICES;
  964. break;
  965. //
  966. // access denied
  967. //
  968. case RPC_S_ACCESS_DENIED:
  969. Status = CR_ACCESS_DENIED;
  970. break;
  971. //
  972. // any other RPC exceptions will just be general failures
  973. //
  974. default:
  975. Status = CR_FAILURE;
  976. break;
  977. }
  978. return Status;
  979. } // MapRpcExceptionToCR
  980.