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.

745 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1998
  6. //
  7. // File: ipeditor.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // ipeditor.cpp : implementation file
  11. //
  12. #include "preDNSsn.h"
  13. #include <SnapBase.h>
  14. #include "dnsutil.h"
  15. #include "dnssnap.h"
  16. #include "snapdata.h"
  17. #include "server.h"
  18. #include "ipeditor.h"
  19. #ifdef DEBUG_ALLOCATOR
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. #endif
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CIPListBox
  28. BEGIN_MESSAGE_MAP(CIPListBox, CListBox)
  29. //{{AFX_MSG_MAP(CIPListBox)
  30. ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelChange)
  31. //}}AFX_MSG_MAP
  32. END_MESSAGE_MAP()
  33. BOOL CIPListBox::OnAdd(DWORD dwIpAddr)
  34. {
  35. if (FindIndexOfIpAddr(dwIpAddr) != -1)
  36. return FALSE;
  37. int nCount = GetCount();
  38. CString szIpAddr;
  39. FormatIpAddress(szIpAddr, dwIpAddr);
  40. InsertString(nCount, szIpAddr);
  41. SetItemData(nCount,dwIpAddr);
  42. return TRUE;
  43. }
  44. BOOL CIPListBox::OnAddEx(DWORD dwIpAddr, LPCTSTR lpszServerName)
  45. {
  46. if (FindIndexOfIpAddr(dwIpAddr) != -1)
  47. return FALSE;
  48. int nCount = GetCount();
  49. // NTRAID#NTBUG9-697838-2002/08/30-artm
  50. // '?' moved to resource file where it can be localized if needed
  51. CString serverNameNotAvailable;
  52. if (!serverNameNotAvailable.LoadString(IDS_QUESTION_MARK))
  53. {
  54. return FALSE;
  55. }
  56. USES_CONVERSION;
  57. CString s;
  58. s.Format(_T("%d.%d.%d.%d (%s)"),
  59. IP_STRING_FMT_ARGS(dwIpAddr),
  60. (lpszServerName != NULL) ? lpszServerName : serverNameNotAvailable);
  61. InsertString(nCount, s);
  62. SetItemData(nCount,dwIpAddr);
  63. return TRUE;
  64. }
  65. void CIPListBox::OnRemove(DWORD* pdwIpAddr)
  66. {
  67. int nSel = GetCurSel();
  68. int nCount = GetCount();
  69. ASSERT(nSel >= 0);
  70. ASSERT(nSel < nCount);
  71. // get item data to return and remove item
  72. *pdwIpAddr = static_cast<DWORD>(GetItemData(nSel));
  73. DeleteString(nSel);
  74. // reset the selection
  75. if (nSel == nCount-1) // deleted the last position in the list
  76. SetCurSel(nSel-1); // move up one line (might get to -1)
  77. else
  78. SetCurSel(nSel); // stay on the same line
  79. }
  80. void CIPListBox::OnUp()
  81. {
  82. int nSel = GetCurSel();
  83. ASSERT(nSel > 0);
  84. ASSERT(nSel < GetCount());
  85. // save selection
  86. CString s;
  87. GetText(nSel,s);
  88. DWORD x = static_cast<DWORD>(GetItemData(nSel));
  89. // delete selection
  90. DeleteString(nSel);
  91. // insert back
  92. InsertString(nSel-1,s);
  93. SetItemData(nSel-1,x);
  94. SetCurSel(nSel-1);
  95. }
  96. void CIPListBox::OnDown()
  97. {
  98. int nSel = GetCurSel();
  99. ASSERT(nSel >= 0);
  100. ASSERT(nSel < GetCount()-1);
  101. // save selection
  102. CString s;
  103. GetText(nSel,s);
  104. DWORD x = static_cast<DWORD>(GetItemData(nSel));
  105. // delete selection
  106. DeleteString(nSel);
  107. // insert back
  108. InsertString(nSel+1,s);
  109. SetItemData(nSel+1,x);
  110. SetCurSel(nSel+1);
  111. }
  112. void CIPListBox::OnSelChange()
  113. {
  114. m_pEditor->OnListBoxSelChange();
  115. }
  116. void CIPListBox::UpdateHorizontalExtent()
  117. {
  118. int nHorzExtent = 0;
  119. CClientDC dc(this);
  120. int nItems = GetCount();
  121. for (int i=0; i < nItems; i++)
  122. {
  123. TEXTMETRIC tm;
  124. VERIFY(dc.GetTextMetrics(&tm));
  125. CString szBuffer;
  126. GetText(i, szBuffer);
  127. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  128. nHorzExtent = max(ext.cx ,nHorzExtent);
  129. }
  130. SetHorizontalExtent(nHorzExtent);
  131. }
  132. int CIPListBox::FindIndexOfIpAddr(DWORD dwIpAddr)
  133. {
  134. int nItems = GetCount();
  135. for (int i=0; i < nItems; i++)
  136. {
  137. DWORD x = static_cast<DWORD>(GetItemData(i));
  138. if (x == dwIpAddr)
  139. return i;
  140. }
  141. return -1; // not found
  142. }
  143. /////////////////////////////////////////////////////////////////////////////
  144. // CIPEdit
  145. BEGIN_MESSAGE_MAP(CIPEdit, CDNSIPv4Control)
  146. //{{AFX_MSG_MAP(CIPEdit)
  147. ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
  148. //}}AFX_MSG_MAP
  149. END_MESSAGE_MAP()
  150. void CIPEdit::OnChange()
  151. {
  152. m_pEditor->OnEditChange();
  153. }
  154. /////////////////////////////////////////////////////////////////////////////
  155. // CMyButton
  156. BEGIN_MESSAGE_MAP(CMyButton, CButton)
  157. //{{AFX_MSG_MAP(CMyButton)
  158. ON_CONTROL_REFLECT(BN_CLICKED, OnClicked)
  159. //}}AFX_MSG_MAP
  160. END_MESSAGE_MAP()
  161. void CMyButton::OnClicked()
  162. {
  163. m_pEditor->OnButtonClicked(this);
  164. }
  165. /////////////////////////////////////////////////////////////////////////////
  166. // CIPEditor
  167. BOOL CIPEditor::Initialize(CWnd* pParentWnd,
  168. CWnd* pControlWnd,
  169. UINT nIDBtnUp, UINT nIDBtnDown,
  170. UINT nIDBtnAdd, UINT nIDBtnRemove,
  171. UINT nIDIPCtrl, UINT nIDIPListBox)
  172. {
  173. ASSERT(pParentWnd != NULL);
  174. if (pParentWnd == NULL)
  175. return FALSE;
  176. m_pParentWnd = pParentWnd;
  177. if (pControlWnd == NULL)
  178. {
  179. m_pControlWnd = pParentWnd;
  180. }
  181. else
  182. {
  183. m_pControlWnd = pControlWnd;
  184. }
  185. // set back pointers
  186. m_upButton.SetEditor(this);
  187. m_removeButton.SetEditor(this);
  188. m_downButton.SetEditor(this);
  189. m_addButton.SetEditor(this);
  190. m_edit.SetEditor(this);
  191. m_listBox.SetEditor(this);
  192. // sublclass buttons
  193. BOOL bRes = m_upButton.SubclassDlgItem(nIDBtnUp, m_pParentWnd);
  194. ASSERT(bRes);
  195. if (!bRes) return FALSE;
  196. bRes = m_removeButton.SubclassDlgItem(nIDBtnRemove, m_pParentWnd);
  197. ASSERT(bRes);
  198. if (!bRes) return FALSE;
  199. bRes = m_downButton.SubclassDlgItem(nIDBtnDown, m_pParentWnd);
  200. ASSERT(bRes);
  201. if (!bRes) return FALSE;
  202. bRes = m_addButton.SubclassDlgItem(nIDBtnAdd, m_pParentWnd);
  203. // subclass listbox
  204. ASSERT(bRes);
  205. if (!bRes) return FALSE;
  206. bRes = m_listBox.SubclassDlgItem(nIDIPListBox, m_pParentWnd);
  207. // sublclass edit control
  208. bRes = m_edit.SubclassDlgItem(nIDIPCtrl, m_pParentWnd);
  209. ASSERT(bRes);
  210. if (!bRes) return FALSE;
  211. //m_edit.SetAlertFunction(CDNSMaskCtrl::AlertFunc);
  212. if (m_bNoUpDown)
  213. {
  214. m_upButton.ShowWindow(FALSE);
  215. m_upButton.EnableWindow(FALSE);
  216. m_downButton.ShowWindow(FALSE);
  217. m_downButton.EnableWindow(FALSE);
  218. }
  219. LRESULT lDefID = SendMessage(m_addButton.GetParent()->GetSafeHwnd(), DM_GETDEFID, 0, 0);
  220. if (lDefID != 0)
  221. {
  222. m_nDefID = LOWORD(lDefID);
  223. }
  224. return bRes;
  225. }
  226. BOOL CIPEditor::OnButtonClicked(CMyButton* pButton)
  227. {
  228. BOOL bRet = TRUE;
  229. if (pButton == &m_upButton)
  230. {
  231. if (m_bNoUpDown)
  232. {
  233. return TRUE;
  234. }
  235. m_listBox.OnUp();
  236. SetButtonsState();
  237. OnChangeData();
  238. }
  239. else if (pButton == &m_downButton)
  240. {
  241. if (m_bNoUpDown)
  242. {
  243. return TRUE;
  244. }
  245. m_listBox.OnDown();
  246. SetButtonsState();
  247. OnChangeData();
  248. }
  249. else if (pButton == &m_addButton)
  250. {
  251. DWORD dwIpAddr;
  252. m_edit.GetIPv4Val(&dwIpAddr);
  253. if (m_listBox.OnAdd(dwIpAddr))
  254. {
  255. SetButtonsState();
  256. m_edit.Clear();
  257. m_edit.SetFocusField(0);
  258. OnChangeData();
  259. m_listBox.UpdateHorizontalExtent();
  260. }
  261. else
  262. {
  263. // if already there, cleard edit but do not add
  264. m_edit.Clear();
  265. m_edit.SetFocusField(0);
  266. bRet = FALSE;
  267. }
  268. }
  269. else if (pButton == &m_removeButton)
  270. {
  271. DWORD dwIpAddr;
  272. m_listBox.OnRemove(&dwIpAddr);
  273. SetButtonsState();
  274. m_edit.SetIPv4Val(dwIpAddr);
  275. OnChangeData();
  276. m_listBox.UpdateHorizontalExtent();
  277. }
  278. else
  279. {
  280. bRet = FALSE;
  281. }
  282. return bRet;
  283. }
  284. void CIPEditor::OnEditChange()
  285. {
  286. BOOL bEnable = !m_edit.IsEmpty();
  287. CWnd* pFocus = CWnd::GetFocus();
  288. if ( !bEnable && (pFocus == &m_addButton))
  289. {
  290. m_edit.SetFocus();
  291. }
  292. if (bEnable)
  293. {
  294. m_addButton.EnableWindow(TRUE);
  295. //
  296. // Set the add button as the default push button
  297. //
  298. SendMessage(GetParentWnd()->GetSafeHwnd(), DM_SETDEFID, (WPARAM)m_addButton.GetDlgCtrlID(), 0);
  299. //
  300. // Force the Add button to redraw itself
  301. //
  302. SendMessage(m_addButton.GetSafeHwnd(),
  303. BM_SETSTYLE,
  304. BS_DEFPUSHBUTTON,
  305. MAKELPARAM(TRUE, 0));
  306. //
  307. // Force the previous default button to redraw itself
  308. //
  309. SendDlgItemMessage(m_pControlWnd->GetSafeHwnd(),
  310. m_nDefID,
  311. BM_SETSTYLE,
  312. BS_PUSHBUTTON,
  313. MAKELPARAM(TRUE, 0));
  314. }
  315. else
  316. {
  317. //
  318. // Set the previous default button back as the default push button
  319. //
  320. SendMessage(m_pControlWnd->GetSafeHwnd(), DM_SETDEFID, (WPARAM)m_nDefID, 0);
  321. //
  322. // Force the previous default button to redraw itself
  323. //
  324. SendMessage(GetDlgItem(m_pControlWnd->GetSafeHwnd(), m_nDefID),
  325. BM_SETSTYLE,
  326. BS_DEFPUSHBUTTON,
  327. MAKELPARAM(TRUE, 0));
  328. //
  329. // Force the Add button to redraw itself
  330. //
  331. SendMessage(m_addButton.GetSafeHwnd(),
  332. BM_SETSTYLE,
  333. BS_PUSHBUTTON,
  334. MAKELPARAM(TRUE, 0));
  335. m_addButton.EnableWindow(FALSE);
  336. }
  337. }
  338. void CIPEditor::AddAddresses(DWORD* pArr, int nArraySize)
  339. {
  340. ASSERT(nArraySize > 0);
  341. for (int i=0; i<nArraySize; i++)
  342. {
  343. m_listBox.OnAdd(pArr[i]);
  344. }
  345. m_listBox.SetCurSel((m_listBox.GetCount() > 0) ? 0 : -1);
  346. SetButtonsState();
  347. OnChangeData();
  348. m_listBox.UpdateHorizontalExtent();
  349. }
  350. void CIPEditor::AddAddresses(DWORD* pArr, LPCTSTR* pStringArr, int nArraySize)
  351. {
  352. ASSERT(nArraySize > 0);
  353. for (int i=0; i<nArraySize; i++)
  354. {
  355. m_listBox.OnAddEx(pArr[i], pStringArr[i]);
  356. }
  357. m_listBox.SetCurSel((m_listBox.GetCount() > 0) ? 0 : -1);
  358. SetButtonsState();
  359. OnChangeData();
  360. m_listBox.UpdateHorizontalExtent();
  361. }
  362. void CIPEditor::GetAddresses(DWORD* pArr, int nArraySize, int* pFilled)
  363. {
  364. ASSERT(nArraySize > 0);
  365. int nCount = m_listBox.GetCount();
  366. ASSERT(nCount <= nArraySize);
  367. *pFilled = (nArraySize > nCount) ? nCount : nArraySize;
  368. for (int i=0; i < (*pFilled); i++)
  369. {
  370. pArr[i] = static_cast<DWORD>(m_listBox.GetItemData(i));
  371. }
  372. }
  373. void CIPEditor::Clear()
  374. {
  375. m_listBox.ResetContent();
  376. m_edit.Clear();
  377. SetButtonsState();
  378. m_listBox.UpdateHorizontalExtent();
  379. }
  380. BOOL CIPEditor::BrowseFromDNSNamespace(CComponentDataObject* pComponentDataObject,
  381. CPropertyPageHolderBase* pHolder,
  382. BOOL bEnableBrowseEdit,
  383. LPCTSTR lpszExcludeServerName)
  384. {
  385. BOOL bRet = TRUE;
  386. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  387. FIX_THREAD_STATE_MFC_BUG();
  388. CThemeContextActivator activator;
  389. CDNSBrowserDlg dlg(pComponentDataObject, pHolder, SERVER,
  390. bEnableBrowseEdit, lpszExcludeServerName);
  391. if (IDOK == dlg.DoModal())
  392. {
  393. //
  394. // First check to see if we can get the server IP address(es) from the node.
  395. //
  396. CDNSServerNode* pServerNode = dynamic_cast<CDNSServerNode*>(dlg.GetSelection());
  397. if (pServerNode != NULL)
  398. {
  399. DWORD dwCount = 0;
  400. PIP_ADDRESS pipServerAddresses = NULL;
  401. pServerNode->GetServerAddressesInfo(&dwCount, &pipServerAddresses);
  402. if (dwCount > 0 && pipServerAddresses != NULL)
  403. {
  404. AddAddresses(pipServerAddresses, dwCount);
  405. return TRUE;
  406. }
  407. }
  408. //
  409. // If we didn't get the IP address(es) from the node, then try the name
  410. //
  411. LPCTSTR lpszServerName = dlg.GetSelectionString();
  412. //
  413. // try to see if the name is already an IP address
  414. //
  415. IP_ADDRESS ipAddr = IPStringToAddr(lpszServerName);
  416. if (ipAddr != INADDR_NONE)
  417. {
  418. AddAddresses(&ipAddr, 1);
  419. return bRet; // it was a valid IP address, just converted
  420. }
  421. //
  422. // it was not an IP address, so try to query for all
  423. // the A records for the server name
  424. //
  425. PDNS_RECORD pARecordList;
  426. DNS_STATUS dwErr = ::DnsQuery((LPTSTR)lpszServerName,
  427. DNS_TYPE_A,
  428. DNS_QUERY_STANDARD,
  429. NULL, &pARecordList, NULL);
  430. int nIPCountFromARec = 0;
  431. PDNS_RECORD pTemp = NULL;
  432. if (dwErr != 0)
  433. {
  434. bRet = FALSE;
  435. }
  436. else
  437. {
  438. pTemp = pARecordList;
  439. while (pTemp != NULL)
  440. {
  441. nIPCountFromARec++;
  442. pTemp = pTemp->pNext;
  443. }
  444. bRet = (nIPCountFromARec > 0);
  445. }
  446. if (!bRet)
  447. {
  448. if (pARecordList != NULL)
  449. ::DnsRecordListFree(pARecordList, DnsFreeRecordListDeep);
  450. return FALSE; // could not do resolution
  451. }
  452. // get the IP addresses from the A record list
  453. // and add them to the IP editor.
  454. // build an array of IP addresses to pass to the IP editor
  455. IP_ADDRESS* ipArray = (IP_ADDRESS*)malloc(nIPCountFromARec*sizeof(IP_ADDRESS));
  456. if (!ipArray)
  457. {
  458. return FALSE;
  459. }
  460. //scan the array of lists of A records we just found
  461. PIP_ADDRESS pCurrAddr = ipArray;
  462. pTemp = pARecordList;
  463. while (pTemp != NULL)
  464. {
  465. CString szTemp;
  466. FormatIpAddress(szTemp, pTemp->Data.A.IpAddress);
  467. TRACE(_T("found address = %s\n"), (LPCTSTR)szTemp);
  468. *pCurrAddr = pTemp->Data.A.IpAddress;
  469. pTemp = pTemp->pNext;
  470. pCurrAddr++;
  471. }
  472. // fill in the array if server names (all the same value, IP's of same host)
  473. LPCTSTR* lpszServerNameArr = (LPCTSTR*)malloc(sizeof(LPCTSTR)*nIPCountFromARec);
  474. if (lpszServerNameArr)
  475. {
  476. for (int i=0; i< nIPCountFromARec; i++)
  477. lpszServerNameArr[i] = lpszServerName;
  478. // add to the editor
  479. AddAddresses(ipArray, lpszServerNameArr, nIPCountFromARec);
  480. }
  481. ASSERT(pARecordList != NULL);
  482. ::DnsRecordListFree(pARecordList, DnsFreeRecordListDeep);
  483. if (ipArray)
  484. {
  485. free(ipArray);
  486. ipArray = 0;
  487. }
  488. if (lpszServerNameArr)
  489. {
  490. free(lpszServerNameArr);
  491. lpszServerNameArr = 0;
  492. }
  493. }
  494. return bRet;
  495. }
  496. void CIPEditor::FindNames()
  497. {
  498. int nCount = GetCount();
  499. if (nCount == 0)
  500. return;
  501. // retrieve an array of IP addresses
  502. DWORD* pIpArr = (DWORD*)malloc(sizeof(DWORD)*nCount);
  503. if (!pIpArr)
  504. {
  505. return;
  506. }
  507. LPCTSTR* lpszServerNameArr = 0;
  508. PDNS_RECORD* pPTRRecordListArr = 0;
  509. do // false loop
  510. {
  511. int nFilled;
  512. GetAddresses(pIpArr, nCount, &nFilled);
  513. ASSERT(nFilled == nCount);
  514. // try IP to host name resoulution
  515. lpszServerNameArr = (LPCTSTR*)malloc(sizeof(LPCTSTR)*nCount);
  516. if (!lpszServerNameArr)
  517. {
  518. break;
  519. }
  520. memset(lpszServerNameArr, 0x0, sizeof(LPCTSTR)*nCount);
  521. pPTRRecordListArr = (PDNS_RECORD*)malloc(sizeof(PDNS_RECORD)*nCount);
  522. if (!pPTRRecordListArr)
  523. {
  524. break;
  525. }
  526. memset(pPTRRecordListArr, 0x0, sizeof(PDNS_RECORD)*nCount);
  527. USES_CONVERSION;
  528. for (int k=0; k<nCount; k++)
  529. {
  530. // get the name of the PTR record
  531. CString szIpAddress;
  532. FormatIpAddress(szIpAddress, pIpArr[k]); // e.g. "157.55.89.116"
  533. ReverseIPString(szIpAddress.GetBuffer(1)); // e.g. "116.89.55.157"
  534. szIpAddress += INADDR_ARPA_SUFFIX; // e.g. "116.89.55.157.in-addr.arpa"
  535. DNS_STATUS dwErr = ::DnsQuery((LPTSTR)(LPCTSTR)szIpAddress,
  536. DNS_TYPE_PTR,
  537. DNS_QUERY_STANDARD,
  538. NULL, &pPTRRecordListArr[k], NULL);
  539. if (dwErr == 0)
  540. {
  541. DWORD nPTRCount = 0;
  542. PDNS_RECORD pTemp = pPTRRecordListArr[k];
  543. while (pTemp != NULL)
  544. {
  545. nPTRCount++;
  546. pTemp = pTemp->pNext;
  547. }
  548. ASSERT(nPTRCount >= 1); // getting multiple host names for a given IP address?
  549. lpszServerNameArr[k] = pPTRRecordListArr[k]->Data.PTR.pNameHost;
  550. }
  551. }
  552. // remove the old entries and add the new ones
  553. int nSel = m_listBox.GetCurSel();
  554. Clear();
  555. AddAddresses(pIpArr, lpszServerNameArr, nCount);
  556. m_listBox.SetCurSel(nSel);
  557. SetButtonsState();
  558. // free memory from DnsQuery()
  559. for (k=0; k<nCount; k++)
  560. {
  561. if(pPTRRecordListArr[k] != NULL)
  562. {
  563. ::DnsRecordListFree(pPTRRecordListArr[k], DnsFreeRecordListDeep);
  564. }
  565. }
  566. } while (false);
  567. if (pIpArr)
  568. {
  569. free(pIpArr);
  570. pIpArr = 0;
  571. }
  572. if (lpszServerNameArr)
  573. {
  574. free(lpszServerNameArr);
  575. lpszServerNameArr = 0;
  576. }
  577. if (pPTRRecordListArr)
  578. {
  579. free(pPTRRecordListArr);
  580. pPTRRecordListArr = 0;
  581. }
  582. }
  583. void CIPEditor::EnableUI(BOOL bEnable, BOOL bListBoxAlwaysEnabled)
  584. {
  585. // cache the value, needed on listbox selections notifications
  586. m_bUIEnabled = bEnable;
  587. m_upButton.EnableWindow(bEnable);
  588. m_removeButton.EnableWindow(bEnable);
  589. m_downButton.EnableWindow(bEnable);
  590. if (bEnable)
  591. m_addButton.EnableWindow(!m_edit.IsEmpty());
  592. else
  593. m_addButton.EnableWindow(FALSE);
  594. m_edit.EnableWindow(bEnable);
  595. if (!bListBoxAlwaysEnabled)
  596. m_listBox.EnableWindow(bEnable);
  597. if (bEnable)
  598. SetButtonsState();
  599. }
  600. void CIPEditor::ShowUI(BOOL bShow)
  601. {
  602. m_upButton.ShowWindow(bShow);
  603. m_removeButton.ShowWindow(bShow);
  604. m_downButton.ShowWindow(bShow);
  605. m_addButton.ShowWindow(bShow);
  606. m_edit.ShowWindow(bShow);
  607. m_listBox.ShowWindow(bShow);
  608. EnableUI(bShow);
  609. }
  610. void CIPEditor::SetButtonsState()
  611. {
  612. if (!m_bUIEnabled)
  613. return;
  614. int nSel = m_listBox.GetCurSel();
  615. int nCount = m_listBox.GetCount();
  616. CWnd* pFocus = CWnd::GetFocus();
  617. // must have item selected to remove
  618. BOOL bEnable = nSel != -1;
  619. if (!bEnable && (pFocus == &m_removeButton))
  620. {
  621. m_edit.SetFocus();
  622. }
  623. m_removeButton.EnableWindow(bEnable);
  624. if (m_bNoUpDown)
  625. return;
  626. // must have item selected not at the to to move it up
  627. bEnable = nSel > 0;
  628. if (!bEnable && (pFocus == &m_upButton))
  629. {
  630. m_edit.SetFocus();
  631. }
  632. m_upButton.EnableWindow(bEnable);
  633. // must have intem selected not at the bottom to move it down
  634. bEnable = (nSel >= 0) && (nSel < nCount-1);
  635. if (!bEnable && (pFocus == &m_downButton))
  636. {
  637. m_edit.SetFocus();
  638. }
  639. m_downButton.EnableWindow(bEnable);
  640. }