ipaddr.cpp
上传用户:qxsjcl
上传日期:2007-01-08
资源大小:263k
文件大小:21k
源码类别:

网络截获/分析

开发平台:

Visual C++

  1. #pragma title("IP Address Custom Control Implementation")
  2. // Created by Joseph A. Dziedzic, September 1997
  3. // Revised April 1998
  4. // Thanks to Dan Anderson, Kenny Goers, Kevin Lussier, and Doug Miller for their suggestions
  5. // and code enhancements.
  6. // Mail comments to dziedzic@ma.ultranet.com
  7. #include "stdafx.h"
  8. #include "IPAddr.h"
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14. // Style bits for the individual edit controls
  15. const int WS_EDIT = WS_CHILD | WS_VISIBLE | ES_CENTER | ES_MULTILINE;
  16. const TCHAR szDialogClass[] = _T("#32770"); // Special window class for dialogs
  17. BOOL CIPAddrCtl::m_bRegistered = Register(); // Register the control during class initialization
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CIPAddrCtl
  20. IMPLEMENT_DYNCREATE(CIPAddrCtl, CWnd)
  21. CIPAddrCtl::CIPAddrCtl()
  22. {
  23. m_bEnabled = TRUE; // Window enabled flag (TRUE by default)
  24. m_bReadOnly = FALSE; // Read only flag (FALSE by default)
  25. m_bNoValidate = FALSE; // Don't do immediate field validation on input
  26. }
  27. CIPAddrCtl::~CIPAddrCtl()
  28. {
  29. }
  30. BEGIN_MESSAGE_MAP(CIPAddrCtl, CWnd)
  31. //{{AFX_MSG_MAP(CIPAddrCtl)
  32. ON_WM_CREATE()
  33. ON_WM_NCDESTROY()
  34. ON_WM_SIZE()
  35. ON_WM_SETFOCUS()
  36. ON_WM_PAINT()
  37. ON_WM_ENABLE()
  38. ON_WM_ERASEBKGND()
  39. ON_MESSAGE(WM_SETFONT, OnSetFont)
  40. ON_MESSAGE(IPAM_GETADDRESS, OnGetAddress)
  41. ON_MESSAGE(IPAM_SETADDRESS, OnSetAddress)
  42. ON_MESSAGE(IPAM_SETREADONLY, OnSetReadOnly)
  43. //}}AFX_MSG_MAP
  44. END_MESSAGE_MAP()
  45. /////////////////////////////////////////////////////////////////////////////
  46. // CIPAddrCtl message handlers
  47. BOOL CIPAddrCtl::Register()
  48. {
  49. // Register the window class of the control
  50. WNDCLASS wc;
  51. wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW; // Usual style bits
  52. wc.lpfnWndProc = IPAddrWndProc; // Message processing code
  53. wc.cbClsExtra = 0; // No extra bytes needed
  54. wc.cbWndExtra = 0;
  55. wc.hInstance = NULL; // No instance handle
  56. wc.hIcon = NULL; // No icon
  57. wc.hCursor = ::LoadCursor(NULL, IDC_IBEAM); // Use I-beam cursor (like edit control)
  58. wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); // Use default window color (overriden in OnEraseBkgnd)
  59. wc.lpszMenuName = NULL; // No menus
  60. wc.lpszClassName = _T("IPAddr"); // Class name
  61. if (!::RegisterClass(&wc)) // If registration failed, subsequent dialogs will fail
  62. {
  63. ASSERT(FALSE);
  64. return FALSE;
  65. }
  66. else
  67. return TRUE;
  68. }
  69. BOOL CIPAddrCtl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwExStyle/*=0*/)
  70. {
  71. // Create a window class that has the properties we want
  72. CString szWndClass = AfxRegisterWndClass(CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW,
  73. ::LoadCursor(NULL, IDC_IBEAM), (HBRUSH) COLOR_WINDOW+1);
  74. // Create using the extended window style
  75. #if _MSC_VER >= 1100
  76. // Original VC 5.0 stuff
  77. return CWnd::CreateEx(dwExStyle, szWndClass, NULL, dwStyle, rect, pParentWnd, nID);
  78. #else
  79. // Back ported to VC 4.2
  80. return CWnd::CreateEx(dwExStyle, szWndClass, NULL, dwStyle,
  81. rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
  82. pParentWnd->GetSafeHwnd(), (HMENU) nID);
  83. #endif
  84. }
  85. LRESULT CALLBACK IPAddrWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  86. {
  87. switch (uiMsg) // Dispatch on message type
  88. {
  89. case WM_NCCREATE: // On WM_NCCREATE we create a C++ object and attach it to the control
  90. {
  91. CIPAddrCtl* pCtl = new CIPAddrCtl; // Create an instance of the class
  92. ASSERT(pCtl); // Better not fail!
  93. BOOL b = pCtl->SubclassWindow(hWnd); // Attach the window handle to the new object
  94. ASSERT(b); // Better not fail!
  95. return b; // Return result to continue/abort window creation
  96. break;
  97. }
  98. default: // All other messages go through default window processor
  99. return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
  100. }
  101. }
  102. int CIPAddrCtl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  103. {
  104. if (CWnd::OnCreate(lpCreateStruct) == -1)
  105. return -1;
  106. // Save the "no immediate validation on input" style setting
  107. m_bNoValidate = (lpCreateStruct->style & IPAS_NOVALIDATE);
  108. // Set the styles for the parent control
  109. ModifyStyleEx(0, WS_EX_CLIENTEDGE | WS_EX_NOPARENTNOTIFY);
  110. // Create the four edit controls used to obtain the four parts of the IP address (size
  111. // of controls gets set during OnSize)
  112. for (int ii = 0; ii < 4; ii++)
  113. {
  114. m_Addr[ii].Create(WS_EDIT, CRect(0,0,0,0), this, IDC_ADDR1 + ii);
  115. m_Addr[ii].LimitText(3);
  116. m_Addr[ii].SetParent(this);
  117. }
  118. return 0;
  119. }
  120. void CIPAddrCtl::OnNcDestroy() 
  121. {
  122. CWnd::OnNcDestroy();
  123. // Make sure the window was destroyed
  124. ASSERT(NULL == m_hWnd);
  125. // Destroy this object since it won't be destroyed otherwise
  126. delete this;
  127. }
  128. void CIPAddrCtl::OnSize(UINT nType, int cx, int cy) 
  129. {
  130. CWnd::OnSize(nType, cx, cy);
  131. // Get the width of a "." drawn in the control
  132. CDC* pDC = GetDC();
  133. CSize szDot = pDC->GetTextExtent(_T("."), 1);
  134. int nDotWidth = szDot.cx;
  135. ReleaseDC(pDC);
  136. // Based on the size of the parent window, compute the width & height of the edit
  137. // controls.  Leave room for the three "." which will be drawn on the parent window
  138. // to separate the four parts of the IP address.
  139. CRect rcClient;
  140. GetClientRect(&rcClient);
  141. int nEditWidth = (rcClient.Width() - (3 * nDotWidth)) / 4;
  142. int nEditHeight = rcClient.Height();
  143. int cyEdge = ::GetSystemMetrics(SM_CYEDGE);
  144. // Compute rectangles for the edit controls, then move the controls into place
  145. CRect rect = CRect(0, cyEdge, nEditWidth, nEditHeight);
  146. for (int ii = 0; ii < 4; ii++)
  147. {
  148. m_rcAddr[ii] = rect;
  149. m_Addr[ii].MoveWindow(rect);
  150. rect.OffsetRect(nEditWidth + nDotWidth, 0);
  151. }
  152. rect = CRect(nEditWidth, 0, nEditWidth + nDotWidth, nEditHeight);
  153. for (ii = 0; ii < 3; ii++)
  154. {
  155. m_rcDot[ii] = rect;
  156. rect.OffsetRect(nEditWidth + nDotWidth, 0);
  157. }
  158. }
  159. void CIPAddrCtl::OnSetFocus(CWnd* pOldWnd) 
  160. {
  161. CWnd::OnSetFocus(pOldWnd);
  162. m_Addr[0].SetFocus(); // Set focus to first edit control
  163. m_Addr[0].SetSel(0, -1); // Select entire contents
  164. }
  165. // Protected function called by the edit control (friend class) when it receives a
  166. // character which should be processed by the parent
  167. void CIPAddrCtl::OnChildChar(UINT nChar, UINT nRepCnt, UINT nFlags, CIPAddrEdit& child)
  168. {
  169. switch (nChar)
  170. {
  171. case '.': // Dot means advance to next edit control (if in first 3)
  172. case VK_RIGHT: // Ditto for right arrow at end of text
  173. case ' ': // Ditto for space
  174. {
  175. UINT nIDC = child.GetDlgCtrlID(); // Get control ID of the edit control
  176. if (nIDC < IDC_ADDR4) // Move focus to appropriate edit control and select entire contents
  177. {
  178. m_Addr[nIDC - IDC_ADDR1 + 1].SetFocus();
  179. if (VK_RIGHT != nChar) // Re-select text unless arrow key entered
  180. m_Addr[nIDC - IDC_ADDR1 + 1].SetSel(0, -1);
  181. }
  182. break;
  183. }
  184. case VK_LEFT: // Left arrow means move to previous edit control (if in last 3)
  185. {
  186. UINT nIDC = child.GetDlgCtrlID(); // Get control ID of the edit control
  187. if (nIDC > IDC_ADDR1) // Move focus to appropriate edit control
  188. m_Addr[nIDC - IDC_ADDR1 - 1].SetFocus();
  189. break;
  190. }
  191. case VK_TAB: // Tab moves between controls in the dialog
  192. {
  193. CWnd* pWnd;
  194. SHORT nShift = ::GetKeyState(VK_SHIFT); // Get state of shift key
  195. if (nShift < 0)
  196. pWnd = GetParent()->GetNextDlgTabItem(this, TRUE);
  197. else
  198. pWnd = GetParent()->GetNextDlgTabItem(this, FALSE);
  199. if (NULL != pWnd) // If there's a control, set focus to it
  200. pWnd->SetFocus();
  201. break;
  202. }
  203. case VK_RETURN: // Return implies default pushbutton press
  204. {
  205. DWORD dw = ((CDialog*) GetParent())->GetDefID(); // Get ID of default pushbutton
  206. if (DC_HASDEFID == HIWORD(dw)) // If there is a default pushbutton, simulate pressing it
  207. {
  208. CWnd* pWnd = GetParent()->GetDlgItem(LOWORD(dw)); // Get the control
  209. WPARAM wp = MAKEWPARAM(LOWORD(dw), BN_CLICKED); // Build wParam for WM_COMMAND
  210. GetParent()->SendMessage(WM_COMMAND, wp, (LPARAM) pWnd->m_hWnd); // Fake like button was pressed
  211. }
  212. }
  213. break;
  214. case '-': // "Field full" indication
  215. // Validate the contents for proper values (unless suppressed)
  216. if (!m_bNoValidate) // If not suppressing immediate validation
  217. {
  218. CString szText;
  219. child.GetWindowText(szText); // Get text from edit control
  220. int n = _ttoi(szText); // Get numeric value from edit control
  221. if (n < 0 || n > 255) // If out of range, notify parent
  222. {
  223. szText.Format(_T("%d is not a valid entry.  Please specify a value between 0 and 255 for this field."), n);
  224. MessageBox(szText, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
  225. child.SetFocus(); // Set focus to offending field
  226. child.SetSel(0, -1); // Select all text
  227. return;
  228. }
  229. }
  230. // Advance to next field
  231. OnChildChar('.', 0, nFlags, child);
  232. break;
  233. default:
  234. TRACE(_T("Unexpected call to CIPAddrCtl::OnChildChar!n"));
  235. }
  236. }
  237. void CIPAddrCtl::OnPaint() 
  238. {
  239. CPaintDC dc(this); // device context for painting
  240. // Save mode and set to transparent (so background remains)
  241. int nOldMode = dc.SetBkMode(TRANSPARENT);
  242. // If disabled, set text color to COLOR_GRAYTEXT, else use COLOR_WINDOWTEXT
  243. COLORREF crText;
  244. if (m_bEnabled)
  245. crText = ::GetSysColor(COLOR_WINDOWTEXT);
  246. else
  247. crText = ::GetSysColor(COLOR_GRAYTEXT);
  248. COLORREF crOldText = dc.SetTextColor(crText);
  249. // Draw the three "." which separate the four edit controls
  250. for (int ii = 0; ii < 3; ii++)
  251. dc.DrawText(_T("."), 1, m_rcDot[ii], DT_CENTER | DT_SINGLELINE | DT_BOTTOM);
  252. // Restore old mode and color
  253. dc.SetBkMode(nOldMode);
  254. dc.SetTextColor(crOldText);
  255. // Do not call CWnd::OnPaint() for painting messages
  256. }
  257. BOOL CIPAddrCtl::OnEraseBkgnd(CDC* pDC) 
  258. {
  259. CRect rcClient;
  260. GetClientRect(&rcClient);
  261. if (m_bEnabled && !m_bReadOnly)
  262. ::FillRect(pDC->m_hDC, rcClient, (HBRUSH) (COLOR_WINDOW+1));
  263. else
  264. ::FillRect(pDC->m_hDC, rcClient, (HBRUSH) (COLOR_BTNFACE+1));
  265. return TRUE;
  266. }
  267. void CIPAddrCtl::OnEnable(BOOL bEnable) 
  268. {
  269. CWnd::OnEnable(bEnable);
  270. // Nothing to do unless the window state has changed
  271. if (bEnable != m_bEnabled)
  272. {
  273. // Save new state
  274. m_bEnabled = bEnable;
  275. // Adjust child controls appropriately
  276. for (int ii = 0; ii < 4; ii++)
  277. m_Addr[ii].EnableWindow(bEnable);
  278. }
  279. Invalidate();
  280. }
  281. LONG CIPAddrCtl::OnSetFont(UINT wParam, LONG lParam)
  282. {
  283. // Note: font passed on to children, but we don't
  284. // use it, the system font is much nicer for printing
  285. // the dots, since they show up much better
  286. for (int ii = 0; ii < 4; ii++)
  287. m_Addr[ii].SendMessage(WM_SETFONT, wParam, lParam);
  288. return 0;
  289. }
  290. LONG CIPAddrCtl::OnGetAddress(UINT wParam, LONG lParam)
  291. {
  292. BOOL bStatus;
  293. int i, nAddr[4], nInError = 0;
  294. BOOL bPrintErrors = (BOOL) wParam; // Cast wParam as a flag
  295. IPA_ADDR* lpIPAddr = (IPA_ADDR*) lParam; // Cast lParam as an IPA_ADDR structure
  296. if (NULL == lpIPAddr) // If it's a bad pointer, return an error
  297. return FALSE;
  298. memset(lpIPAddr, 0, sizeof(IPA_ADDR)); // Zero out the returned data
  299. // Parse the fields and return an error indication if something bad was detected
  300. for (i = 0; i < 4; i++)
  301. {
  302. bStatus = ParseAddressPart(m_Addr[i], nAddr[i]);
  303. if (!bStatus) // If it failed to parse, quit now
  304. {
  305. nInError = i + 1; // Remember which address part was in error
  306. break; // Break out of for loop
  307. }
  308. }
  309. if (!bStatus) // Error detected during parse?
  310. {
  311. lpIPAddr->nInError = nInError; // Show where it occurred
  312. if (bPrintErrors) // If they want us to print error messages
  313. {
  314. CString szText;
  315. if (nAddr[i] < 0)
  316. szText = _T("Missing value in IP address");
  317. else
  318. szText.Format(_T("%d is not a valid entry.  Please specify a value between 0 and 255 for this field."), nAddr[i]);
  319. MessageBox(szText, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
  320. }
  321. m_Addr[i].SetFocus(); // Set focus to offending byte
  322. m_Addr[i].SetSel(0, -1); // Select entire contents
  323. return FALSE; // Return an error
  324. }
  325. lpIPAddr->nAddr1 = nAddr[0]; // Return the pieces to the caller
  326. lpIPAddr->nAddr2 = nAddr[1];
  327. lpIPAddr->nAddr3 = nAddr[2];
  328. lpIPAddr->nAddr4 = nAddr[3];
  329. lpIPAddr->nInError = 0; // No error to report
  330. return TRUE; // Return success
  331. }
  332. LONG CIPAddrCtl::OnSetAddress(UINT wParam, LONG lParam)
  333. {
  334. CString szText;
  335. IPA_ADDR* lpIPAddr = (IPA_ADDR*) lParam; // Cast lParam as an IPA_ADDR structure
  336. // Format their data and load the edit controls
  337. szText.Format(_T("%u"), lpIPAddr->nAddr1);
  338. m_Addr[0].SetWindowText(szText);
  339. szText.Format(_T("%u"), lpIPAddr->nAddr2);
  340. m_Addr[1].SetWindowText(szText);
  341. szText.Format(_T("%u"), lpIPAddr->nAddr3);
  342. m_Addr[2].SetWindowText(szText);
  343. szText.Format(_T("%u"), lpIPAddr->nAddr4);
  344. m_Addr[3].SetWindowText(szText);
  345. return TRUE;
  346. }
  347. LONG CIPAddrCtl::OnSetReadOnly(UINT wParam, LONG lParam)
  348. {
  349. m_bReadOnly = (BOOL) wParam;
  350. for (int ii = 0; ii < 4; ii++)
  351. m_Addr[ii].SetReadOnly(m_bReadOnly);
  352. Invalidate();
  353. return TRUE;
  354. }
  355. BOOL CIPAddrCtl::ParseAddressPart(CEdit& edit, int& n)
  356. {
  357. CString szText;
  358. edit.GetWindowText(szText); // Get text from edit control
  359. if (szText.IsEmpty()) // Empty text is an error
  360. {
  361. n = -1; // Return bogus value
  362. return FALSE; // Return parse failure to caller
  363. }
  364. n = _ttoi(szText); // Grab a decimal value from edit text
  365. if (n < 0 || n > 255) // If it is out of range, return an error
  366. return FALSE;
  367. return TRUE; // Looks acceptable, return success
  368. }
  369. CIPAddrEdit* CIPAddrCtl::GetEditControl(int nIndex)
  370. {
  371. if (nIndex < 1 || nIndex > 4)
  372. return NULL;
  373. return &m_Addr[nIndex - 1];
  374. }
  375. /////////////////////////////////////////////////////////////////////////////
  376. // CIPAddrEdit
  377. CIPAddrEdit::CIPAddrEdit()
  378. {
  379. }
  380. CIPAddrEdit::~CIPAddrEdit()
  381. {
  382. }
  383. void CIPAddrEdit::SetParent(CIPAddrCtl* pParent)
  384. {
  385. m_pParent = pParent; // Save pointer to parent control
  386. }
  387. BEGIN_MESSAGE_MAP(CIPAddrEdit, CEdit)
  388. //{{AFX_MSG_MAP(CIPAddrEdit)
  389. ON_WM_CHAR()
  390. ON_WM_KEYDOWN()
  391. //}}AFX_MSG_MAP
  392. END_MESSAGE_MAP()
  393. /////////////////////////////////////////////////////////////////////////////
  394. // CIPAddrEdit message handlers
  395. void CIPAddrEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
  396. {
  397. // Logic for this function:
  398. // Tab and dot are forwarded to the parent.  Tab (or shift-tab) operate
  399. // just like expected (focus moves to next control after the parent).
  400. // Dot or space causes the parent to set focus to the next child edit (if
  401. // focus is currently set to one of the first three edit controls).
  402. // Numerics (0..9) and control characters are forwarded to the standard
  403. // CEdit OnChar method; all other characters are dropped.
  404. if (VK_TAB == nChar ||
  405. '.' == nChar ||
  406. ' ' == nChar ||
  407. VK_RETURN == nChar)
  408. m_pParent->OnChildChar(nChar, nRepCnt, nFlags, *this);
  409. else if (('0' <= nChar && '9'>= nChar) || iscntrl(nChar))
  410. {
  411. CEdit::OnChar(nChar, nRepCnt, nFlags);
  412. // Automatically advance to next child control if 3 characters were entered;
  413. // use "-" to indicate field was full to OnChildChar
  414. if (3 == GetWindowTextLength())
  415. m_pParent->OnChildChar('-', 0, nFlags, *this);
  416. }
  417. else
  418. ::MessageBeep(0xFFFFFFFF);
  419. }
  420. void CIPAddrEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  421. {
  422. // Handle the left and right arrow keys.  If the left arrow key is pressed
  423. // with the caret at the left of the input text, shift focus to the previous
  424. // control (if in edit controls 2-4).  Likewise for the right arrow key.
  425. // This is done by calling the parent's OnChildChar method.
  426. // If not left or right arrow, or not at beginning or end, call default
  427. // OnKeyDown processor so key down gets passed to edit control.
  428. if (VK_LEFT == nChar || VK_RIGHT == nChar)
  429. {
  430. CPoint ptCaret = GetCaretPos();
  431. int nCharPos = LOWORD(CharFromPos(ptCaret));
  432. if ((VK_LEFT == nChar && nCharPos == 0) ||
  433. (VK_RIGHT == nChar && nCharPos == GetWindowTextLength()))
  434. m_pParent->OnChildChar(nChar, nRepCnt, nFlags, *this);
  435. }
  436. else if (VK_ESCAPE == nChar)
  437. {
  438. // Must handle VK_ESCAPE specially.
  439. // In a normal dialog, VK_ESCAPE gets handled by the dialog box window process,
  440. // and the edit control never sees the character.  When the edit control lives
  441. // on a property page, this doesn't happen.  If VK_ESCAPE is not handled here
  442. // then when the escape key is pressed the entire control disappears from the
  443. // dialog!  If the parent of the control is a dialog, and the dialog's parent
  444. // is also a dialog, that's a sign that the control is on a property page.
  445. TCHAR cClass1[12];
  446. TCHAR cClass2[12];
  447. // Clear out window class name arrays
  448. memset(cClass1, 0, sizeof(cClass1));
  449. memset(cClass2, 0, sizeof(cClass2));
  450. // Get parent and parent's parent window pointers
  451. CWnd* pDialog = m_pParent->GetParent(); // Get parent of the IP address edit control
  452. CWnd* pDialogParent = pDialog->GetParent(); // Get its parent
  453. // Get class names of the windows that own the IP address edit control and its parent
  454. if (NULL != pDialog)
  455. ::GetClassName(pDialog->m_hWnd, cClass1, sizeof(cClass1)/sizeof(TCHAR));
  456. if (NULL != pDialogParent)
  457. ::GetClassName(pDialogParent->m_hWnd, cClass2, sizeof(cClass2)/sizeof(TCHAR));
  458. // If parent is a dialog, and parent's parent is a dialog, simulate Cancel button press
  459. if (0 == _tcscmp(cClass1, szDialogClass) && 0 == _tcscmp(cClass2, szDialogClass))
  460. {
  461. CWnd* pCancel = pDialogParent->GetDlgItem(IDCANCEL); // Get the Cancel button
  462. pDialogParent->SendMessage(WM_COMMAND,
  463. MAKEWPARAM(IDCANCEL, BN_CLICKED),
  464. (LPARAM) (NULL != pCancel->m_hWnd ? pCancel->m_hWnd : NULL));
  465. return;
  466. }
  467. }
  468. CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
  469. }
  470. /////////////////////////////////////////////////////////////////////////////
  471. // DDX routines
  472. void DDX_IPAddr(CDataExchange* pDX, int nIDC, unsigned char* nAddr)
  473. {
  474. IPA_ADDR x;
  475. HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  476. ASSERT(hWndCtrl);
  477. CIPAddrCtl* pIPAddrCtl = (CIPAddrCtl*) CWnd::FromHandle(hWndCtrl);
  478. ASSERT(pIPAddrCtl);
  479. if (!pDX->m_bSaveAndValidate)
  480. {
  481. // Load IP address control with current data
  482. x.nAddr1 = nAddr[0]; // Copy address bytes over
  483. x.nAddr2 = nAddr[1];
  484. x.nAddr3 = nAddr[2];
  485. x.nAddr4 = nAddr[3];
  486. pIPAddrCtl->SetAddress(&x);
  487. }
  488. else
  489. {
  490. // Save contents of IP address control
  491. BOOL bStatus = pIPAddrCtl->GetAddress(TRUE, &x);
  492. if (!bStatus)
  493. {
  494. // x.nInError contains the 1-based index of the address field that was in error
  495. pDX->m_hWndLastControl = pIPAddrCtl->GetEditControl(x.nInError)->m_hWnd; // Set HWND of control to set focus on
  496. pDX->m_bEditLastControl = TRUE; // It's an edit control (so Fail selects the text)
  497. pDX->Fail(); // Fail DDX
  498. }
  499. nAddr[0] = x.nAddr1;
  500. nAddr[1] = x.nAddr2;
  501. nAddr[2] = x.nAddr3;
  502. nAddr[3] = x.nAddr4;
  503. }
  504. }
  505. void DDX_IPAddr(CDataExchange* pDX, int nIDC, CString& szAddr)
  506. {
  507. IPA_ADDR x;
  508. HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  509. ASSERT(hWndCtrl);
  510. CIPAddrCtl* pIPAddrCtl = (CIPAddrCtl*) CWnd::FromHandle(hWndCtrl);
  511. ASSERT(pIPAddrCtl);
  512. if (!pDX->m_bSaveAndValidate)
  513. {
  514.         // Convert string to numbers
  515.         unsigned char nAddr[4];
  516.         memset(nAddr, 0, 4);
  517.         // Get numbers
  518.         for (int ii = 0; ii < 4; ii++)
  519.         {
  520.             if (ii < 3)
  521.             {
  522.                 int nIndex = szAddr.Find(_T('.'));
  523.                 if (-1 != nIndex)
  524.                 {
  525.                     nAddr[ii] = (unsigned char) _ttoi(szAddr.Left(nIndex));
  526.                     szAddr = szAddr.Mid(nIndex + 1);
  527.                 }
  528.             }
  529.             else
  530.                 nAddr[ii] = (unsigned char) _ttoi(szAddr);
  531.         }
  532. // Load IP address control with current data
  533. x.nAddr1 = nAddr[0]; // Copy address bytes over
  534. x.nAddr2 = nAddr[1];
  535. x.nAddr3 = nAddr[2];
  536. x.nAddr4 = nAddr[3];
  537. pIPAddrCtl->SetAddress(&x);
  538. }
  539. else
  540. {
  541. // Save contents of IP address control
  542. BOOL bStatus = pIPAddrCtl->GetAddress(TRUE, &x);
  543. if (!bStatus)
  544. {
  545. // x.nInError contains the 1-based index of the address field that was in error
  546. pDX->m_hWndLastControl = pIPAddrCtl->GetEditControl(x.nInError)->m_hWnd; // Set HWND of control to set focus on
  547. pDX->m_bEditLastControl = TRUE; // It's an edit control (so Fail selects the text)
  548. pDX->Fail(); // Fail DDX
  549. }
  550.         szAddr.Format(_T("%d.%d.%d.%d"),
  551.                 (unsigned char) x.nAddr1, (unsigned char) x.nAddr2,
  552.                 (unsigned char) x.nAddr3, (unsigned char) x.nAddr4);
  553. }
  554. }