Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

983 lines
21 KiB

  1. //============================================================================
  2. // Copyright (c) 1996, Microsoft Corporation
  3. //
  4. // File: setup.c
  5. //
  6. // History:
  7. // 06/24/96 Abolade Gbadegesin Created.
  8. //
  9. // Implements API functions used by IP and IPX to read installation information
  10. // stored under HKLM\Software\Microsoft\Router.
  11. //
  12. // The API functions are presented first, followed by private functions
  13. // in alphabetical order.
  14. //============================================================================
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <rtutils.h>
  20. #include <mprapi.h>
  21. //
  22. // Constant strings used to access the registry:
  23. //
  24. extern const WCHAR c_szProtocolId[];
  25. extern const WCHAR c_szRouter[];
  26. extern const WCHAR c_szRouterManagers[];
  27. const WCHAR c_szDLLName[] = L"DLLName";
  28. const TCHAR c_szCurrentVersion[] = L"CurrentVersion";
  29. const WCHAR c_szMicrosoft[] = L"Microsoft";
  30. const WCHAR c_szSoftware[] = L"Software";
  31. const WCHAR c_szIpInIp[] = L"IpInIp";
  32. //
  33. // Memory management macros:
  34. //
  35. #define Malloc(s) HeapAlloc(GetProcessHeap(), 0, (s))
  36. #define ReAlloc(p,s) HeapReAlloc(GetProcessHeap(), 0, (p), (s))
  37. #define Free(p) HeapFree(GetProcessHeap(), 0, (p))
  38. #define Free0(p) ((p) ? Free(p) : TRUE)
  39. DWORD
  40. QueryRmSoftwareKey(
  41. IN HKEY hkeyMachine,
  42. IN DWORD dwTransportId,
  43. OUT HKEY* phkrm,
  44. OUT LPWSTR* lplpwsRm
  45. );
  46. DWORD
  47. QueryIpInIpSoftwareKey(
  48. IN HKEY hkeyMachine,
  49. OUT HKEY* phkIpIpRead,
  50. OUT HKEY* phkIpIpWrite,
  51. OUT PDWORD pdwNumValues,
  52. OUT PDWORD pdwMaxValueNameLen,
  53. OUT PDWORD pdwMaxValueLen
  54. );
  55. //----------------------------------------------------------------------------
  56. // Function: MprSetupProtocolEnum
  57. //
  58. // Enumerates the protocols installed for transport 'dwTransportId'.
  59. //
  60. // The information is loaded from HKLM\Software\Microsoft\Router,
  61. // where subkeys exist for each router-manager under the 'RouterManagers' key.
  62. // Each router-manager subkey has subkeys containing information
  63. // about that router-manager's routing-protocols.
  64. //
  65. // This API reads a subset of that information, so that router-managers
  66. // can map protocol-IDs to DLL names when loading routing-protocols.
  67. //----------------------------------------------------------------------------
  68. DWORD APIENTRY
  69. MprSetupProtocolEnum(
  70. IN DWORD dwTransportId,
  71. OUT LPBYTE* lplpBuffer, // MPR_PROTOCOL_0
  72. OUT LPDWORD lpdwEntriesRead
  73. ) {
  74. HKEY hkrm;
  75. WCHAR* lpwsRm = NULL;
  76. DWORD dwErr, dwItemCount;
  77. MPR_PROTOCOL_0* pItem, *pItemTable = NULL;
  78. //
  79. // Validate the caller's parameters
  80. //
  81. if (!lplpBuffer ||
  82. !lpdwEntriesRead) { return ERROR_INVALID_PARAMETER; }
  83. *lplpBuffer = NULL;
  84. *lpdwEntriesRead = 0;
  85. //
  86. // Open the key for the specified router-manager
  87. // under HKLM\Software\Microsoft\Router\CurrentVersion\RouterManagers
  88. //
  89. dwErr = QueryRmSoftwareKey(
  90. HKEY_LOCAL_MACHINE, dwTransportId, &hkrm, &lpwsRm
  91. );
  92. if (dwErr != NO_ERROR) { return dwErr; }
  93. //
  94. // The transport was found, so its registry key is in 'hkrm'
  95. //
  96. do {
  97. //
  98. // Retrieve information about the subkeys of the router-manager,
  99. // since these should all contain data for routing-protocols.
  100. //
  101. WCHAR* pwsKey;
  102. DWORD i, dwSize, dwType;
  103. DWORD dwKeyCount, dwMaxKeyLength;
  104. dwErr = RegQueryInfoKey(
  105. hkrm, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLength,
  106. NULL, NULL, NULL, NULL, NULL, NULL
  107. );
  108. if (dwErr != ERROR_SUCCESS) { break; }
  109. //
  110. // Allocate enough space for the longest of the subkeys
  111. //
  112. pwsKey = Malloc((dwMaxKeyLength + 1) * sizeof(WCHAR));
  113. if (!pwsKey) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
  114. //
  115. // Allocate an array to hold the keys' contents
  116. //
  117. pItemTable = (MPR_PROTOCOL_0*)Malloc(dwKeyCount * sizeof(*pItem));
  118. if (!pItemTable) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
  119. ZeroMemory(pItemTable, dwKeyCount * sizeof(*pItem));
  120. //
  121. // Enumerate the keys
  122. //
  123. dwItemCount = 0;
  124. for (i = 0; i < dwKeyCount; i++) {
  125. HKEY hkprot;
  126. PBYTE pValue = NULL;
  127. //
  128. // Get the name of the current key
  129. //
  130. dwSize = dwMaxKeyLength + 1;
  131. dwErr = RegEnumKeyEx(
  132. hkrm, i, pwsKey, &dwSize, NULL, NULL, NULL, NULL
  133. );
  134. if (dwErr != ERROR_SUCCESS) { continue; }
  135. //
  136. // Open the key
  137. //
  138. dwErr = RegOpenKeyEx(hkrm, pwsKey, 0, KEY_READ, &hkprot);
  139. if (dwErr != ERROR_SUCCESS) { continue; }
  140. pItem = pItemTable + dwItemCount;
  141. do {
  142. DWORD dwMaxValLength;
  143. //
  144. // Copy the string for the protocol
  145. //
  146. lstrcpyn(pItem->wszProtocol, pwsKey, MAX_PROTOCOL_NAME_LEN+1);
  147. //
  148. // Get information about the key's values
  149. //
  150. dwErr = RegQueryInfoKey(
  151. hkprot, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  152. NULL, &dwMaxValLength, NULL, NULL
  153. );
  154. if (dwErr != ERROR_SUCCESS) { break; }
  155. //
  156. // Allocate space to hold the longest of the values
  157. //
  158. pValue = Malloc(dwMaxValLength + 1);
  159. if (!pValue) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
  160. //
  161. // Read the ProtocolId value
  162. //
  163. dwSize = dwMaxValLength + 1;
  164. dwErr = RegQueryValueEx(
  165. hkprot, c_szProtocolId, 0, &dwType, pValue, &dwSize
  166. );
  167. if (dwErr != ERROR_SUCCESS) { break; }
  168. pItem->dwProtocolId = *(PDWORD)pValue;
  169. //
  170. // Read the DLLName value
  171. //
  172. dwSize = dwMaxValLength + 1;
  173. dwErr = RegQueryValueEx(
  174. hkprot, c_szDLLName, 0, &dwType, pValue, &dwSize
  175. );
  176. if (dwErr != ERROR_SUCCESS) { break; }
  177. lstrcpyn(
  178. pItem->wszDLLName, (WCHAR*)pValue, MAX_PROTOCOL_DLL_LEN+1);
  179. //
  180. // Increment the count of loaded protocols
  181. //
  182. ++dwItemCount;
  183. dwErr = ERROR_SUCCESS;
  184. } while(FALSE);
  185. Free0(pValue);
  186. RegCloseKey(hkprot);
  187. }
  188. Free0(pwsKey);
  189. } while(FALSE);
  190. Free0(lpwsRm);
  191. if (dwErr != NO_ERROR) {
  192. Free0(pItemTable);
  193. }
  194. else {
  195. //
  196. // Adjust the size of the buffer to be returned,
  197. // in case not all the keys contained routing-protocols,
  198. // and save the number of protocols loaded.
  199. //
  200. *lplpBuffer = ReAlloc(pItemTable, dwItemCount * sizeof(*pItem));
  201. *lpdwEntriesRead = dwItemCount;
  202. }
  203. RegCloseKey(hkrm);
  204. return dwErr;
  205. }
  206. //----------------------------------------------------------------------------
  207. // Function: MprSetupProtocolFree
  208. //
  209. // Called to free a buffer allocated by 'MprSetupProtocolEnum'.
  210. //----------------------------------------------------------------------------
  211. DWORD APIENTRY
  212. MprSetupProtocolFree(
  213. IN LPVOID lpBuffer
  214. ) {
  215. if (!lpBuffer) { return ERROR_INVALID_PARAMETER; }
  216. Free(lpBuffer);
  217. return NO_ERROR;
  218. }
  219. DWORD
  220. APIENTRY
  221. MprSetupIpInIpInterfaceFriendlyNameEnum(
  222. IN PWCHAR pwszMachineName,
  223. OUT LPBYTE* lplpBuffer, // MPR_IPINIP_INTERFACE_0
  224. OUT LPDWORD lpdwEntriesRead
  225. )
  226. {
  227. HKEY hkRead=NULL, hkWrite=NULL, hkMachine=NULL;
  228. DWORD dwErr, dwIndex, i;
  229. DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueLen;
  230. PMPR_IPINIP_INTERFACE_0 pItem, pTable = NULL;
  231. //
  232. // Validate the caller's parameters
  233. //
  234. if (!lplpBuffer ||
  235. !lpdwEntriesRead) {
  236. return ERROR_INVALID_PARAMETER;
  237. }
  238. *lplpBuffer = NULL;
  239. *lpdwEntriesRead = 0;
  240. //
  241. // Connect to the registry
  242. //
  243. dwErr = RegConnectRegistry(
  244. pwszMachineName,
  245. HKEY_LOCAL_MACHINE,
  246. &hkMachine
  247. );
  248. if(dwErr != NO_ERROR) {
  249. return dwErr;
  250. }
  251. //
  252. // Open the HKLM\Software\Microsoft\IpInIp key
  253. //
  254. dwErr = QueryIpInIpSoftwareKey(
  255. hkMachine,
  256. &hkRead,
  257. &hkWrite,
  258. &dwNumValues,
  259. &dwMaxValueNameLen,
  260. &dwMaxValueLen
  261. );
  262. if (dwErr != NO_ERROR)
  263. {
  264. //We need to close hkMachine here
  265. RegCloseKey(hkMachine);
  266. return dwErr;
  267. }
  268. if(dwNumValues == 0) {
  269. if(hkWrite != NULL) {
  270. RegCloseKey(hkWrite);
  271. }
  272. RegCloseKey(hkRead);
  273. RegCloseKey(hkMachine);
  274. return NO_ERROR;
  275. }
  276. //
  277. // So the Value Name shouldnt be longer than a GUID length and
  278. // the value itself should be less that MAX_INTERFACE_NAME_LEN
  279. //
  280. if((dwMaxValueNameLen > 38) ||
  281. (dwMaxValueLen > MAX_INTERFACE_NAME_LEN)) {
  282. RegCloseKey(hkMachine);
  283. return ERROR_REGISTRY_CORRUPT;
  284. }
  285. dwErr = NO_ERROR;
  286. do {
  287. UNICODE_STRING usTempString;
  288. WCHAR rgwcGuid[40];
  289. DWORD dwType;
  290. //
  291. // Allocate an array to hold the ipinip info
  292. //
  293. pTable = Malloc(dwNumValues * sizeof(*pItem));
  294. if (!pTable) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
  295. ZeroMemory(pTable, dwNumValues * sizeof(*pItem));
  296. //
  297. // Enumerate the keys
  298. //
  299. usTempString.MaximumLength = sizeof(rgwcGuid);
  300. usTempString.Buffer = rgwcGuid;
  301. for (i = 0, dwIndex = 0; i < dwNumValues; i++) {
  302. DWORD dwValueNameLen = 39;
  303. DWORD dwValueLen = (MAX_INTERFACE_NAME_LEN + 1) * sizeof(WCHAR);
  304. dwErr = RegEnumValue(
  305. hkRead,
  306. i,
  307. rgwcGuid,
  308. &dwValueNameLen,
  309. NULL,
  310. &dwType,
  311. (PBYTE)(pTable[dwIndex].wszFriendlyName),
  312. &dwValueLen
  313. );
  314. if((dwErr == NO_ERROR) &&
  315. (dwType == REG_SZ)) {
  316. //
  317. // Convert the string to a guid
  318. //
  319. ASSERT(dwValueNameLen <= 38);
  320. usTempString.Length = (USHORT)(dwValueNameLen * sizeof(WCHAR));
  321. dwErr = RtlGUIDFromString(
  322. &usTempString,
  323. &(pTable[dwIndex].Guid)
  324. );
  325. if(dwErr == STATUS_SUCCESS) {
  326. dwIndex++;
  327. }
  328. }
  329. }
  330. } while(FALSE);
  331. if (dwIndex == 0) {
  332. Free0(pTable);
  333. } else {
  334. *lplpBuffer = (PBYTE)pTable;
  335. *lpdwEntriesRead = dwIndex;
  336. }
  337. if(hkWrite != NULL) {
  338. RegCloseKey(hkWrite);
  339. }
  340. RegCloseKey(hkRead);
  341. RegCloseKey(hkMachine);
  342. if(dwIndex == 0) {
  343. return dwErr ? dwErr : ERROR_CAN_NOT_COMPLETE;
  344. }
  345. return NO_ERROR;
  346. }
  347. DWORD
  348. APIENTRY
  349. MprSetupIpInIpInterfaceFriendlyNameFree(
  350. IN LPVOID lpBuffer
  351. )
  352. {
  353. if (!lpBuffer) { return ERROR_INVALID_PARAMETER; }
  354. Free(lpBuffer);
  355. return NO_ERROR;
  356. }
  357. DWORD
  358. APIENTRY
  359. MprSetupIpInIpInterfaceFriendlyNameCreate(
  360. PWCHAR pwszMachineName,
  361. PMPR_IPINIP_INTERFACE_0 pNameInformation
  362. )
  363. {
  364. DWORD dwErr, dwNumValues, dwMaxValueNameLen, dwMaxValueLen;
  365. DWORD dwType, dwValueLen;
  366. HKEY hkMachine=NULL, hkRead=NULL, hkWrite=NULL;
  367. WCHAR rgwcName[MAX_INTERFACE_NAME_LEN + 2];
  368. UNICODE_STRING usTempString;
  369. //
  370. // Connect to the registry
  371. //
  372. dwErr = RegConnectRegistry(
  373. pwszMachineName,
  374. HKEY_LOCAL_MACHINE,
  375. &hkMachine);
  376. if(dwErr != NO_ERROR) {
  377. return dwErr;
  378. }
  379. //
  380. // Just call the query function to open the key
  381. //
  382. dwErr = QueryIpInIpSoftwareKey(
  383. hkMachine,
  384. &hkRead,
  385. &hkWrite,
  386. &dwNumValues,
  387. &dwMaxValueNameLen,
  388. &dwMaxValueLen
  389. );
  390. RegCloseKey(hkMachine);
  391. if (dwErr != NO_ERROR) {
  392. return dwErr;
  393. }
  394. //
  395. // Dont need this
  396. //
  397. RegCloseKey(hkRead);
  398. if(hkWrite == NULL) {
  399. return ERROR_ACCESS_DENIED;
  400. }
  401. //
  402. // Convert guid to string
  403. //
  404. dwErr = RtlStringFromGUID(
  405. &(pNameInformation->Guid),
  406. &usTempString);
  407. if(dwErr != STATUS_SUCCESS) {
  408. RegCloseKey(hkWrite);
  409. return ERROR_INVALID_PARAMETER;
  410. }
  411. //
  412. // See if it exists
  413. //
  414. dwValueLen = sizeof(rgwcName);
  415. dwErr = RegQueryValueEx(
  416. hkWrite,
  417. usTempString.Buffer,
  418. NULL,
  419. &dwType,
  420. (PBYTE)rgwcName,
  421. &dwValueLen);
  422. if(dwErr == NO_ERROR) {
  423. //
  424. // hmm already exists
  425. //
  426. RegCloseKey(hkWrite);
  427. RtlFreeUnicodeString(&usTempString);
  428. return ERROR_OBJECT_ALREADY_EXISTS;
  429. }
  430. //
  431. // Set the value
  432. //
  433. dwErr = RegSetValueEx(
  434. hkWrite,
  435. usTempString.Buffer,
  436. 0,
  437. REG_SZ,
  438. (PBYTE)pNameInformation->wszFriendlyName,
  439. (wcslen(pNameInformation->wszFriendlyName) + 1) * sizeof(WCHAR));
  440. RegCloseKey(hkWrite);
  441. RtlFreeUnicodeString(&usTempString);
  442. return dwErr;
  443. }
  444. DWORD
  445. APIENTRY
  446. MprSetupIpInIpInterfaceFriendlyNameDelete(
  447. IN PWCHAR pwszMachineName,
  448. IN GUID *pGuid
  449. )
  450. {
  451. DWORD dwErr, dwNumValues, dwMaxValueNameLen, dwMaxValueLen;
  452. HKEY hkMachine=NULL, hkRead=NULL, hkWrite=NULL;
  453. UNICODE_STRING usTempString;
  454. //
  455. // Connect to the registry
  456. //
  457. dwErr = RegConnectRegistry(
  458. pwszMachineName,
  459. HKEY_LOCAL_MACHINE,
  460. &hkMachine);
  461. if(dwErr != NO_ERROR) {
  462. return dwErr;
  463. }
  464. //
  465. // Just call the query function to open the key
  466. //
  467. dwErr = QueryIpInIpSoftwareKey(
  468. hkMachine,
  469. &hkRead,
  470. &hkWrite,
  471. &dwNumValues,
  472. &dwMaxValueNameLen,
  473. &dwMaxValueLen
  474. );
  475. RegCloseKey(hkMachine);
  476. if (dwErr != NO_ERROR) {
  477. return dwErr;
  478. }
  479. //
  480. // Dont need this
  481. //
  482. RegCloseKey(hkRead);
  483. if(hkWrite == NULL) {
  484. return ERROR_ACCESS_DENIED;
  485. }
  486. //
  487. // Convert guid to string
  488. //
  489. dwErr = RtlStringFromGUID(
  490. pGuid,
  491. &usTempString);
  492. if(dwErr != STATUS_SUCCESS) {
  493. RegCloseKey(hkWrite);
  494. return ERROR_INVALID_PARAMETER;
  495. }
  496. //
  497. // See if it exists
  498. //
  499. dwErr = RegDeleteValue(
  500. hkWrite,
  501. usTempString.Buffer);
  502. RegCloseKey(hkWrite);
  503. RtlFreeUnicodeString(&usTempString);
  504. return dwErr;
  505. }
  506. //----------------------------------------------------------------------------
  507. // Function: QueryRmSoftwareKey
  508. //
  509. // Called to open the key for a router-manager given its transport ID.
  510. //----------------------------------------------------------------------------
  511. DWORD
  512. QueryRmSoftwareKey(
  513. IN HKEY hkeyMachine,
  514. IN DWORD dwTransportId,
  515. OUT HKEY* phkrm,
  516. OUT LPWSTR* lplpwsRm
  517. ) {
  518. HKEY hkey;
  519. DWORD dwErr;
  520. WCHAR wszKey[256], *pwsKey;
  521. //
  522. // Open the key HKLM\Software\Microsoft\Router\RouterManagers
  523. //
  524. wsprintf(
  525. wszKey, L"%s\\%s\\%s\\%s\\%s", c_szSoftware, c_szMicrosoft, c_szRouter,
  526. c_szCurrentVersion, c_szRouterManagers
  527. );
  528. dwErr = RegOpenKeyEx(hkeyMachine, wszKey, 0, KEY_READ, &hkey);
  529. if (dwErr != ERROR_SUCCESS) { return dwErr; }
  530. //
  531. // Enumerate the subkeys of the 'RouterManagers' key,
  532. // in search of one which as a 'ProtocolId' value equal to 'dwTransportId'.
  533. //
  534. do {
  535. //
  536. // Retrieve information about the subkeys of the key
  537. //
  538. DWORD dwKeyCount, dwMaxKeyLength;
  539. DWORD i, dwSize, dwType, dwProtocolId = ~dwTransportId;
  540. dwErr = RegQueryInfoKey(
  541. hkey, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLength,
  542. NULL, NULL, NULL, NULL, NULL, NULL
  543. );
  544. if (dwErr != ERROR_SUCCESS) { break; }
  545. //
  546. // Allocate enough space for the longest of the subkeys
  547. //
  548. pwsKey = Malloc((dwMaxKeyLength + 1) * sizeof(WCHAR));
  549. if (!pwsKey) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
  550. //
  551. // Enumerate the keys
  552. //
  553. for (i = 0; i < dwKeyCount; i++) {
  554. //
  555. // Get the name of the current key
  556. //
  557. dwSize = dwMaxKeyLength + 1;
  558. dwErr = RegEnumKeyEx(
  559. hkey, i, pwsKey, &dwSize, NULL, NULL, NULL, NULL
  560. );
  561. if (dwErr != ERROR_SUCCESS) { continue; }
  562. //
  563. // Open the key
  564. //
  565. dwErr = RegOpenKeyEx(hkey, pwsKey, 0, KEY_READ, phkrm);
  566. if (dwErr != ERROR_SUCCESS) { continue; }
  567. //
  568. // Try to read the ProtocolId value
  569. //
  570. dwSize = sizeof(dwProtocolId);
  571. dwErr = RegQueryValueEx(
  572. *phkrm, c_szProtocolId, 0, &dwType,
  573. (BYTE*)&dwProtocolId, &dwSize
  574. );
  575. //
  576. // Break if this is the transport we're looking for,
  577. // otherwise close the key and continue
  578. //
  579. if (dwErr == ERROR_SUCCESS &&
  580. dwProtocolId == dwTransportId) { break; }
  581. RegCloseKey(*phkrm);
  582. }
  583. if (i >= dwKeyCount) { Free(pwsKey); break; }
  584. //
  585. // The transport was found, so save its key-name
  586. //
  587. *lplpwsRm = pwsKey;
  588. } while(FALSE);
  589. RegCloseKey(hkey);
  590. return (*lplpwsRm ? NO_ERROR : ERROR_NO_MORE_ITEMS);
  591. }
  592. DWORD
  593. QueryIpInIpSoftwareKey(
  594. IN HKEY hkeyMachine,
  595. OUT HKEY* phkIpIpRead,
  596. OUT HKEY* phkIpIpWrite,
  597. OUT PDWORD pdwNumValues,
  598. OUT PDWORD pdwMaxValueNameLen,
  599. OUT PDWORD pdwMaxValueLen
  600. )
  601. {
  602. HKEY hkReg;
  603. DWORD dwErr, dwDisp;
  604. WCHAR wszKey[256], *pwsKey;
  605. DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueLen;
  606. *phkIpIpWrite = NULL;
  607. *phkIpIpRead = NULL;
  608. *pdwNumValues = 0;
  609. *pdwMaxValueLen = 0;
  610. *pdwMaxValueNameLen = 0;
  611. //
  612. // Open the key HKLM\Software\Microsoft\IpInIp
  613. //
  614. wsprintf(
  615. wszKey, L"%s\\%s\\%s", c_szSoftware, c_szMicrosoft, c_szIpInIp
  616. );
  617. //
  618. // First open/create a key for all access
  619. //
  620. dwErr = RegCreateKeyEx(
  621. hkeyMachine,
  622. wszKey,
  623. 0,
  624. NULL,
  625. 0,
  626. KEY_ALL_ACCESS,
  627. NULL,
  628. &hkReg,
  629. &dwDisp);
  630. if (dwErr == NO_ERROR) {
  631. *phkIpIpWrite = hkReg;
  632. } else {
  633. *phkIpIpWrite = NULL;
  634. }
  635. dwErr = RegOpenKeyEx(
  636. hkeyMachine,
  637. wszKey,
  638. 0,
  639. KEY_READ,
  640. &hkReg);
  641. if (dwErr != NO_ERROR) {
  642. ASSERT(*phkIpIpWrite == NULL);
  643. *phkIpIpRead = NULL;
  644. return dwErr;
  645. } else {
  646. *phkIpIpRead = hkReg;
  647. }
  648. //
  649. // Atleast the read key is opened, query the number of interfaces
  650. //
  651. dwErr = RegQueryInfoKey(
  652. *phkIpIpRead,
  653. NULL,
  654. NULL,
  655. NULL,
  656. NULL,
  657. NULL,
  658. NULL,
  659. &dwNumValues,
  660. &dwMaxValueNameLen,
  661. &dwMaxValueLen,
  662. NULL,
  663. NULL);
  664. if (dwErr != NO_ERROR) {
  665. if(*phkIpIpWrite != NULL) {
  666. RegCloseKey(*phkIpIpWrite);
  667. }
  668. RegCloseKey(*phkIpIpRead);
  669. return dwErr;
  670. }
  671. *pdwNumValues = dwNumValues;
  672. *pdwMaxValueLen = dwMaxValueLen;
  673. *pdwMaxValueNameLen = dwMaxValueNameLen;
  674. return NO_ERROR;
  675. }