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.

1392 lines
39 KiB

  1. //***************************************************************************
  2. //
  3. // VIPSPAGE.CPP
  4. //
  5. // Module: NLB Manager
  6. //
  7. // Purpose: Implements VipsPage, which is a dialog for managing the list
  8. // of cluster ip addresses.
  9. //
  10. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  11. //
  12. // History:
  13. //
  14. // 09/24/01 JosephJ Created
  15. // 01/22/2002 SHouse cleaned up this dialog
  16. //
  17. //***************************************************************************
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include "private.h"
  21. #include "vipspage.h"
  22. #include "vipspage.tmh"
  23. // BEGIN_MESSAGE_MAP( VipsPage, CDialog )
  24. BEGIN_MESSAGE_MAP( VipsPage, CPropertyPage )
  25. ON_BN_CLICKED(IDC_BUTTON_ADD_VIP, OnButtonAdd)
  26. ON_BN_CLICKED(IDC_BUTTON_MODIFY_VIP, OnButtonEdit)
  27. ON_BN_CLICKED(IDC_BUTTON_REMOVE_VIP, OnButtonRemove)
  28. ON_NOTIFY(NM_DBLCLK, IDC_LIST_ADDITIONAL_VIPS, OnDoubleClick)
  29. ON_WM_HELPINFO()
  30. ON_WM_CONTEXTMENU()
  31. ON_NOTIFY( LVN_ITEMCHANGED, IDC_LIST_ADDITIONAL_VIPS, OnSelchanged )
  32. //
  33. // Other options...
  34. //
  35. // ON_EN_SETFOCUS(IDC_EDIT_HOSTADDRESS,OnSetFocusEditHostAddress)
  36. // ON_WM_ACTIVATE()
  37. // ON_NOTIFY( NM_DBLCLK, IDC_LIST_ADDITONAL_VIPS, OnDoubleClick )
  38. // ON_NOTIFY( LVN_COLUMNCLICK, IDC_LIST_ADDITONAL_VIPS, OnColumnClick )
  39. //
  40. END_MESSAGE_MAP()
  41. //
  42. // Static help-id maps
  43. //
  44. DWORD
  45. VipsPage::s_HelpIDs[] =
  46. {
  47. IDC_GROUP_PRIMARY_IP, IDC_EDIT_PRIMARY_IP,
  48. IDC_TEXT_PRIMARY_IP, IDC_EDIT_PRIMARY_IP,
  49. IDC_EDIT_PRIMARY_IP, IDC_EDIT_PRIMARY_IP,
  50. IDC_TEXT_PRIMARY_MASK, IDC_EDIT_PRIMARY_IP,
  51. IDC_EDIT_PRIMARY_MASK, IDC_EDIT_PRIMARY_IP,
  52. IDC_GROUP_ADDITIONAL_VIPS, IDC_LIST_ADDITIONAL_VIPS,
  53. IDC_LIST_ADDITIONAL_VIPS, IDC_LIST_ADDITIONAL_VIPS,
  54. IDC_BUTTON_ADD_VIP, IDC_BUTTON_ADD_VIP,
  55. IDC_BUTTON_MODIFY_VIP, IDC_BUTTON_MODIFY_VIP,
  56. IDC_BUTTON_REMOVE_VIP, IDC_BUTTON_REMOVE_VIP,
  57. 0, 0
  58. };
  59. VipsPage::VipsPage(
  60. CPropertySheet *psh,
  61. NLB_EXTENDED_CLUSTER_CONFIGURATION *pNlbCfg,
  62. BOOL fClusterView,
  63. CWnd* parent
  64. )
  65. :
  66. CPropertyPage(IDD),
  67. m_pshOwner(psh),
  68. m_pNlbCfg(pNlbCfg),
  69. m_fClusterView(fClusterView),
  70. m_fModified(FALSE),
  71. m_uPrimaryClusterIp(0)
  72. {
  73. }
  74. void
  75. VipsPage::DoDataExchange( CDataExchange* pDX )
  76. {
  77. // CDialog::DoDataExchange(pDX);
  78. CPropertyPage::DoDataExchange(pDX);
  79. DDX_Control(pDX, IDC_LIST_ADDITIONAL_VIPS, listAdditionalVips);
  80. //
  81. // Note: the buttons are handled by the ON_BN_CLICKED macro
  82. // above.
  83. //
  84. // DDX_Control(pDX, IDC_BUTTON_CONNECT, buttonConnect);
  85. // DDX_Control(pDX, IDC_BUTTON_CREDENTIALS, credentialsButton);
  86. }
  87. BOOL
  88. VipsPage::OnInitDialog()
  89. {
  90. BOOL fRet = CPropertyPage::OnInitDialog();
  91. if (fRet)
  92. {
  93. CWnd *pItem = NULL;
  94. // Initialize the list control
  95. mfn_InitializeListView();
  96. mfn_LoadFromNlbCfg();
  97. /* Disable the Delete button. */
  98. pItem = GetDlgItem(IDC_BUTTON_REMOVE_VIP);
  99. if (pItem)
  100. {
  101. ::EnableWindow (pItem->m_hWnd, FALSE);
  102. }
  103. /* Disable the Edit button. */
  104. pItem = GetDlgItem(IDC_BUTTON_MODIFY_VIP);
  105. if (pItem)
  106. {
  107. ::EnableWindow (pItem->m_hWnd, FALSE);
  108. }
  109. /* Enable the Add button only if we're showing cluster
  110. properties; otherwise its read-only, disable it. */
  111. pItem = GetDlgItem(IDC_BUTTON_ADD_VIP);
  112. if (pItem)
  113. {
  114. ::EnableWindow (pItem->m_hWnd, m_fClusterView);
  115. }
  116. /* Disable the primary IP address dialog. */
  117. pItem = GetDlgItem(IDC_EDIT_PRIMARY_IP);
  118. if (pItem)
  119. {
  120. ::EnableWindow (pItem->m_hWnd, FALSE);
  121. }
  122. /* Disable the primary IP subnet mask dialog */
  123. pItem = GetDlgItem(IDC_EDIT_PRIMARY_MASK);
  124. if (pItem)
  125. {
  126. ::EnableWindow (pItem->m_hWnd, FALSE);
  127. }
  128. }
  129. return fRet;
  130. }
  131. BOOL
  132. VipsPage::OnHelpInfo (HELPINFO* helpInfo )
  133. {
  134. if( helpInfo->iContextType == HELPINFO_WINDOW )
  135. {
  136. ::WinHelp( static_cast<HWND> ( helpInfo->hItemHandle ),
  137. CVY_CTXT_HELP_FILE,
  138. HELP_WM_HELP,
  139. (ULONG_PTR ) s_HelpIDs);
  140. }
  141. return TRUE;
  142. }
  143. void
  144. VipsPage::OnContextMenu( CWnd* pWnd, CPoint point )
  145. {
  146. ::WinHelp( m_hWnd,
  147. CVY_CTXT_HELP_FILE,
  148. HELP_CONTEXTMENU,
  149. (ULONG_PTR ) s_HelpIDs);
  150. }
  151. BOOL
  152. VipsPage::OnKillActive()
  153. {
  154. // validate data
  155. mfn_SaveToNlbCfg();
  156. return TRUE;
  157. }
  158. void
  159. VipsPage::mfn_InitializeListView(void)
  160. //
  161. // Set the columns on the list box based on the type of dialog
  162. //
  163. {
  164. RECT rect;
  165. INT colWidth;
  166. CWnd * List = GetDlgItem(IDC_LIST_ADDITIONAL_VIPS);
  167. List->GetClientRect(&rect);
  168. colWidth = (rect.right - rect.left)/2;
  169. //
  170. // The interface list is that of interfaces already bound to NLB.
  171. // we display the cluster dnsname and ip first, then adapter name.
  172. //
  173. listAdditionalVips.InsertColumn(
  174. 0,
  175. GETRESOURCEIDSTRING( IDS_HEADER_VIPLIST_IP_ADDRESS),
  176. LVCFMT_LEFT,
  177. colWidth);
  178. listAdditionalVips.InsertColumn(
  179. 1,
  180. GETRESOURCEIDSTRING( IDS_HEADER_VIPLIST_SUBNET_MASK),
  181. LVCFMT_LEFT,
  182. colWidth);
  183. //
  184. // Allow entire row to be selected.
  185. //
  186. listAdditionalVips.SetExtendedStyle(listAdditionalVips.GetExtendedStyle() | LVS_EX_FULLROWSELECT );
  187. }
  188. void
  189. VipsPage::mfn_InsertNetworkAddress(
  190. LPCWSTR szIP,
  191. LPCWSTR szSubnetMask,
  192. UINT lParam,
  193. int nItem
  194. )
  195. {
  196. LVFINDINFO Info;
  197. int eItem;
  198. ZeroMemory(&Info, sizeof(Info));
  199. Info.flags = LVFI_PARAM;
  200. Info.lParam = lParam;
  201. eItem = listAdditionalVips.FindItem(&Info);
  202. /* If we found an entry that already has this IP address, we
  203. need to do some extra work to resolve the duplicate entry. */
  204. if (eItem != -1) {
  205. /* If this is an Add operation, then we should simple usurp
  206. this entry in the list and re-use it for this IP. If a
  207. user tries to add an IP address that already exists, we'll
  208. in effect change it to a modify operation in the case that
  209. the subnet mask has changed; otherwise its a no-op. */
  210. if (nItem == -1) {
  211. /* Change nItem to eItem to usurp the existing list entry
  212. for this new IP address entry. */
  213. nItem = eItem;
  214. /* Otherwise, if this is already an edit operation, then what
  215. what actually need to do is both turn this operation into
  216. an edit on the existing entry we found for this IP address,
  217. but further, we need to delete the item we were actually in
  218. the process of editing, as it was the user's intention to
  219. get rid of that IP address. */
  220. } else if (eItem != nItem) {
  221. /* Delete the list entry we're "editing". */
  222. listAdditionalVips.DeleteItem(nItem);
  223. /* Change nItem to eItem to usurp the existing list entry
  224. for this new IP address entry. */
  225. nItem = eItem;
  226. }
  227. }
  228. /* An index of -1 indicates a new item to list. If the index is NOT
  229. -1, then we're dealing with changes to an existing list item. */
  230. if (nItem != -1) {
  231. listAdditionalVips.SetItemText(nItem, 0, szIP);
  232. listAdditionalVips.SetItemText(nItem, 1, szSubnetMask);
  233. /* Otherwise, insert a new item. */
  234. } else {
  235. nItem = listAdditionalVips.GetItemCount();
  236. /* Add the IP address. */
  237. listAdditionalVips.InsertItem(
  238. LVIF_TEXT | LVIF_PARAM, // nMask
  239. nItem, // nItem
  240. szIP,
  241. 0, // nState
  242. 0, // nStateMask
  243. 0, // nImage
  244. lParam // lParam
  245. );
  246. /* Add the subnet mask. */
  247. listAdditionalVips.SetItemText(nItem, 1, szSubnetMask);
  248. }
  249. /* Select the new or modified rule. */
  250. listAdditionalVips.SetItemState(nItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  251. return;
  252. }
  253. void VipsPage::OnOK()
  254. {
  255. mfn_SaveToNlbCfg();
  256. CPropertyPage::OnOK();
  257. }
  258. void VipsPage::OnButtonAdd()
  259. /*
  260. User has clicked the "Add" button.
  261. 2. Switch cursor to hourglass, connect, switch back from hourglass.
  262. */
  263. {
  264. LPWSTR szIPAddress = NULL;
  265. LPWSTR szSubnetMask = NULL;
  266. /* Create a dialog to add a new VIP. Initialize with empty strings
  267. (or NULL) since this is an Add operation. */
  268. CIPAddressDialog pIPDlg(L"", L"");
  269. /* Show the dialog box. If the user presses "OK", update the VIP list, otherwise ignore it. */
  270. if (pIPDlg.DoModal() == IDOK) {
  271. WCHAR szMungedIpAddress[WLBS_MAX_CL_IP_ADDR+1];
  272. WCHAR szDefaultSubnetMask[WLBS_MAX_CL_NET_MASK+1];
  273. WCHAR szConcatenatedIPandMask[WLBS_MAX_CL_IP_ADDR + WLBS_MAX_CL_NET_MASK + 2];
  274. LPWSTR szNewIPAddress = NULL;
  275. LPWSTR szNewSubnetMask = NULL;
  276. UINT uClusterIp = 0;
  277. UINT uSubnetMask = 0;
  278. UINT uDefaultSubnetMask = 0;
  279. /* Get the IP address and subnet mask the user typed into the dialog.
  280. Note that the dialog allocates the memory for us and we're required
  281. to free it when we're done. */
  282. szIPAddress = pIPDlg.GetIPAddress();
  283. szSubnetMask = pIPDlg.GetSubnetMask();
  284. /* Cat the IP address and subnetmask for verification by CfgUtilsValidateNetworkAddress. */
  285. StringCbPrintf(
  286. szConcatenatedIPandMask,
  287. sizeof(szConcatenatedIPandMask),
  288. L"%ls/%ls", szIPAddress, szSubnetMask
  289. );
  290. //
  291. // Validate the network address -- if failure, put up msg box.
  292. // TODO: call extended validation function.
  293. //
  294. {
  295. WBEMSTATUS wStat;
  296. wStat = CfgUtilsValidateNetworkAddress(
  297. szConcatenatedIPandMask,
  298. &uClusterIp,
  299. &uSubnetMask,
  300. &uDefaultSubnetMask
  301. );
  302. if (!FAILED(wStat))
  303. {
  304. //
  305. // Add some more checks...
  306. //
  307. UINT u = uClusterIp&0xff;
  308. if (u<1 || u>=224)
  309. {
  310. wStat = WBEM_E_CRITICAL_ERROR;
  311. }
  312. }
  313. if (FAILED(wStat))
  314. {
  315. ::MessageBox(
  316. NULL,
  317. GETRESOURCEIDSTRING(IDS_INVALID_IP_OR_SUBNET),
  318. GETRESOURCEIDSTRING(IDS_INVALID_INFORMATION),
  319. MB_ICONINFORMATION | MB_OK
  320. );
  321. goto end;
  322. }
  323. //
  324. // Can't add the primary cluster vip.
  325. //
  326. if (uClusterIp == m_uPrimaryClusterIp)
  327. {
  328. goto end;
  329. }
  330. }
  331. if (*szSubnetMask == 0)
  332. {
  333. // subnet mask was not specified -- substitute default.
  334. uSubnetMask = uDefaultSubnetMask;
  335. }
  336. //
  337. // Change subnet to canonical form...
  338. //
  339. {
  340. LPBYTE pb = (LPBYTE) &uSubnetMask;
  341. StringCbPrintf(
  342. szDefaultSubnetMask,
  343. sizeof(szDefaultSubnetMask),
  344. L"%lu.%lu.%lu.%lu",
  345. pb[0], pb[1], pb[2], pb[3]
  346. );
  347. szNewSubnetMask = szDefaultSubnetMask;
  348. }
  349. //
  350. // Change IP to canonical form
  351. //
  352. {
  353. LPBYTE pb = (LPBYTE) &uClusterIp;
  354. StringCbPrintf(
  355. szMungedIpAddress,
  356. sizeof(szMungedIpAddress),
  357. L"%lu.%lu.%lu.%lu",
  358. pb[0], pb[1], pb[2], pb[3]
  359. );
  360. szNewIPAddress = szMungedIpAddress;
  361. }
  362. //
  363. // mfn_InsertNetworkAddress will make sure it's inserted in the
  364. // proper location and will not insert it if it's a duplicate.
  365. //
  366. mfn_InsertNetworkAddress(szNewIPAddress, szNewSubnetMask, uClusterIp, -1);
  367. m_fModified = TRUE; // we'll need to update m_pNlbCfg later.
  368. }
  369. end:
  370. /* Move the focus from the add button back to the list view. */
  371. listAdditionalVips.SetFocus();
  372. /* Free the IP address and subnet mask memory that were allocated by CIPAddressDialog. */
  373. if (szIPAddress) free(szIPAddress);
  374. if (szSubnetMask) free(szSubnetMask);
  375. return;
  376. }
  377. void VipsPage::OnButtonRemove()
  378. /*
  379. User has clicked the "Remove" button.
  380. */
  381. {
  382. int nItem;
  383. UINT uCount;
  384. /* Get the selected item - if nothing is selected, bail out. */
  385. nItem = listAdditionalVips.GetNextItem(-1, LVNI_ALL|LVNI_SELECTED);
  386. if (nItem == -1)
  387. {
  388. goto end;
  389. }
  390. /* Delete the selected entry. */
  391. listAdditionalVips.DeleteItem(nItem);
  392. uCount = listAdditionalVips.GetItemCount();
  393. if (uCount > nItem) {
  394. /* This was NOT the last (in order) VIP in the list, so highlight
  395. the VIP in the same position in the list box. */
  396. listAdditionalVips.SetItemState(nItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  397. } else if (uCount > 0) {
  398. /* This was the last (in order) VIP in the list, so we highlight
  399. the VIP "behind" us in the list - our position minus one. */
  400. listAdditionalVips.SetItemState(nItem - 1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  401. } else {
  402. /* The list is empty - no need to select anything. */
  403. }
  404. m_fModified = TRUE; // we'll need to update m_pNlbCfg later.
  405. end:
  406. /* Move the focus from the delete button back to the list view. */
  407. listAdditionalVips.SetFocus();
  408. return;
  409. }
  410. void VipsPage::OnDoubleClick (NMHDR * pNotifyStruct, LRESULT * result )
  411. {
  412. OnButtonEdit();
  413. *result = 0;
  414. return;
  415. }
  416. void VipsPage::OnButtonEdit()
  417. /*
  418. User has clicked the "Edit" button.
  419. */
  420. {
  421. WCHAR wszSubnetMask[64];
  422. WCHAR wszIPAddress[64];
  423. LPWSTR szIPAddress = NULL;
  424. LPWSTR szSubnetMask = NULL;
  425. int nItem;
  426. int iLen;
  427. nItem = listAdditionalVips.GetNextItem(-1, LVNI_ALL|LVNI_SELECTED);
  428. if (nItem == -1)
  429. {
  430. return;
  431. }
  432. /* Get the IP address from the listview. */
  433. iLen = listAdditionalVips.GetItemText(
  434. nItem,
  435. 0,
  436. wszIPAddress,
  437. sizeof(wszIPAddress)/sizeof(*wszIPAddress));
  438. wszIPAddress[(sizeof(wszIPAddress)/sizeof(*wszIPAddress))-1]=0;
  439. /* Get the subnet mask from the listview. */
  440. iLen = listAdditionalVips.GetItemText(
  441. nItem,
  442. 1,
  443. wszSubnetMask,
  444. sizeof(wszSubnetMask)/sizeof(*wszSubnetMask));
  445. wszSubnetMask[(sizeof(wszSubnetMask)/sizeof(*wszSubnetMask))-1]=0;
  446. /* Create a dialog to add a new VIP. Initialize with the IP address and
  447. subnet masks retrieved from the listview since this is an Edit operation. */
  448. CIPAddressDialog pIPDlg(wszIPAddress, wszSubnetMask);
  449. /* Show the dialog box. If the user presses "OK", update the VIP list, otherwise ignore it. */
  450. if (pIPDlg.DoModal() == IDOK) {
  451. WCHAR szMungedIpAddress[WLBS_MAX_CL_IP_ADDR+1];
  452. WCHAR szDefaultSubnetMask[WLBS_MAX_CL_NET_MASK+1];
  453. WCHAR szConcatenatedIPandMask[WLBS_MAX_CL_IP_ADDR + WLBS_MAX_CL_NET_MASK + 2];
  454. LPWSTR szNewIPAddress = NULL;
  455. LPWSTR szNewSubnetMask = NULL;
  456. UINT uClusterIp = 0;
  457. UINT uSubnetMask = 0;
  458. UINT uDefaultSubnetMask = 0;
  459. /* Get the IP address and subnet mask the user typed into the dialog.
  460. Note that the dialog allocates the memory for us and we're required
  461. to free it when we're done. */
  462. szIPAddress = pIPDlg.GetIPAddress();
  463. szSubnetMask = pIPDlg.GetSubnetMask();
  464. /* Cat the IP address and subnetmask for verification by CfgUtilsValidateNetworkAddress. */
  465. StringCbPrintf(
  466. szConcatenatedIPandMask,
  467. sizeof(szConcatenatedIPandMask),
  468. L"%ls/%ls", szIPAddress, szSubnetMask
  469. );
  470. //
  471. // Validate the network address -- if failure, put up msg box.
  472. // TODO: call extended validation function.
  473. //
  474. {
  475. WBEMSTATUS wStat;
  476. wStat = CfgUtilsValidateNetworkAddress(
  477. szConcatenatedIPandMask,
  478. &uClusterIp,
  479. &uSubnetMask,
  480. &uDefaultSubnetMask
  481. );
  482. if (!FAILED(wStat))
  483. {
  484. //
  485. // Add some more checks...
  486. //
  487. UINT u = uClusterIp&0xff;
  488. if (u<1 || u>=224)
  489. {
  490. wStat = WBEM_E_CRITICAL_ERROR;
  491. }
  492. }
  493. if (FAILED(wStat))
  494. {
  495. ::MessageBox(
  496. NULL,
  497. GETRESOURCEIDSTRING(IDS_INVALID_IP_OR_SUBNET),
  498. GETRESOURCEIDSTRING(IDS_INVALID_INFORMATION),
  499. MB_ICONINFORMATION | MB_OK
  500. );
  501. goto end;
  502. }
  503. //
  504. // Can't add the primary cluster vip.
  505. //
  506. if (uClusterIp == m_uPrimaryClusterIp)
  507. {
  508. goto end;
  509. }
  510. }
  511. if (*szSubnetMask == 0)
  512. {
  513. // subnet mask was not specified -- substitute default.
  514. uSubnetMask = uDefaultSubnetMask;
  515. }
  516. //
  517. // Change subnet to canonical form...
  518. //
  519. {
  520. LPBYTE pb = (LPBYTE) &uSubnetMask;
  521. StringCbPrintf(
  522. szDefaultSubnetMask,
  523. sizeof(szDefaultSubnetMask),
  524. L"%lu.%lu.%lu.%lu",
  525. pb[0], pb[1], pb[2], pb[3]
  526. );
  527. szNewSubnetMask = szDefaultSubnetMask;
  528. }
  529. //
  530. // Change IP to canonical form
  531. //
  532. {
  533. LPBYTE pb = (LPBYTE) &uClusterIp;
  534. StringCbPrintf(
  535. szMungedIpAddress,
  536. sizeof(szMungedIpAddress),
  537. L"%lu.%lu.%lu.%lu",
  538. pb[0], pb[1], pb[2], pb[3]
  539. );
  540. szNewIPAddress = szMungedIpAddress;
  541. }
  542. //
  543. // mfn_InsertNetworkAddress will make sure it's inserted in the
  544. // proper location and will not insert it if it's a duplicate.
  545. //
  546. mfn_InsertNetworkAddress(szNewIPAddress, szNewSubnetMask, uClusterIp, nItem);
  547. m_fModified = TRUE; // we'll need to update m_pNlbCfg later.
  548. }
  549. end:
  550. /* Move the focus from the edit button back to the list view. */
  551. listAdditionalVips.SetFocus();
  552. /* Free the IP address and subnet mask memory that were allocated by CIPAddressDialog. */
  553. if (szIPAddress) free(szIPAddress);
  554. if (szSubnetMask) free(szSubnetMask);
  555. return;
  556. }
  557. void VipsPage::OnSelchanged(NMHDR * pNotifyStruct, LRESULT * result )
  558. /*
  559. A listbox item has been selected.
  560. */
  561. {
  562. POSITION pos;
  563. BOOL fSelected = FALSE;
  564. if (!m_fClusterView)
  565. {
  566. goto end; // we don't allow modifications unless its the cluster
  567. // view.
  568. }
  569. pos = listAdditionalVips.GetFirstSelectedItemPosition();
  570. fSelected = FALSE;
  571. if( pos != NULL )
  572. {
  573. int index = listAdditionalVips.GetNextSelectedItem( pos );
  574. fSelected = TRUE;
  575. }
  576. else
  577. {
  578. }
  579. if (fSelected)
  580. {
  581. // enable remove
  582. ::EnableWindow (GetDlgItem(IDC_BUTTON_REMOVE_VIP)->m_hWnd, TRUE);
  583. // enable edit
  584. ::EnableWindow (GetDlgItem(IDC_BUTTON_MODIFY_VIP)->m_hWnd, TRUE);
  585. }
  586. else
  587. {
  588. // disable remove
  589. ::EnableWindow (GetDlgItem(IDC_BUTTON_REMOVE_VIP)->m_hWnd, FALSE);
  590. // disable edit
  591. ::EnableWindow (GetDlgItem(IDC_BUTTON_MODIFY_VIP)->m_hWnd, FALSE);
  592. }
  593. end:
  594. *result = 0;
  595. return;
  596. }
  597. BOOL
  598. VipsPage::OnSetActive()
  599. {
  600. BOOL fRet = CPropertyPage::OnSetActive();
  601. m_pshOwner->SetWizardButtons(
  602. PSWIZB_BACK|
  603. PSWIZB_NEXT|
  604. // PSWIZB_FINISH|
  605. // PSWIZB_DISABLEDFINISH|
  606. 0
  607. );
  608. mfn_LoadFromNlbCfg();
  609. return fRet;
  610. }
  611. void
  612. VipsPage::mfn_LoadFromNlbCfg(void)
  613. {
  614. WBEMSTATUS wStatus;
  615. UINT uClusterIp = 0;
  616. UINT uDedicatedIp = 0;
  617. WBEMSTATUS wStat;
  618. //
  619. // Initialize the cluster network address.
  620. //
  621. {
  622. CWnd *pItem = GetDlgItem(IDC_EDIT_PRIMARY_IP);
  623. m_uPrimaryClusterIp = 0;
  624. if (pItem)
  625. {
  626. wStat = CfgUtilsValidateNetworkAddress(
  627. m_pNlbCfg->NlbParams.cl_ip_addr,
  628. &uClusterIp,
  629. NULL,
  630. NULL
  631. );
  632. if (wStat != WBEM_NO_ERROR)
  633. {
  634. uClusterIp = 0;
  635. pItem->SetWindowText(L"");
  636. }
  637. else
  638. {
  639. m_uPrimaryClusterIp = uClusterIp;
  640. pItem->SetWindowText(m_pNlbCfg->NlbParams.cl_ip_addr);
  641. }
  642. }
  643. pItem = GetDlgItem(IDC_EDIT_PRIMARY_MASK);
  644. if (pItem)
  645. {
  646. pItem->SetWindowText(m_pNlbCfg->NlbParams.cl_net_mask);
  647. }
  648. }
  649. //
  650. // Get the DWORD form of the dedicated IP address
  651. //
  652. {
  653. wStat = CfgUtilsValidateNetworkAddress(
  654. m_pNlbCfg->NlbParams.ded_ip_addr,
  655. &uDedicatedIp,
  656. NULL,
  657. NULL
  658. );
  659. if (wStat != WBEM_NO_ERROR)
  660. {
  661. uDedicatedIp = 0;
  662. }
  663. }
  664. //
  665. // Fill in the list box, EXCLUDING the cluster network address
  666. // and dedicated ip address (if each are present)
  667. //
  668. {
  669. //
  670. // Clear the list box
  671. //
  672. listAdditionalVips.DeleteAllItems();
  673. //
  674. // For each ip address list, if it's not the vip or dip,
  675. // insert it into the list view.
  676. //
  677. // Find location of old network address
  678. for (UINT u=0; u<m_pNlbCfg->NumIpAddresses; u++)
  679. {
  680. UINT uTmpIp = 0;
  681. NLB_IP_ADDRESS_INFO *pInfo = & m_pNlbCfg->pIpAddressInfo[u];
  682. wStat = CfgUtilsValidateNetworkAddress(
  683. pInfo->IpAddress,
  684. &uTmpIp,
  685. NULL,
  686. NULL
  687. );
  688. if (wStat == WBEM_NO_ERROR)
  689. {
  690. if (uTmpIp == uDedicatedIp || uTmpIp == uClusterIp)
  691. {
  692. //
  693. // It's the cluster ip or the dedicated ip -- skip.
  694. //
  695. continue;
  696. }
  697. }
  698. else
  699. {
  700. TRACE_CRIT(L"%!FUNC! Invalid IP address %ws",
  701. m_pNlbCfg->pIpAddressInfo[u].IpAddress);
  702. //
  703. // Invalid IP -- don't display it -- should we?
  704. //
  705. continue;
  706. }
  707. mfn_InsertNetworkAddress(
  708. pInfo->IpAddress,
  709. pInfo->SubnetMask,
  710. uTmpIp,
  711. -1
  712. );
  713. }
  714. }
  715. m_fModified = FALSE; // not been modified since we've last synched
  716. // with m_pNlbCfg.
  717. }
  718. void
  719. VipsPage::mfn_SaveToNlbCfg(void)
  720. /*
  721. Save settings to m_pNlbCfg
  722. */
  723. {
  724. WBEMSTATUS wStatus;
  725. if (!m_fModified)
  726. {
  727. // Nothing to do.
  728. goto end;
  729. }
  730. m_fModified = FALSE;
  731. //
  732. // We expect that the list ctrl never contains the
  733. // primary cluster IP, so we'll always add it first,
  734. // followed by all the ip in the list ctrl.
  735. //
  736. {
  737. // Pre-allocate the array
  738. UINT uCount = listAdditionalVips.GetItemCount();
  739. NLB_IP_ADDRESS_INFO *rgInfo = new NLB_IP_ADDRESS_INFO[uCount+1];
  740. if (rgInfo == NULL)
  741. {
  742. TRACE_CRIT("%!FUNC! allocation failure!");
  743. goto end;
  744. }
  745. ZeroMemory(rgInfo, sizeof(NLB_IP_ADDRESS_INFO)*(uCount+1));
  746. //
  747. // Insert the primary vip first.
  748. //
  749. ARRAYSTRCPY(
  750. rgInfo[0].IpAddress,
  751. m_pNlbCfg->NlbParams.cl_ip_addr
  752. );
  753. ARRAYSTRCPY(
  754. rgInfo[0].SubnetMask,
  755. m_pNlbCfg->NlbParams.cl_net_mask
  756. );
  757. //
  758. // Insert the remaining ones.
  759. //
  760. for (int nItem = 0; nItem < uCount; nItem++)
  761. {
  762. NLB_IP_ADDRESS_INFO *pInfo = &rgInfo[nItem+1];
  763. WCHAR rgTmp[64];
  764. int iLen;
  765. /* Get the IP address. */
  766. iLen = listAdditionalVips.GetItemText(
  767. nItem,
  768. 0, // nSubItem,
  769. rgTmp,
  770. sizeof(rgTmp)/sizeof(*rgTmp));
  771. rgTmp[(sizeof(rgTmp)/sizeof(*rgTmp))-1]=0;
  772. if (iLen > 0)
  773. {
  774. ARRAYSTRCPY(pInfo->IpAddress, rgTmp);
  775. }
  776. /* Get the subnet mask. */
  777. iLen = listAdditionalVips.GetItemText(
  778. nItem,
  779. 1, // nSubItem,
  780. rgTmp,
  781. sizeof(rgTmp)/sizeof(*rgTmp));
  782. rgTmp[(sizeof(rgTmp)/sizeof(*rgTmp))-1]=0;
  783. if (iLen > 0)
  784. {
  785. ARRAYSTRCPY(pInfo->SubnetMask, rgTmp);
  786. }
  787. }
  788. //
  789. // Now replace the old address list with the new.
  790. //
  791. m_pNlbCfg->SetNetworkAddressesRaw(rgInfo, uCount+1);
  792. }
  793. end:
  794. return;
  795. }
  796. /*** CIPAddressDialog ***/
  797. DWORD
  798. CIPAddressDialog::s_HelpIDs[] =
  799. {
  800. IDC_TEXT_IP_ADDRESS, IDC_EDIT_IP_ADDRESS,
  801. IDC_EDIT_IP_ADDRESS, IDC_EDIT_IP_ADDRESS,
  802. IDC_TEXT_SUBNET_MASK, IDC_EDIT_IP_ADDRESS,
  803. IDC_EDIT_SUBNET_MASK, IDC_EDIT_IP_ADDRESS,
  804. 0, 0
  805. };
  806. BEGIN_MESSAGE_MAP(CIPAddressDialog, CDialog)
  807. ON_EN_SETFOCUS (IDC_EDIT_SUBNET_MASK, OnEditSubnetMask)
  808. ON_WM_HELPINFO()
  809. ON_WM_CONTEXTMENU()
  810. END_MESSAGE_MAP()
  811. CIPAddressDialog::CIPAddressDialog (LPWSTR szIPAddress, LPWSTR szSubnetMask)
  812. : CDialog(CIPAddressDialog::IDD)
  813. {
  814. ZeroMemory(&address, sizeof(address));
  815. /* If an initial IP address was specified, copy it into local storage. */
  816. if (szIPAddress)
  817. wcsncpy(address.IpAddress, szIPAddress, WLBS_MAX_CL_IP_ADDR);
  818. /* If an initial subnet mask was specified, copy it into local storage. */
  819. if (szSubnetMask)
  820. wcsncpy(address.SubnetMask, szSubnetMask, WLBS_MAX_CL_NET_MASK);
  821. }
  822. CIPAddressDialog::~CIPAddressDialog ()
  823. {
  824. }
  825. void CIPAddressDialog::DoDataExchange( CDataExchange* pDX )
  826. {
  827. CDialog::DoDataExchange(pDX);
  828. DDX_Control(pDX, IDC_EDIT_IP_ADDRESS, IPAddress);
  829. DDX_Control(pDX, IDC_EDIT_SUBNET_MASK, SubnetMask);
  830. }
  831. BOOL CIPAddressDialog::OnHelpInfo (HELPINFO* helpInfo )
  832. {
  833. if( helpInfo->iContextType == HELPINFO_WINDOW )
  834. {
  835. ::WinHelp( static_cast<HWND> ( helpInfo->hItemHandle ),
  836. CVY_CTXT_HELP_FILE,
  837. HELP_WM_HELP,
  838. (ULONG_PTR ) s_HelpIDs);
  839. }
  840. return TRUE;
  841. }
  842. void CIPAddressDialog::OnContextMenu( CWnd* pWnd, CPoint point )
  843. {
  844. ::WinHelp( m_hWnd,
  845. CVY_CTXT_HELP_FILE,
  846. HELP_CONTEXTMENU,
  847. (ULONG_PTR ) s_HelpIDs);
  848. }
  849. BOOL CIPAddressDialog::OnInitDialog ()
  850. {
  851. /* Call the base class initialize method. */
  852. BOOL fRet = CDialog::OnInitDialog();
  853. if (fRet)
  854. {
  855. /* Set the valid ranges on each field of the IP address. */
  856. IPAddress.SetFieldRange(0, 1, 223);
  857. IPAddress.SetFieldRange(1, 0, 255);
  858. IPAddress.SetFieldRange(2, 0, 255);
  859. IPAddress.SetFieldRange(3, 0, 255);
  860. /* Set the valid ranges on each field of the subnet mask. */
  861. SubnetMask.SetFieldRange(0, 0, 255);
  862. SubnetMask.SetFieldRange(1, 0, 255);
  863. SubnetMask.SetFieldRange(2, 0, 255);
  864. SubnetMask.SetFieldRange(3, 0, 255);
  865. /* If the IP address is blank, clear the dialog; otherwise, convert
  866. the string to an IP address DWORD and fill in the dialog. */
  867. if (!lstrlen(address.IpAddress))
  868. IPAddress.ClearAddress();
  869. else
  870. IPAddress.SetAddress(WideStringToIPAddress(address.IpAddress));
  871. /* If the subnet mask is blank, clear the dialog; otherwise, convert
  872. the string to an IP address DWORD and fill in the dialog. */
  873. if (!lstrlen(address.SubnetMask))
  874. SubnetMask.ClearAddress();
  875. else
  876. SubnetMask.SetAddress(WideStringToIPAddress(address.SubnetMask));
  877. }
  878. return fRet;
  879. }
  880. /*
  881. * Method: OnEditSubnetMask
  882. * Description: This method is invoked when the focus changes to the
  883. * subnet mask control. If the IP address has been already
  884. * specified and the subnet mask is blank, auto-generate one.
  885. */
  886. void CIPAddressDialog::OnEditSubnetMask ()
  887. {
  888. /* Only if the IP address is NOT blank and the subnet mask IS
  889. blank do we want to auto-generate a subnet mask. */
  890. if (!IPAddress.IsBlank() && SubnetMask.IsBlank()) {
  891. WCHAR wszIPAddress[WLBS_MAX_CL_IP_ADDR + 1];
  892. WCHAR wszSubnetMask[WLBS_MAX_CL_NET_MASK + 1];
  893. DWORD dwIPAddress;
  894. /* Get the IP address from the IP address dialog. */
  895. IPAddress.GetAddress(dwIPAddress);
  896. /* Convert the IP address to a unicode string. */
  897. IPAddressToWideString(dwIPAddress, wszIPAddress);
  898. /* Generate a subnet mask from the class of the given IP address. */
  899. GenerateSubnetMask(wszIPAddress, ASIZE(wszSubnetMask), wszSubnetMask);
  900. /* Fill in the subnet mask dialog with the generated subnet mask. */
  901. SubnetMask.SetAddress(WideStringToIPAddress(wszSubnetMask));
  902. }
  903. }
  904. /*
  905. * Method: On OK
  906. * Description: Called when the user presses OK. If the user presses
  907. * Cancel, no method is called and changes are lost.
  908. */
  909. void CIPAddressDialog::OnOK ()
  910. {
  911. DWORD dwIPAddress;
  912. DWORD dwSubnetMask;
  913. if (IPAddress.IsBlank()) {
  914. /* If the IP address dialog is blank, store an empty
  915. string; if we actually perform a GetAddress call,
  916. it will tell us its 0.0.0.0 and we want to be able
  917. to tell the difference between blank and 0.0.0.0. */
  918. wcsncpy(address.IpAddress, L"", WLBS_MAX_CL_IP_ADDR);
  919. } else {
  920. /* Otherwise, get the IP address DWORD from the control
  921. and convert it to a unicode string. */
  922. IPAddress.GetAddress(dwIPAddress);
  923. IPAddressToWideString(dwIPAddress, address.IpAddress);
  924. }
  925. if (SubnetMask.IsBlank()) {
  926. /* If the subnet mask dialog is blank, store an empty
  927. string; if we actually perform a GetAddress call,
  928. it will tell us its 0.0.0.0 and we want to be able
  929. to tell the difference between blank and 0.0.0.0. */
  930. wcsncpy(address.SubnetMask, L"", WLBS_MAX_CL_NET_MASK);
  931. } else {
  932. /* Otherwise, get the IP address DWORD from the control
  933. and convert it to a unicode string. */
  934. SubnetMask.GetAddress(dwSubnetMask);
  935. IPAddressToWideString(dwSubnetMask, address.SubnetMask);
  936. }
  937. /* Check the validity of the IP address and subnet mask. If
  938. one or both is invalid, throw up an error and don't close
  939. the dialog. */
  940. if (!IsValid(address.IpAddress, address.SubnetMask)) {
  941. ::MessageBox(
  942. NULL,
  943. GETRESOURCEIDSTRING(IDS_INVALID_IP_OR_SUBNET),
  944. GETRESOURCEIDSTRING(IDS_INVALID_INFORMATION),
  945. MB_ICONINFORMATION | MB_OK
  946. );
  947. /* If the IP address is blank, clear the dialog; otherwise, convert
  948. the string to an IP address DWORD and fill in the dialog. */
  949. if (!lstrlen(address.IpAddress))
  950. IPAddress.ClearAddress();
  951. else
  952. IPAddress.SetAddress(WideStringToIPAddress(address.IpAddress));
  953. /* If the subnet mask is blank, clear the dialog; otherwise, convert
  954. the string to an IP address DWORD and fill in the dialog. */
  955. if (!lstrlen(address.SubnetMask))
  956. SubnetMask.ClearAddress();
  957. else
  958. SubnetMask.SetAddress(WideStringToIPAddress(address.SubnetMask));
  959. return;
  960. }
  961. EndDialog(IDOK);
  962. }
  963. /*
  964. * Method:
  965. * Description:
  966. */
  967. DWORD CIPAddressDialog::WideStringToIPAddress (const WCHAR* wszIPAddress)
  968. {
  969. CHAR szIPAddress[MAXIPSTRLEN + 1];
  970. DWORD dwIPAddress;
  971. DWORD dwTemp;
  972. BYTE * pTemp = (BYTE *)&dwTemp;
  973. BYTE * pIPAddress = (BYTE *)&dwIPAddress;
  974. if (!wszIPAddress) return 0;
  975. WideCharToMultiByte(CP_ACP, 0, wszIPAddress, -1, szIPAddress, sizeof(szIPAddress), NULL, NULL);
  976. dwTemp = inet_addr(szIPAddress);
  977. pIPAddress[0] = pTemp[3];
  978. pIPAddress[1] = pTemp[2];
  979. pIPAddress[2] = pTemp[1];
  980. pIPAddress[3] = pTemp[0];
  981. return dwIPAddress;
  982. }
  983. /*
  984. * Method:
  985. * Description:
  986. */
  987. void CIPAddressDialog::IPAddressToWideString (DWORD dwIPAddress, LPWSTR wszIPAddress)
  988. {
  989. CHAR * szIPAddress;
  990. DWORD dwTemp;
  991. BYTE * pTemp = (BYTE *)&dwTemp;
  992. const BYTE * pIPAddress = (const BYTE *)&dwIPAddress;
  993. if (!wszIPAddress) return;
  994. pTemp[0] = pIPAddress[3];
  995. pTemp[1] = pIPAddress[2];
  996. pTemp[2] = pIPAddress[1];
  997. pTemp[3] = pIPAddress[0];
  998. szIPAddress = inet_ntoa(*(struct in_addr *)&dwTemp);
  999. if (!szIPAddress)
  1000. {
  1001. wcsncpy(wszIPAddress, L"", MAXIPSTRLEN);
  1002. return;
  1003. }
  1004. MultiByteToWideChar(CP_ACP, 0, szIPAddress, -1, wszIPAddress, MAXIPSTRLEN + 1);
  1005. }
  1006. /*
  1007. * Method:
  1008. * Description:
  1009. */
  1010. void CIPAddressDialog::GetIPAddressOctets (LPWSTR wszIPAddress, DWORD dwIPAddress[4])
  1011. {
  1012. DWORD dwIP = WideStringToIPAddress(wszIPAddress);
  1013. const BYTE * bp = (const BYTE *)&dwIP;
  1014. dwIPAddress[3] = (DWORD)bp[0];
  1015. dwIPAddress[2] = (DWORD)bp[1];
  1016. dwIPAddress[1] = (DWORD)bp[2];
  1017. dwIPAddress[0] = (DWORD)bp[3];
  1018. }
  1019. /*
  1020. * Method:
  1021. * Description:
  1022. */
  1023. BOOL CIPAddressDialog::IsValid (LPWSTR wszIPAddress, LPWSTR wszSubnetMask)
  1024. {
  1025. BOOL fNoError = TRUE;
  1026. DWORD dwAddr = WideStringToIPAddress(wszIPAddress);
  1027. DWORD dwMask = WideStringToIPAddress(wszSubnetMask);
  1028. if (!IsContiguousSubnetMask(wszSubnetMask))
  1029. return FALSE;
  1030. if (( (dwMask | dwAddr) == 0xFFFFFFFF) // Is the host ID all 1's ?
  1031. || (((~dwMask) & dwAddr) == 0) // Is the host ID all 0's ?
  1032. || ( (dwMask & dwAddr) == 0)) // Is the network ID all 0's ?
  1033. return FALSE;
  1034. DWORD ardwNetID[4];
  1035. DWORD ardwHostID[4];
  1036. DWORD ardwIp[4];
  1037. DWORD ardwMask[4];
  1038. GetIPAddressOctets(wszIPAddress, ardwIp);
  1039. GetIPAddressOctets(wszSubnetMask, ardwMask);
  1040. INT nFirstByte = ardwIp[0] & 0xFF;
  1041. // setup Net ID
  1042. ardwNetID[0] = ardwIp[0] & ardwMask[0] & 0xFF;
  1043. ardwNetID[1] = ardwIp[1] & ardwMask[1] & 0xFF;
  1044. ardwNetID[2] = ardwIp[2] & ardwMask[2] & 0xFF;
  1045. ardwNetID[3] = ardwIp[3] & ardwMask[3] & 0xFF;
  1046. // setup Host ID
  1047. ardwHostID[0] = ardwIp[0] & (~(ardwMask[0]) & 0xFF);
  1048. ardwHostID[1] = ardwIp[1] & (~(ardwMask[1]) & 0xFF);
  1049. ardwHostID[2] = ardwIp[2] & (~(ardwMask[2]) & 0xFF);
  1050. ardwHostID[3] = ardwIp[3] & (~(ardwMask[3]) & 0xFF);
  1051. // check each case
  1052. if( ((nFirstByte & 0xF0) == 0xE0) || // Class D
  1053. ((nFirstByte & 0xF0) == 0xF0) || // Class E
  1054. (ardwNetID[0] == 127) || // NetID cannot be 127...
  1055. ((ardwNetID[0] == 0) && // netid cannot be 0.0.0.0
  1056. (ardwNetID[1] == 0) &&
  1057. (ardwNetID[2] == 0) &&
  1058. (ardwNetID[3] == 0)) ||
  1059. // netid cannot be equal to sub-net mask
  1060. ((ardwNetID[0] == ardwMask[0]) &&
  1061. (ardwNetID[1] == ardwMask[1]) &&
  1062. (ardwNetID[2] == ardwMask[2]) &&
  1063. (ardwNetID[3] == ardwMask[3])) ||
  1064. // hostid cannot be 0.0.0.0
  1065. ((ardwHostID[0] == 0) &&
  1066. (ardwHostID[1] == 0) &&
  1067. (ardwHostID[2] == 0) &&
  1068. (ardwHostID[3] == 0)) ||
  1069. // hostid cannot be 255.255.255.255
  1070. ((ardwHostID[0] == 0xFF) &&
  1071. (ardwHostID[1] == 0xFF) &&
  1072. (ardwHostID[2] == 0xFF) &&
  1073. (ardwHostID[3] == 0xFF)) ||
  1074. // test for all 255
  1075. ((ardwIp[0] == 0xFF) &&
  1076. (ardwIp[1] == 0xFF) &&
  1077. (ardwIp[2] == 0xFF) &&
  1078. (ardwIp[3] == 0xFF)))
  1079. return FALSE;
  1080. return TRUE;
  1081. }
  1082. /*
  1083. * Method:
  1084. * Description:
  1085. */
  1086. BOOL CIPAddressDialog::IsContiguousSubnetMask (LPWSTR wszSubnetMask)
  1087. {
  1088. DWORD dwSubnetMask[4];
  1089. GetIPAddressOctets(wszSubnetMask, dwSubnetMask);
  1090. DWORD dwMask = (dwSubnetMask[0] << 24) + (dwSubnetMask[1] << 16)
  1091. + (dwSubnetMask[2] << 8) + dwSubnetMask[3];
  1092. DWORD i, dwContiguousMask;
  1093. // Find out where the first '1' is in binary going right to left
  1094. dwContiguousMask = 0;
  1095. for (i = 0; i < sizeof(dwMask)*8; i++) {
  1096. dwContiguousMask |= 1 << i;
  1097. if (dwContiguousMask & dwMask)
  1098. break;
  1099. }
  1100. // At this point, dwContiguousMask is 000...0111... If we inverse it,
  1101. // we get a mask that can be or'd with dwMask to fill in all of
  1102. // the holes.
  1103. dwContiguousMask = dwMask | ~dwContiguousMask;
  1104. // If the new mask is different, correct it here
  1105. if (dwMask != dwContiguousMask)
  1106. return FALSE;
  1107. else
  1108. return TRUE;
  1109. }
  1110. /*
  1111. * Method:
  1112. * Description:
  1113. */
  1114. BOOL CIPAddressDialog::GenerateSubnetMask (LPWSTR wszIPAddress,
  1115. UINT cchSubnetMask,
  1116. LPWSTR wszSubnetMask
  1117. )
  1118. {
  1119. DWORD b[4];
  1120. if (swscanf(wszIPAddress, L"%d.%d.%d.%d", b, b+1, b+2, b+3) != EOF)
  1121. {
  1122. if ((b[0] >= 1) && (b[0] <= 126)) {
  1123. b[0] = 255;
  1124. b[1] = 0;
  1125. b[2] = 0;
  1126. b[3] = 0;
  1127. } else if ((b[0] >= 128) && (b[0] <= 191)) {
  1128. b[0] = 255;
  1129. b[1] = 255;
  1130. b[2] = 0;
  1131. b[3] = 0;
  1132. } else if ((b[0] >= 192) && (b[0] <= 223)) {
  1133. b[0] = 255;
  1134. b[1] = 255;
  1135. b[2] = 255;
  1136. b[3] = 0;
  1137. } else {
  1138. b[0] = 0;
  1139. b[1] = 0;
  1140. b[2] = 0;
  1141. b[3] = 0;
  1142. }
  1143. }
  1144. else
  1145. {
  1146. b[0] = 0;
  1147. b[1] = 0;
  1148. b[2] = 0;
  1149. b[3] = 0;
  1150. }
  1151. StringCchPrintf(
  1152. wszSubnetMask,
  1153. cchSubnetMask,
  1154. L"%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
  1155. return((b[0] + b[1] + b[2] + b[3]) > 0);
  1156. }