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.

1807 lines
46 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: T C P U T I L . C P P
  7. //
  8. // Contents: Utility functions used by tcpipcfg
  9. //
  10. // Notes:
  11. //
  12. // Author: tongl
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <ncxbase.h>
  18. #include <dsrole.h>
  19. #include "ncatlui.h"
  20. #include <time.h>
  21. #include "ncreg.h"
  22. #include "ncstl.h"
  23. #include "ncui.h"
  24. #include "tcpconst.h"
  25. #include "tcputil.h"
  26. #include "resource.h"
  27. #include "tcpmacro.h"
  28. #include "atmcommon.h"
  29. #define MAX_NUM_DIGIT_MULTI_INTERFACES 10
  30. extern const WCHAR c_szNetCfgHelpFile[];
  31. // HrLoadSubkeysFromRegistry
  32. // Gets the list of subkeys under a registry key
  33. // hkey the root registry key
  34. // pvstrAdapters returns the list of subkeykey names from hkey
  35. HRESULT HrLoadSubkeysFromRegistry(const HKEY hkey,
  36. OUT VSTR * const pvstrSubkeys)
  37. {
  38. HRESULT hr = S_OK;
  39. Assert(pvstrSubkeys);
  40. // Initialize output parameter
  41. FreeCollectionAndItem(*pvstrSubkeys);
  42. WCHAR szBuf[256];
  43. FILETIME time;
  44. DWORD dwSize = celems(szBuf);
  45. DWORD dwRegIndex = 0;
  46. while(SUCCEEDED(hr = HrRegEnumKeyEx(hkey, dwRegIndex++, szBuf,
  47. &dwSize, NULL, NULL, &time)))
  48. {
  49. dwSize = celems(szBuf);
  50. Assert(szBuf);
  51. pvstrSubkeys->push_back(new tstring(szBuf));
  52. }
  53. if(hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
  54. hr = S_OK;
  55. TraceError("HrLoadSubkeysFromRegistry", hr);
  56. return hr;
  57. }
  58. //
  59. //HrIsComponentInstalled Given a Component ID, determins if the component
  60. // is installed in the system
  61. // Note: The net class of the component must be
  62. //
  63. //pnc the system's INetCfg
  64. //rguidClass the Net Class of this component we are earching for
  65. //pszInfId the Component ID
  66. //pfInstalled returns a flag to determine if the component is installed
  67. //
  68. // Returns S_OK if succeed ( whether component found or not
  69. // Other: ERROR
  70. HRESULT HrIsComponentInstalled(INetCfg * pnc,
  71. const GUID& rguidClass,
  72. PCWSTR pszInfId,
  73. OUT BOOL * const pfInstalled)
  74. {
  75. Assert(pnc);
  76. Assert(pszInfId);
  77. Assert(pfInstalled);
  78. *pfInstalled = FALSE;
  79. INetCfgComponent * pncc;
  80. HRESULT hr = pnc->FindComponent(pszInfId, &pncc);
  81. if(hr == S_OK)
  82. {
  83. Assert(pncc);
  84. *pfInstalled = TRUE;
  85. }
  86. else if(hr == S_FALSE)
  87. {
  88. Assert(!pncc);
  89. *pfInstalled = FALSE;
  90. hr = S_OK;
  91. }
  92. ReleaseObj(pncc);
  93. TraceError("HrIsComponentInstalled", hr);
  94. return hr;
  95. }
  96. //
  97. // GetNodeNum
  98. //
  99. // Get an IP Address and return the 4 numbers in the IP address.
  100. //
  101. // pszIpAddress: IP Address
  102. // ardw[4]: The 4 numbers in the IP Address
  103. VOID GetNodeNum(PCWSTR pszIpAddress, DWORD ardw[4])
  104. {
  105. VSTR vstr;
  106. tstring strIpAddress(pszIpAddress);
  107. ConvertStringToColString(strIpAddress.c_str(),
  108. CH_DOT,
  109. vstr);
  110. VSTR_ITER iter = vstr.begin();
  111. // Go through each field and get the number value
  112. ardw[0] = 0;
  113. ardw[1] = 0;
  114. ardw[2] = 0;
  115. ardw[3] = 0;
  116. if(iter != vstr.end())
  117. {
  118. ardw[0] = _ttol((*iter++)->c_str());
  119. if(iter != vstr.end())
  120. {
  121. ardw[1] = _ttol((*iter++)->c_str());
  122. if(iter != vstr.end())
  123. {
  124. ardw[2] = _ttol((*iter++)->c_str());
  125. if(iter != vstr.end())
  126. {
  127. ardw[3] = _ttol((*iter++)->c_str());
  128. }
  129. }
  130. }
  131. }
  132. FreeCollectionAndItem(vstr);
  133. }
  134. //Check if the subnet mask is contiguous
  135. //Return: TRUE contiguous
  136. // FALSE uncontigous
  137. BOOL IsContiguousSubnet(PCWSTR pszSubnet)
  138. {
  139. DWORD ardwSubnet[4];
  140. GetNodeNum(pszSubnet, ardwSubnet);
  141. DWORD dwMask = (ardwSubnet[0] << 24) + (ardwSubnet[1] << 16)
  142. + (ardwSubnet[2] << 8) + ardwSubnet[3];
  143. DWORD i, dwContiguousMask;
  144. // Find out where the first '1' is in binary going right to left
  145. dwContiguousMask = 0;
  146. for (i = 0; i < sizeof(dwMask)*8; i++)
  147. {
  148. dwContiguousMask |= 1 << i;
  149. if (dwContiguousMask & dwMask)
  150. break;
  151. }
  152. // At this point, dwContiguousMask is 000...0111... If we inverse it,
  153. // we get a mask that can be or'd with dwMask to fill in all of
  154. // the holes.
  155. dwContiguousMask = dwMask | ~dwContiguousMask;
  156. // If the new mask is different, correct it here
  157. if (dwMask != dwContiguousMask)
  158. return FALSE;
  159. else
  160. return TRUE;
  161. }
  162. // Replace first element of a vector of tstrings
  163. VOID ReplaceFirstAddress(VSTR * pvstr, PCWSTR pszIpAddress)
  164. {
  165. Assert(pszIpAddress);
  166. if(pvstr->empty())
  167. {
  168. pvstr->push_back(new tstring(pszIpAddress));
  169. }
  170. else
  171. {
  172. *(*pvstr)[0] = pszIpAddress;
  173. }
  174. }
  175. // Replace second element of a vector of tstrings
  176. VOID ReplaceSecondAddress(VSTR * pvstr, PCWSTR pszIpAddress)
  177. {
  178. Assert(pszIpAddress);
  179. if (pvstr->size()<2)
  180. {
  181. pvstr->push_back(new tstring(pszIpAddress));
  182. }
  183. else
  184. {
  185. *(*pvstr)[1] = pszIpAddress;
  186. }
  187. }
  188. // Generate subnetmask for an IP address
  189. BOOL GenerateSubnetMask(IpControl & ipAddress,
  190. tstring * pstrSubnetMask)
  191. {
  192. BOOL bResult = TRUE;
  193. if (!ipAddress.IsBlank())
  194. {
  195. tstring strAddress;
  196. DWORD adwIpAddress[4];
  197. ipAddress.GetAddress(&strAddress);
  198. GetNodeNum(strAddress.c_str(), adwIpAddress);
  199. DWORD nValue = adwIpAddress[0];
  200. if(nValue <= SUBNET_RANGE_1_MAX)
  201. {
  202. *pstrSubnetMask = c_szBASE_SUBNET_MASK_1;
  203. }
  204. else if( nValue <= SUBNET_RANGE_2_MAX)
  205. {
  206. *pstrSubnetMask = c_szBASE_SUBNET_MASK_2;
  207. }
  208. else if( nValue <= SUBNET_RANGE_3_MAX)
  209. {
  210. *pstrSubnetMask = c_szBASE_SUBNET_MASK_3;
  211. }
  212. else
  213. {
  214. Assert(FALSE);
  215. bResult = FALSE;
  216. }
  217. }
  218. else
  219. {
  220. bResult = FALSE;
  221. }
  222. return bResult;
  223. }
  224. // BOOL fIsSameVstr
  225. // Return TRUE is all strings in a vstr are the same and in same order
  226. BOOL fIsSameVstr(const VSTR vstr1, const VSTR vstr2)
  227. {
  228. int iCount1 = vstr1.size();
  229. int iCount2 = vstr2.size();
  230. int idx =0;
  231. if (iCount1 != iCount2)
  232. {
  233. return FALSE;
  234. }
  235. else // same size
  236. {
  237. // For each string in both vstr1 and vstr2
  238. for (idx=0; idx<iCount1; idx++)
  239. {
  240. // if mismatch found
  241. if((*vstr1[idx] != *vstr2[idx]))
  242. {
  243. return FALSE;
  244. }
  245. }
  246. }
  247. Assert((iCount1==iCount2) && (iCount1==idx));
  248. return TRUE;
  249. }
  250. // Registry access help functions for Boolean type
  251. // FRegQueryBool
  252. // hkey the regisry key
  253. // pszName the value in the registry key
  254. // fValue the default vaule
  255. //
  256. // NOTE: If the function failed to read the value from the registry, it will return
  257. // the default value.
  258. BOOL FRegQueryBool(const HKEY hkey, PCWSTR pszName, BOOL fDefaultValue)
  259. {
  260. BOOL fRetValue = fDefaultValue;
  261. DWORD dwValue;
  262. HRESULT hr = HrRegQueryDword(hkey, pszName, &dwValue);
  263. if (S_OK == hr)
  264. {
  265. fRetValue = !!dwValue;
  266. }
  267. #ifdef ENABLETRACE
  268. else
  269. {
  270. const HRESULT hrNoRegValue = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  271. if (hr == hrNoRegValue)
  272. {
  273. TraceTag(ttidTcpip, "FRegQueryBool: registry key %S not found", pszName);
  274. hr = S_OK;
  275. }
  276. }
  277. #endif
  278. TraceError("FRegQueryBool", hr);
  279. return fRetValue;
  280. }
  281. // ResetLmhostsFile
  282. // Called by Cancel and Cancelproperties to roll back changes to the file lmhosts
  283. VOID ResetLmhostsFile()
  284. {
  285. WCHAR szSysPath[MAX_PATH] = {0};
  286. WCHAR szSysPathBackup[MAX_PATH];
  287. BOOL fSysPathFound = (GetSystemDirectory(szSysPath, MAX_PATH) != 0);
  288. lstrcpyW(szSysPathBackup, szSysPath);
  289. wcscat(szSysPath, RGAS_LMHOSTS_PATH);
  290. wcscat(szSysPathBackup, RGAS_LMHOSTS_PATH_BACKUP);
  291. WIN32_FIND_DATA FileData;
  292. if (FindFirstFile(szSysPathBackup, &FileData) == INVALID_HANDLE_VALUE)
  293. {
  294. AssertSz(FALSE, "lmhosts.bak file not found");
  295. }
  296. else
  297. {
  298. BOOL ret;
  299. // Rename lmhosts.bak file to lmhosts
  300. ret = MoveFileEx(szSysPathBackup, szSysPath, MOVEFILE_REPLACE_EXISTING);
  301. AssertSz(ret, "Failed to restore lmhosts file!");
  302. }
  303. }
  304. //
  305. // IPAlertPrintf() - Does a printf to a message box for IP address
  306. //
  307. // ids: message string, IDS_IPBAD_FIELD_VALUE
  308. // iCurrent: value of the field
  309. // iLow: Low range of the field
  310. // iHigh: High range of the field
  311. //
  312. int IPAlertPrintf(HWND hwndParent, UINT ids,
  313. int iCurrent, int iLow, int iHigh)
  314. {
  315. if (ids != IDS_IPNOMEM)
  316. {
  317. WCHAR szCurrent[3];
  318. wsprintfW(szCurrent, c_szItoa, iCurrent);
  319. WCHAR szLow[3];
  320. wsprintfW(szLow, c_szItoa, iLow);
  321. WCHAR szHigh[3];
  322. wsprintfW(szHigh, c_szItoa, iHigh);
  323. return NcMsgBox(hwndParent,
  324. IDS_IPMBCAPTION,
  325. ids,
  326. MB_ICONEXCLAMATION,
  327. szCurrent, szLow, szHigh);
  328. }
  329. else
  330. return NcMsgBox(hwndParent,
  331. IDS_IPMBCAPTION,
  332. ids,
  333. MB_ICONEXCLAMATION);
  334. }
  335. // IpRangeError
  336. //
  337. VOID IpCheckRange(LPNMIPADDRESS lpnmipa, HWND hWnd, int iLow, int iHigh, BOOL fCheckLoopback)
  338. {
  339. /*
  340. // This is a workaround because the IP control will send this notification
  341. // twice if I don't set the out of range value in this code. However there
  342. // is no way to set the value of an individual field. Send request to strohma.
  343. static BOOL fNotified = FALSE;
  344. static int iNotifiedValue = 0;
  345. if ((lpnmipa->iValue != c_iEmptyIpField) &&
  346. ((lpnmipa->iValue<iLow) || (lpnmipa->iValue>iHigh)))
  347. {
  348. if (!fNotified) // If we havn't been notified yet
  349. {
  350. fNotified = TRUE;
  351. iNotifiedValue = lpnmipa->iValue;
  352. IPAlertPrintf(hWnd, IDS_IPBAD_FIELD_VALUE,
  353. lpnmipa->iValue, iLow, iHigh);
  354. }
  355. else // ignor the second notify
  356. {
  357. // Make sure we are alerted of change in the workaround from common control
  358. AssertSz(iNotifiedValue == lpnmipa->iValue, "Common control behaviour changed!!");
  359. fNotified = FALSE;
  360. iNotifiedValue =0;
  361. }
  362. };
  363. */
  364. /*
  365. // This is a workaround because the IP control will send this notification
  366. // twice if I don't set the out of range value in this code. However there
  367. // is no way to set the value of an individual field. Send request to strohma.
  368. if ((lpnmipa->iValue != c_iEmptyIpField) &&
  369. ((lpnmipa->iValue<iLow) || (lpnmipa->iValue>iHigh)))
  370. {
  371. IPAlertPrintf(hWnd, IDS_IPBAD_FIELD_VALUE,
  372. lpnmipa->iValue, iLow, iHigh);
  373. if (lpnmipa->iValue<iLow)
  374. lpnmipa->iValue = iLow;
  375. else
  376. lpnmipa->iValue = iHigh;
  377. };
  378. */
  379. //$REVIEW (nsun) BUG171839 this is a workaround because the IP control will send this notifcation
  380. // twice when I put a 3 digit value. I added a static value to make sure every error message
  381. // is brought up only once
  382. // The static values that should be able to uniquely identify a notification
  383. static UINT idIpControl = 0;
  384. static int iField = 0;
  385. static int iValue = 0;
  386. //we know the notification may be sent twice
  387. //We only want to the second duplcate notifiction
  388. //If we receive the third notification with the same control, field and value, it should
  389. //be real notification and we shouldn't ignore it.
  390. static UINT cRejectTimes = 0;
  391. if(idIpControl != lpnmipa->hdr.idFrom ||
  392. iField != lpnmipa->iField || iValue != lpnmipa->iValue || cRejectTimes > 0)
  393. {
  394. //update the static values
  395. //(nsun) We have to update the static values before the error
  396. // message box because there will be IPN_FIELDCHANGED notification
  397. // sent out when the message box is brought up.
  398. cRejectTimes = 0;
  399. idIpControl = lpnmipa->hdr.idFrom;
  400. iField = lpnmipa->iField;
  401. iValue = lpnmipa->iValue;
  402. if ((lpnmipa->iValue != c_iEmptyIpField) &&
  403. ((lpnmipa->iValue<iLow) || (lpnmipa->iValue>iHigh)))
  404. {
  405. IPAlertPrintf(hWnd, IDS_IPBAD_FIELD_VALUE,
  406. lpnmipa->iValue, iLow, iHigh);
  407. }
  408. if (fCheckLoopback && lpnmipa->iValue == c_iIPADDR_FIELD_1_LOOPBACK
  409. && 0 == lpnmipa->iField)
  410. {
  411. IPAlertPrintf(hWnd, IDS_INCORRECT_IP_LOOPBACK,
  412. lpnmipa->iValue, iLow, iHigh);
  413. lpnmipa->iValue = iLow;
  414. }
  415. }
  416. else
  417. {
  418. cRejectTimes++;
  419. }
  420. }
  421. //+---------------------------------------------------------------------------
  422. //
  423. // Name: SetButtons
  424. //
  425. // Purpose: Enables/disables push buttons based on item count and current selection
  426. // in the list.
  427. // Used by DNS and ATM ARPC pages that have group of HANDLES
  428. //
  429. // Arguments:
  430. // h [in] The group of handles
  431. // nNumLimit [in] Limit of number of elements allowed in the list
  432. //
  433. // Returns: Nothing
  434. //
  435. // Author: tongl 9 July 1997
  436. //
  437. // Notes:
  438. //
  439. VOID SetButtons(HANDLES& h, const int nNumLimit)
  440. {
  441. Assert(IsWindow(h.m_hList));
  442. Assert(IsWindow(h.m_hAdd));
  443. Assert(IsWindow(h.m_hEdit));
  444. Assert(IsWindow(h.m_hRemove));
  445. // $REVIEW(tongl):macro problem
  446. int nCount = Tcp_ListBox_GetCount(h.m_hList);
  447. // If there are currently no item in list, set focus to "Add" button
  448. if (!nCount)
  449. {
  450. // remove the default on the remove button, if any
  451. SendMessage(h.m_hRemove, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
  452. // move focus to Add button
  453. ::SetFocus(h.m_hAdd);
  454. }
  455. // If number of items less than limit, enable "Add" button
  456. // Otherwise disable it
  457. if (nCount != nNumLimit)
  458. ::EnableWindow(h.m_hAdd, TRUE);
  459. else
  460. {
  461. //disable the button and move focus only if the add button is currently enabled
  462. if (::IsWindowEnabled(h.m_hAdd))
  463. {
  464. // disable "Add button"
  465. ::EnableWindow(h.m_hAdd, FALSE);
  466. // remove the default on the add button, if any
  467. SendMessage(h.m_hAdd, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
  468. // move focus to edit button
  469. ::SetFocus(h.m_hEdit);
  470. }
  471. }
  472. // If number of items >0, enable "Edit" and "Remove" buttons
  473. // Otherwise disable them
  474. ::EnableWindow(h.m_hEdit, nCount);
  475. ::EnableWindow(h.m_hRemove, nCount);
  476. // Enable/disable the "Up" and "Down" buttons
  477. // determine Up and Down logic
  478. if (nCount > 1)
  479. {
  480. int idxCurSel = Tcp_ListBox_GetCurSel(h.m_hList);
  481. Assert(idxCurSel != CB_ERR );
  482. BOOL fChangeFocus = FALSE;
  483. if (idxCurSel == 0)
  484. {
  485. if (h.m_hUp == ::GetFocus())
  486. fChangeFocus = TRUE;
  487. ::EnableWindow(h.m_hUp, FALSE);
  488. ::EnableWindow(h.m_hDown, TRUE);
  489. // remove the default on the up button, if any
  490. SendMessage(h.m_hUp, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
  491. if (fChangeFocus)
  492. ::SetFocus(h.m_hDown);
  493. }
  494. else if (idxCurSel == (nCount-1))
  495. {
  496. if (h.m_hDown == ::GetFocus())
  497. fChangeFocus = TRUE;
  498. ::EnableWindow(h.m_hUp, TRUE);
  499. ::EnableWindow(h.m_hDown, FALSE);
  500. // remove the default on the down button, if any
  501. SendMessage(h.m_hDown, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
  502. if (fChangeFocus)
  503. ::SetFocus(h.m_hUp);
  504. }
  505. else
  506. {
  507. ::EnableWindow(h.m_hUp, TRUE);
  508. ::EnableWindow(h.m_hDown, TRUE);
  509. }
  510. }
  511. else
  512. {
  513. ::EnableWindow(h.m_hUp, FALSE);
  514. ::EnableWindow(h.m_hDown, FALSE);
  515. }
  516. }
  517. //+---------------------------------------------------------------------------
  518. //
  519. // Name: ListBoxRemoveAt
  520. //
  521. // Purpose: Remove an item from a list box and save it to a tstring
  522. // Used by DNS and ATM ARPC pages.
  523. //
  524. // Arguments:
  525. // hListBox [in] Handle to the list box
  526. // idx [in] Index of the item to remove
  527. // pstrRemovedItem [out] The content of the removed item
  528. //
  529. // Returns: TRUE if succeeded, else FALSE
  530. //
  531. // Author: tongl 9 July 1997
  532. //
  533. // Notes:
  534. //
  535. BOOL ListBoxRemoveAt(HWND hListBox, int idx, tstring * pstrRemovedItem)
  536. {
  537. BOOL bResult = FALSE;
  538. Assert(idx >=0);
  539. Assert(hListBox);
  540. WCHAR buf[MAX_PATH];
  541. int len;
  542. if((len = Tcp_ListBox_GetTextLen(hListBox, idx)) >= celems(buf))
  543. {
  544. Assert(FALSE);
  545. return FALSE;
  546. }
  547. Assert(len != 0);
  548. Tcp_ListBox_GetText(hListBox, idx, buf);
  549. *pstrRemovedItem = buf;
  550. if (len != 0)
  551. {
  552. if (::SendMessage(hListBox,
  553. LB_DELETESTRING,
  554. (WPARAM)(int)(idx), 0L) != LB_ERR)
  555. bResult = TRUE;
  556. }
  557. return bResult;
  558. }
  559. //+---------------------------------------------------------------------------
  560. //
  561. // Name: ListBoxInsertAfter
  562. //
  563. // Purpose: Insert an item into a list box
  564. // Used by DNS and ATM ARPC pages
  565. //
  566. // Arguments:
  567. // hListBox [in] Handle to the list box
  568. // idx [in] Index of the item to insert after
  569. // pszItem [out] The item to insert
  570. //
  571. // Returns: TRUE if succeeded, else FALSE
  572. //
  573. // Author: tongl 9 July 1997
  574. //
  575. // Notes:
  576. //
  577. BOOL ListBoxInsertAfter(HWND hListBox, int idx, PCWSTR pszItem)
  578. {
  579. #ifdef DBG
  580. Assert(hListBox);
  581. // validate the range
  582. int nCount = Tcp_ListBox_GetCount(hListBox);
  583. Assert(idx >=0);
  584. Assert(idx <= nCount);
  585. // insist there is a string
  586. Assert(pszItem);
  587. #endif
  588. return (Tcp_ListBox_InsertString(hListBox, idx, pszItem) == idx);
  589. }
  590. //+---------------------------------------------------------------------------
  591. //
  592. // Name: HrRegRenameTree
  593. //
  594. // Purpose: Rename a registr subkey
  595. //
  596. // Arguments:
  597. // hkeyRoot [in] The root key where the subkey to be renamed exists
  598. // pszOldName [in] The existing name of the sub key
  599. // pszNewName [in] The new name of the sub key
  600. //
  601. // Returns: S_OK if succeeded,
  602. // E_FAIL otherwise
  603. //
  604. // Author: tongl 7 Aug 1997
  605. //
  606. // Notes:
  607. //
  608. HRESULT HrRegRenameTree(HKEY hkeyRoot, PCWSTR pszOldName, PCWSTR pszNewName)
  609. {
  610. HRESULT hr = S_OK;
  611. HKEY hkeyNew = NULL;
  612. HKEY hkeyOld = NULL;
  613. DWORD dwDisposition;
  614. //$REVIEW (nsun) make sure we don't rename the same tree
  615. if(0 == lstrcmpiW (pszOldName, pszNewName))
  616. return S_OK;
  617. // Create new subkey
  618. hr = HrRegCreateKeyEx(hkeyRoot,
  619. pszNewName,
  620. REG_OPTION_NON_VOLATILE,
  621. KEY_READ_WRITE,
  622. NULL,
  623. &hkeyNew,
  624. &dwDisposition);
  625. if (S_OK == hr)
  626. {
  627. // Copy all items under old subkey to new subkey
  628. hr = HrRegOpenKeyEx(hkeyRoot,
  629. pszOldName,
  630. KEY_READ_WRITE_DELETE,
  631. &hkeyOld);
  632. if (S_OK == hr)
  633. {
  634. hr = HrRegCopyKeyTree(hkeyNew, hkeyOld);
  635. RegSafeCloseKey(hkeyOld);
  636. if (S_OK == hr)
  637. {
  638. // Delete old subkey
  639. hr = HrRegDeleteKeyTree(hkeyRoot, pszOldName);
  640. }
  641. }
  642. }
  643. RegSafeCloseKey(hkeyNew);
  644. TraceTag(ttidTcpip, "HrRegRenameTree failed to rename %S to %S", pszOldName, pszNewName);
  645. TraceError("Tcpipcfg: HrRegRenameTree failed", hr);
  646. return hr;
  647. }
  648. //+---------------------------------------------------------------------------
  649. //
  650. // Name: HrRegCopyKeyTree
  651. //
  652. // Purpose: Copies a registry subtree to a new location
  653. //
  654. // Arguments:
  655. // hkeyDest [in] The subkey to copy to
  656. // hkeySrc [in] The subkey to copy from
  657. //
  658. // Returns: S_OK if succeeded,
  659. // E_FAIL otherwise
  660. //
  661. // Author: tongl 7 Aug 1997
  662. //
  663. // Notes: Modified from NetSetupRegCopyTree in ncpa1.1\netcfg\setup.cpp
  664. //
  665. HRESULT HrRegCopyKeyTree(HKEY hkeyDest, HKEY hkeySrc )
  666. {
  667. HRESULT hr = S_OK;
  668. FILETIME ftLastWrite;
  669. DWORD cchMaxSubKeyLen;
  670. DWORD cchMaxClassLen;
  671. DWORD cchMaxValueNameLen;
  672. DWORD cbMaxValueLen;
  673. DWORD iItem;
  674. PWSTR pszName;
  675. PWSTR pszClass;
  676. PBYTE pbData;
  677. DWORD cchName;
  678. DWORD cchClass;
  679. DWORD cbData;
  680. HKEY hkeyChildDest = NULL;
  681. HKEY hkeyChildSrc = NULL;
  682. DWORD dwDisposition;
  683. // Find out the longest name and data field and create the buffers
  684. // to store enumerations in
  685. //
  686. LONG lrt;
  687. lrt = RegQueryInfoKeyW( hkeySrc,
  688. NULL,
  689. NULL,
  690. NULL,
  691. NULL,
  692. &cchMaxSubKeyLen,
  693. &cchMaxClassLen,
  694. NULL,
  695. &cchMaxValueNameLen,
  696. &cbMaxValueLen,
  697. NULL,
  698. &ftLastWrite );
  699. do
  700. {
  701. if (ERROR_SUCCESS != lrt)
  702. {
  703. hr = HrFromLastWin32Error();
  704. break;
  705. }
  706. // use only one buffer for all names, values or keys
  707. cchMaxValueNameLen = max( cchMaxSubKeyLen, cchMaxValueNameLen );
  708. // allocate buffers
  709. hr = E_OUTOFMEMORY;
  710. pszName = new WCHAR[cchMaxValueNameLen + 1];
  711. if (NULL == pszName)
  712. {
  713. break;
  714. }
  715. pszClass = new WCHAR[cchMaxClassLen + 1];
  716. if (NULL == pszClass)
  717. {
  718. delete [] pszName;
  719. break;
  720. }
  721. pbData = new BYTE[ cbMaxValueLen ];
  722. if (NULL == pbData)
  723. {
  724. delete [] pszName;
  725. delete [] pszClass;
  726. break;
  727. }
  728. hr = S_OK;
  729. // enum all sub keys and copy them
  730. //
  731. iItem = 0;
  732. do
  733. {
  734. cchName = cchMaxValueNameLen + 1;
  735. cchClass = cchMaxClassLen + 1;
  736. // Enumerate the subkeys
  737. hr = HrRegEnumKeyEx(hkeySrc,
  738. iItem,
  739. pszName,
  740. &cchName,
  741. pszClass,
  742. &cchClass,
  743. &ftLastWrite );
  744. iItem++;
  745. if (SUCCEEDED(hr))
  746. {
  747. // create key at destination
  748. // Note: (tongl 8/7/97): Netcfg common code sets class to NULL ??
  749. hr = HrRegCreateKeyEx( hkeyDest,
  750. pszName,
  751. REG_OPTION_NON_VOLATILE,
  752. KEY_READ_WRITE,
  753. NULL,
  754. &hkeyChildDest,
  755. &dwDisposition );
  756. if (S_OK != hr)
  757. {
  758. break;
  759. }
  760. // open the key at source
  761. hr = HrRegOpenKeyEx(hkeySrc,
  762. pszName,
  763. KEY_READ_WRITE,
  764. &hkeyChildSrc );
  765. if (S_OK != hr)
  766. {
  767. RegSafeCloseKey(hkeyChildDest);
  768. break;
  769. }
  770. // copy this sub-tree
  771. hr = HrRegCopyKeyTree(hkeyChildDest, hkeyChildSrc);
  772. RegSafeCloseKey(hkeyChildDest);
  773. RegSafeCloseKey(hkeyChildSrc);
  774. }
  775. } while (S_OK == hr);
  776. // We are done with the subkeys, now onto copying values
  777. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  778. {
  779. // enum completed, no errors
  780. //
  781. DWORD dwType;
  782. // enum all values and copy them
  783. //
  784. iItem = 0;
  785. do
  786. {
  787. cchName = cchMaxValueNameLen + 1;
  788. cbData = cbMaxValueLen;
  789. hr = HrRegEnumValue(hkeySrc,
  790. iItem,
  791. pszName,
  792. &cchName,
  793. &dwType,
  794. pbData,
  795. &cbData );
  796. iItem++;
  797. if (S_OK == hr)
  798. {
  799. // write the value to the destination
  800. hr = HrRegSetValueEx(hkeyDest,
  801. pszName,
  802. dwType,
  803. pbData,
  804. cbData );
  805. }
  806. } while (S_OK == hr);
  807. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  808. {
  809. // if we hit the end of the enum without error
  810. // reset error code to success
  811. //
  812. hr = S_OK;
  813. }
  814. }
  815. // free our buffers
  816. delete [] pszName;
  817. delete [] pszClass;
  818. delete [] pbData;
  819. } while ( FALSE );
  820. TraceError("HrRegCopyKeyTree failed.", hr);
  821. return( hr );
  822. }
  823. //+---------------------------------------------------------------------------
  824. //
  825. // Name: fQueryFirstAddress
  826. //
  827. // Purpose: Retrieves the first string in a vector of strings
  828. //
  829. // Arguments:
  830. // vstr [in] The vector of strings
  831. // pstr [in] The first string
  832. //
  833. // Returns: TRUE if succeeded,
  834. // FALSE otherwise
  835. //
  836. // Author: tongl 10 Nov 1997
  837. //
  838. // Notes: Modified from NetSetupRegCopyTree in ncpa1.1\netcfg\setup.cpp
  839. //
  840. BOOL fQueryFirstAddress(const VSTR & vstr, tstring * const pstr)
  841. {
  842. if(vstr.empty())
  843. {
  844. *pstr = L"";
  845. return FALSE;
  846. }
  847. else
  848. {
  849. *pstr = *vstr[0];
  850. return TRUE;
  851. }
  852. }
  853. //+---------------------------------------------------------------------------
  854. //
  855. // Name: fQuerySecondAddress
  856. //
  857. // Purpose: Retrieves the first string in a vector of strings
  858. //
  859. // Arguments:
  860. // vstr [in] The vector of strings
  861. // pstr [in] The second string
  862. //
  863. // Returns: TRUE if succeeded,
  864. // FALSE otherwise
  865. //
  866. // Author: tongl 10 Nov 1997
  867. //
  868. // Notes: Modified from NetSetupRegCopyTree in ncpa1.1\netcfg\setup.cpp
  869. //
  870. BOOL fQuerySecondAddress(const VSTR & vstr, tstring * const pstr)
  871. {
  872. if(vstr.size()<2)
  873. {
  874. *pstr = L"";
  875. return FALSE;
  876. }
  877. else
  878. {
  879. *pstr = *vstr[1];
  880. return TRUE;
  881. }
  882. }
  883. // Function that decides whether a string is a valid ATM address
  884. // Return TRUE if Valid, return FALSE and the index of the first
  885. // invalid character if invalid.
  886. BOOL FIsValidAtmAddress(PCWSTR pszAtmAddress,
  887. INT * piErrCharPos,
  888. INT * pnId)
  889. {
  890. const WCHAR * pch;
  891. *piErrCharPos =0;
  892. *pnId =0;
  893. // 1. Validate characters must be '+' (first character),
  894. // '.', or hex digits '0'~'F'
  895. for (pch=pszAtmAddress; *pch; pch++)
  896. {
  897. if (!(((*pch == L'+') && (pch == pszAtmAddress))||
  898. (*pch == L'.')||
  899. (((*pch >= L'0') && (*pch <= L'9'))||
  900. ((*pch >= L'A') && (*pch <= L'F'))||
  901. ((*pch >= L'a') && (*pch <= L'f')))))
  902. {
  903. *piErrCharPos = pch - pszAtmAddress;
  904. *pnId = IDS_ATM_INVALID_CHAR;
  905. return FALSE;
  906. }
  907. if (*pch == L'.')
  908. {
  909. // '.' is for punctuation, so it should not be at the beginning,
  910. // end or have two in a row
  911. if ((pch == pszAtmAddress) ||
  912. (pch == pszAtmAddress+lstrlenW(pszAtmAddress)-1) ||
  913. (*pch == *(pch+1)))
  914. {
  915. *piErrCharPos = pch-pszAtmAddress;
  916. *pnId = IDS_ATM_INVALID_CHAR;
  917. return FALSE;
  918. }
  919. }
  920. }
  921. // 2. Strip off all punctuation characters ('.' characters)
  922. PWSTR pszBuff = new WCHAR[lstrlenW(pszAtmAddress)+1];
  923. if (NULL == pszBuff)
  924. return TRUE;
  925. PWSTR pchBuff = pszBuff;
  926. pch = pszAtmAddress;
  927. for (pch = pszAtmAddress; *pch; pch++)
  928. {
  929. if (*pch != L'.')
  930. {
  931. *pchBuff = *pch;
  932. pchBuff++;
  933. }
  934. }
  935. *pchBuff = L'\0';
  936. // 3. Decide whether the address is E.164 or NSAP
  937. // and check syntax accordingly
  938. if ((lstrlenW(pszBuff) <= 15) ||
  939. ((*pszBuff == L'+') && (lstrlenW(pszBuff) <= 16)))
  940. {
  941. // The address is E.164;
  942. // Check if string is empty
  943. if (*pchBuff == L'+')
  944. {
  945. pchBuff++;
  946. if (lstrlenW(pchBuff) == 0) // empty string
  947. {
  948. *pnId = IDS_ATM_EMPTY_ADDRESS;
  949. delete pszBuff;
  950. return FALSE;
  951. }
  952. }
  953. // Check that all characters are in range '0' through '9'
  954. // i.e. (ASCII values)
  955. pch = pszAtmAddress;
  956. if (*pch == L'+')
  957. {
  958. pch++;
  959. }
  960. while (*pch)
  961. {
  962. if ((*pch != L'.') &&
  963. (!((*pch >= L'0') && (*pch <= L'9'))))
  964. {
  965. *piErrCharPos = pch-pszAtmAddress;
  966. *pnId = IDS_ATM_INVALID_CHAR;
  967. delete pszBuff;
  968. return FALSE;
  969. }
  970. pch++;
  971. }
  972. }
  973. else
  974. {
  975. // The address is NSAP;
  976. if (lstrlenW(pszBuff) != 40)
  977. {
  978. *pnId = IDS_ATM_INVALID_LENGTH;
  979. delete pszBuff;
  980. return FALSE;
  981. }
  982. }
  983. delete pszBuff;
  984. return TRUE;
  985. }
  986. BOOL FIsIpInRange(PCWSTR pszIp)
  987. {
  988. BOOL fReturn = TRUE;
  989. DWORD ardwIp[4];
  990. GetNodeNum(pszIp, ardwIp);
  991. if ((ardwIp[0] > c_iIPADDR_FIELD_1_HIGH) ||
  992. (ardwIp[0] < c_iIPADDR_FIELD_1_LOW))
  993. {
  994. fReturn = FALSE;
  995. }
  996. return fReturn;
  997. }
  998. VOID ShowContextHelp(HWND hDlg, UINT uCommand, const DWORD* pdwHelpIDs)
  999. {
  1000. if (pdwHelpIDs != NULL)
  1001. {
  1002. WinHelp(hDlg,
  1003. c_szNetCfgHelpFile,
  1004. uCommand,
  1005. (ULONG_PTR)pdwHelpIDs);
  1006. }
  1007. }
  1008. //+---------------------------------------------------------------------------
  1009. //
  1010. // Name: AddInterfacesToAdapterInfo
  1011. //
  1012. // Purpose: Add several interfaces IDs into the interface list
  1013. //
  1014. // Arguments:
  1015. // pAdapter [in] Adapter info to add interfaces to
  1016. // dwNumInterfaces [in] Number of interface IDs to be added
  1017. //
  1018. // Returns: None
  1019. //
  1020. // Author: nsun 22 August 1998
  1021. //
  1022. //
  1023. VOID AddInterfacesToAdapterInfo(
  1024. ADAPTER_INFO* pAdapter,
  1025. DWORD dwNumInterfaces)
  1026. {
  1027. DWORD i;
  1028. GUID guid;
  1029. for (i = 0; i < dwNumInterfaces; i++)
  1030. {
  1031. if (SUCCEEDED(CoCreateGuid(&guid)))
  1032. {
  1033. pAdapter->m_IfaceIds.push_back(guid);
  1034. }
  1035. }
  1036. }
  1037. //+---------------------------------------------------------------------------
  1038. //
  1039. // Name: GetGuidArrayFromIfaceColWithCoTaskMemAlloc
  1040. //
  1041. // Purpose: Get the data as a DWORD array from a DWORD list.
  1042. // The caller is responsible to free the array by
  1043. // calling CoTaskMemFree()
  1044. //
  1045. // Arguments:
  1046. // ldw [in] The DWORD list
  1047. // ppdw [out] Pointer to the array
  1048. // pcguid [out] The count of guids placed in the array.
  1049. //
  1050. // Returns: S_OK
  1051. // E_OUTOFMEMORY
  1052. //
  1053. // Author: nsun 22 August 1998
  1054. //
  1055. //
  1056. HRESULT GetGuidArrayFromIfaceColWithCoTaskMemAlloc(
  1057. const IFACECOL& Ifaces,
  1058. GUID** ppguid,
  1059. DWORD* pcguid)
  1060. {
  1061. Assert(pcguid);
  1062. // Initialize output parameters
  1063. //
  1064. if (ppguid)
  1065. {
  1066. *ppguid = NULL;
  1067. }
  1068. HRESULT hr = S_OK;
  1069. DWORD cguid = Ifaces.size();
  1070. if ((cguid > 0) && ppguid)
  1071. {
  1072. GUID* pguid = (GUID*)CoTaskMemAlloc(cguid * sizeof(GUID));
  1073. if (pguid)
  1074. {
  1075. *ppguid = pguid;
  1076. *pcguid = cguid;
  1077. IFACECOL::const_iterator iter;
  1078. for (iter = Ifaces.begin();
  1079. iter != Ifaces.end();
  1080. iter++)
  1081. {
  1082. *(pguid++) = *iter;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. hr = E_OUTOFMEMORY;
  1088. }
  1089. }
  1090. else
  1091. {
  1092. // Caller just wants the count.
  1093. //
  1094. *pcguid = 0;
  1095. }
  1096. TraceHr(ttidError, FAL, hr, FALSE, "GetGuidArrayFromIfaceColWithCoTaskMemAlloc");
  1097. return hr;
  1098. }
  1099. //+---------------------------------------------------------------------------
  1100. //
  1101. // Name: GetInterfaceName
  1102. //
  1103. // Purpose: Get the interface name as <Adapter name>_<interface ID>
  1104. // to support multiple interface for WAN adapters.
  1105. //
  1106. // Arguments:
  1107. // pszAdapterName [in] The adapter name
  1108. // guidIfaceId [in] The interface ID
  1109. // pstrIfaceName [out] The interface name
  1110. //
  1111. // Returns: None
  1112. //
  1113. // Author: nsun 12 Sept 1998
  1114. //
  1115. // Note: This function is also used to construct NetBt binding
  1116. // interface names from NetBt binding path
  1117. //
  1118. VOID GetInterfaceName(
  1119. PCWSTR pszAdapterName,
  1120. const GUID& guidIfaceId,
  1121. tstring* pstrIfaceName)
  1122. {
  1123. Assert(pszAdapterName);
  1124. Assert(pstrIfaceName);
  1125. WCHAR pszGuid [c_cchGuidWithTerm];
  1126. StringFromGUID2 (guidIfaceId, pszGuid, c_cchGuidWithTerm);
  1127. // pstrIfaceName->assign(pszAdapterName);
  1128. // pstrIfaceName->append(pszGuid);
  1129. pstrIfaceName->assign(pszGuid);
  1130. }
  1131. //+---------------------------------------------------------------------------
  1132. //
  1133. // Name: RetrieveStringFromOptionList
  1134. //
  1135. // Purpose: Retrieve a substring from the option list of REMOTE_IPINFO
  1136. //
  1137. //
  1138. // Arguments:
  1139. // pszOption [in] The string of option list
  1140. // szIdentifier [in] The identifier of the substring to retrieve
  1141. // str [out] The substring
  1142. //
  1143. // Returns: S_OK
  1144. // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
  1145. // E_INVALIDARG
  1146. //
  1147. // Author: nsun 01/11/99
  1148. //
  1149. //
  1150. HRESULT RetrieveStringFromOptionList(PCWSTR pszOption,
  1151. PCWSTR szIdentifier,
  1152. tstring & str)
  1153. {
  1154. Assert(szIdentifier);
  1155. HRESULT hr = S_OK;
  1156. WCHAR* pszBegin;
  1157. WCHAR* pszEnd;
  1158. PWSTR pszString = NULL;
  1159. str = c_szEmpty;
  1160. if (!pszOption)
  1161. {
  1162. goto LERROR;
  1163. }
  1164. pszBegin = wcsstr(pszOption, szIdentifier);
  1165. if (!pszBegin)
  1166. {
  1167. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1168. goto LERROR;
  1169. }
  1170. pszString = (PWSTR) MemAlloc((wcslen(pszOption)+1) * sizeof(WCHAR));
  1171. if (NULL == pszString)
  1172. {
  1173. hr = E_OUTOFMEMORY;
  1174. goto LERROR;
  1175. }
  1176. pszBegin += wcslen(szIdentifier);
  1177. wcscpy(pszString, pszBegin);
  1178. pszEnd = wcschr(pszString, c_chOptionSeparator);
  1179. if(!pszEnd)
  1180. hr = E_INVALIDARG;
  1181. else
  1182. {
  1183. //set the end of the string
  1184. *pszEnd = 0;
  1185. str = pszString;
  1186. }
  1187. LERROR:
  1188. //it's ok to MemFree(NULL)
  1189. MemFree(pszString);
  1190. return hr;
  1191. }
  1192. //+---------------------------------------------------------------------------
  1193. //
  1194. // Name: ConstructOptionListString
  1195. //
  1196. // Purpose: Construct the option list of REMOTE_IPINFO
  1197. //
  1198. //
  1199. // Arguments:
  1200. // pAdapter [in] Pointer to info of the adapter
  1201. // strOptionList [out] The OptionList string
  1202. //
  1203. // Returns: None
  1204. //
  1205. // Author: nsun 01/12/99
  1206. //
  1207. // Note: Syntax of the Option list:
  1208. // "<Identifier><data>;<Identifier><data>;...;"
  1209. // The order of identifiers does not matter.
  1210. //
  1211. // Example:
  1212. // "DefGw=111.111.111.111,222.222.222.222;GwMetric=1,2;IfMetric=1;DNS=1.1.1.1;WINS=2.2.2.2"
  1213. //
  1214. VOID ConstructOptionListString(ADAPTER_INFO* pAdapter,
  1215. tstring & strOptionList)
  1216. {
  1217. Assert(pAdapter);
  1218. strOptionList = c_szEmpty;
  1219. //add gateway list
  1220. tstring str = c_szEmpty;
  1221. tstring strGatewayList = c_szDefGw;
  1222. ConvertColStringToString(pAdapter->m_vstrDefaultGateway,
  1223. c_chListSeparator,
  1224. str);
  1225. strGatewayList += str;
  1226. strOptionList += strGatewayList;
  1227. strOptionList += c_chOptionSeparator;
  1228. //add gateway metric list
  1229. tstring strMetricList = c_szGwMetric;
  1230. str = c_szEmpty;
  1231. ConvertColStringToString(pAdapter->m_vstrDefaultGatewayMetric,
  1232. c_chListSeparator,
  1233. str);
  1234. strMetricList += str;
  1235. strOptionList += strMetricList;
  1236. strOptionList += c_chOptionSeparator;
  1237. //add interface metric info to option list
  1238. strOptionList += c_szIfMetric;
  1239. WCHAR szBuf[MAX_METRIC_DIGITS + 1];
  1240. _ltot(pAdapter->m_dwInterfaceMetric, szBuf, 10);
  1241. strOptionList += szBuf;
  1242. strOptionList += c_chOptionSeparator;
  1243. //add DNS server list
  1244. strOptionList += c_szDNS;
  1245. str = c_szEmpty;
  1246. ConvertColStringToString(pAdapter->m_vstrDnsServerList,
  1247. c_chListSeparator,
  1248. str);
  1249. strOptionList += str;
  1250. strOptionList += c_chOptionSeparator;
  1251. //add WINS server list
  1252. strOptionList += c_szWINS;
  1253. str = c_szEmpty;
  1254. ConvertColStringToString(pAdapter->m_vstrWinsServerList,
  1255. c_chListSeparator,
  1256. str);
  1257. strOptionList += str;
  1258. strOptionList += c_chOptionSeparator;
  1259. //add DNS update parameters
  1260. strOptionList += c_szDynamicUpdate;
  1261. ZeroMemory(szBuf, sizeof(szBuf));
  1262. _ltot(pAdapter->m_fDisableDynamicUpdate ? 0 : 1, szBuf, 10);
  1263. strOptionList += szBuf;
  1264. strOptionList += c_chOptionSeparator;
  1265. strOptionList += c_szNameRegistration;
  1266. ZeroMemory(szBuf, sizeof(szBuf));
  1267. _ltot(pAdapter->m_fEnableNameRegistration ? 1 : 0, szBuf, 10);
  1268. strOptionList += szBuf;
  1269. strOptionList += c_chOptionSeparator;
  1270. }
  1271. //+---------------------------------------------------------------------------
  1272. //
  1273. // Name: HrParseOptionList
  1274. //
  1275. // Purpose: Parse the option list string of REMOTE_IPINFO and load the
  1276. // settings to the adapter info struct
  1277. //
  1278. // Arguments:
  1279. // pszOption [in] The OptionList string
  1280. // pAdapter [in/out] Pointer to info of the adapter
  1281. //
  1282. // Returns: S_OK if succeed
  1283. // Otherwise, the hresult error
  1284. //
  1285. // Author: nsun 07/11/99
  1286. //
  1287. //
  1288. HRESULT HrParseOptionList(PCWSTR pszOption,
  1289. ADAPTER_INFO* pAdapter)
  1290. {
  1291. HRESULT hr = S_OK;
  1292. Assert(pAdapter);
  1293. if (NULL == pszOption)
  1294. return hr;
  1295. HRESULT hrTmp = S_OK;
  1296. tstring str;
  1297. DWORD dwTemp = 0;
  1298. //Get default gateways
  1299. hr = RetrieveStringFromOptionList(pszOption,
  1300. c_szDefGw,
  1301. str);
  1302. if(SUCCEEDED(hr))
  1303. {
  1304. ConvertStringToColString(str.c_str(),
  1305. c_chListSeparator,
  1306. pAdapter->m_vstrDefaultGateway);
  1307. //Get gateway metrics
  1308. hr = RetrieveStringFromOptionList(pszOption,
  1309. c_szGwMetric,
  1310. str);
  1311. if(SUCCEEDED(hr))
  1312. {
  1313. ConvertStringToColString(str.c_str(),
  1314. c_chListSeparator,
  1315. pAdapter->m_vstrDefaultGatewayMetric);
  1316. }
  1317. }
  1318. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1319. {
  1320. //the option list doesn't have to have any of the tags
  1321. hr = S_OK;
  1322. }
  1323. //Get interface metric
  1324. hrTmp = RetrieveStringFromOptionList(pszOption,
  1325. c_szIfMetric,
  1326. str);
  1327. if(SUCCEEDED(hrTmp) && !str.empty())
  1328. {
  1329. DWORD dwIfMetric = _wtol(str.c_str());
  1330. pAdapter->m_dwInterfaceMetric = dwIfMetric;
  1331. }
  1332. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
  1333. {
  1334. hrTmp = S_OK;
  1335. }
  1336. if(SUCCEEDED(hr))
  1337. hr = hrTmp;
  1338. //Get DNS servers
  1339. hrTmp = RetrieveStringFromOptionList(pszOption,
  1340. c_szDNS,
  1341. str);
  1342. if (SUCCEEDED(hrTmp))
  1343. {
  1344. ConvertStringToColString(str.c_str(),
  1345. c_chListSeparator,
  1346. pAdapter->m_vstrDnsServerList);
  1347. }
  1348. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
  1349. {
  1350. hrTmp = S_OK;
  1351. }
  1352. if(SUCCEEDED(hr))
  1353. hr = hrTmp;
  1354. //Get WINS servers
  1355. hrTmp = RetrieveStringFromOptionList(pszOption,
  1356. c_szWINS,
  1357. str);
  1358. if (SUCCEEDED(hrTmp))
  1359. {
  1360. ConvertStringToColString(str.c_str(),
  1361. c_chListSeparator,
  1362. pAdapter->m_vstrWinsServerList);
  1363. }
  1364. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
  1365. {
  1366. hrTmp = S_OK;
  1367. }
  1368. if(SUCCEEDED(hr))
  1369. hr = hrTmp;
  1370. //Get DNS dynamic update parameters
  1371. hrTmp = RetrieveStringFromOptionList(pszOption,
  1372. c_szDynamicUpdate,
  1373. str);
  1374. if (SUCCEEDED(hrTmp))
  1375. {
  1376. dwTemp = _wtol(str.c_str());
  1377. pAdapter->m_fDisableDynamicUpdate = !dwTemp;
  1378. }
  1379. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
  1380. {
  1381. hrTmp = S_OK;
  1382. }
  1383. if(SUCCEEDED(hr))
  1384. hr = hrTmp;
  1385. hrTmp = RetrieveStringFromOptionList(pszOption,
  1386. c_szNameRegistration,
  1387. str);
  1388. if (SUCCEEDED(hrTmp))
  1389. {
  1390. dwTemp = _wtol(str.c_str());
  1391. pAdapter->m_fEnableNameRegistration = !!dwTemp;
  1392. }
  1393. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
  1394. {
  1395. hrTmp = S_OK;
  1396. }
  1397. if(SUCCEEDED(hr))
  1398. hr = hrTmp;
  1399. return hr;
  1400. }
  1401. //+---------------------------------------------------------------------------
  1402. //
  1403. // Name: HrGetPrimaryDnsDomain
  1404. //
  1405. // Purpose: Get the Primary Dns Domain name
  1406. //
  1407. //
  1408. // Arguments:
  1409. // pstr [out] The string contains the Primary Dns Domain name
  1410. //
  1411. // Returns: HRESULT
  1412. //
  1413. // Author: nsun 03/03/99
  1414. HRESULT HrGetPrimaryDnsDomain(tstring *pstr)
  1415. {
  1416. HRESULT hr = S_OK;
  1417. Assert(pstr);
  1418. DWORD dwErr;
  1419. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  1420. dwErr = DsRoleGetPrimaryDomainInformation( NULL,
  1421. DsRolePrimaryDomainInfoBasic,
  1422. (PBYTE *) &pPrimaryDomainInfo);
  1423. if (ERROR_SUCCESS == dwErr && NULL != pPrimaryDomainInfo )
  1424. {
  1425. if (pPrimaryDomainInfo->DomainNameDns)
  1426. *pstr = pPrimaryDomainInfo->DomainNameDns;
  1427. else
  1428. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1429. DsRoleFreeMemory(pPrimaryDomainInfo);
  1430. }
  1431. else
  1432. hr = HRESULT_FROM_WIN32(dwErr);
  1433. TraceError("CTcpipcfg::HrGetPrimaryDnsDomain:", hr);
  1434. return hr;
  1435. }
  1436. //+---------------------------------------------------------------------------
  1437. //
  1438. // Name: WriteSetupErrorLog
  1439. //
  1440. // Purpose: Write an error to setuperr.log
  1441. //
  1442. //
  1443. // Arguments:
  1444. // nIdErrorFormat [in] The ID of the error format string
  1445. //
  1446. // Returns: None, but Error trace will be generated if fails to write setup
  1447. // error log
  1448. //
  1449. // Author: nsun 03/21/99
  1450. VOID WriteTcpSetupErrorLog(UINT nIdErrorFormat, ...)
  1451. {
  1452. PCWSTR pszFormat = SzLoadIds(nIdErrorFormat);
  1453. PWSTR pszText = NULL;
  1454. DWORD dwRet;
  1455. va_list val;
  1456. va_start(val, nIdErrorFormat);
  1457. dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  1458. pszFormat, 0, 0, (PWSTR)&pszText, 0, &val);
  1459. va_end(val);
  1460. if (dwRet && pszText)
  1461. {
  1462. tstring strMsg = L"";
  1463. //Add the current time at the begining of the error log
  1464. time_t tclock;
  1465. time(&tclock);
  1466. struct tm * ptmLocalTime;
  1467. ptmLocalTime = localtime(&tclock);
  1468. if (ptmLocalTime)
  1469. {
  1470. LPWSTR pwsz = _wasctime(ptmLocalTime);
  1471. if (pwsz)
  1472. {
  1473. strMsg = pwsz;
  1474. }
  1475. }
  1476. strMsg += pszText;
  1477. if (!SetupLogError(strMsg.c_str(), LogSevError))
  1478. {
  1479. TraceError("Tcpip: WriteSetupErrorLog", HRESULT_FROM_WIN32(GetLastError()));
  1480. }
  1481. LocalFree(pszText);
  1482. }
  1483. else
  1484. {
  1485. TraceError("Tcpip: WriteSetupErrorLog: unable to FormatMessage()", HRESULT_FROM_WIN32(GetLastError()));
  1486. }
  1487. }
  1488. DWORD IPStringToDword(LPCTSTR szIP)
  1489. {
  1490. if (NULL == szIP || 0 == lstrlenW(szIP))
  1491. {
  1492. return 0;
  1493. }
  1494. DWORD arrdwIp[4];
  1495. GetNodeNum(szIP, arrdwIp);
  1496. return (arrdwIp[0] << 24) + (arrdwIp[1] << 16)
  1497. + (arrdwIp[2] << 8) + arrdwIp[3];
  1498. }
  1499. void DwordToIPString(DWORD dwIP, tstring & strIP)
  1500. {
  1501. if (0 == dwIP)
  1502. {
  1503. strIP = c_szEmpty;
  1504. return;
  1505. }
  1506. WCHAR szTemp[4];
  1507. wsprintf(szTemp, L"%d", dwIP >> 24);
  1508. strIP = szTemp;
  1509. strIP += CH_DOT;
  1510. wsprintf(szTemp, L"%d", (dwIP & 0x00FF0000) >> 16);
  1511. strIP += szTemp;
  1512. strIP += CH_DOT;
  1513. wsprintf(szTemp, L"%d", (dwIP & 0x0000FF00) >> 8);
  1514. strIP += szTemp;
  1515. strIP += CH_DOT;
  1516. wsprintf(szTemp, L"%d", (dwIP & 0x000000FF));
  1517. strIP += szTemp;
  1518. return;
  1519. }
  1520. //Seach a List view for an item contains the specified string
  1521. //Arguments:
  1522. // hListView [IN] Handle to the list view
  1523. // iSubItem [IN] Subitem to search
  1524. // psz [IN] The string to search
  1525. //Return
  1526. // -1 if no items are found
  1527. // otherwise the index of the first item matching the string
  1528. //
  1529. int SearchListViewItem(HWND hListView, int iSubItem, LPCWSTR psz)
  1530. {
  1531. int iRet = -1;
  1532. int nlvCount = ListView_GetItemCount(hListView);
  1533. WCHAR szBuf[256];
  1534. LV_ITEM lvItem;
  1535. lvItem.mask = LVIF_TEXT;
  1536. lvItem.pszText = szBuf;
  1537. lvItem.cchTextMax = celems(szBuf);
  1538. for (int i = 0; i < nlvCount; i++)
  1539. {
  1540. lvItem.iItem = i;
  1541. lvItem.iSubItem = iSubItem;
  1542. ListView_GetItem(hListView, &lvItem);
  1543. if (lstrcmpiW(psz, szBuf) == 0)
  1544. {
  1545. iRet = i;
  1546. break;
  1547. }
  1548. }
  1549. return iRet;
  1550. }