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.

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