00001 #pragma title("IP Address Custom Control Implementation")
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "stdafx.h"
00011 #include "IPAddr.h"
00012
00013 #ifdef _DEBUG
00014 #define new DEBUG_NEW
00015 #undef THIS_FILE
00016 static char THIS_FILE[] = __FILE__;
00017 #endif
00018
00019
00020 const int WS_EDIT = WS_CHILD | WS_VISIBLE | ES_CENTER | ES_MULTILINE;
00021 const TCHAR szDialogClass[] = _T("#32770");
00022
00023 BOOL CIPAddrCtl::m_bRegistered = Register();
00024
00026
00027
00028 IMPLEMENT_DYNCREATE(CIPAddrCtl, CWnd)
00029
00030 CIPAddrCtl::CIPAddrCtl()
00031 {
00032 m_bEnabled = TRUE;
00033 m_bReadOnly = FALSE;
00034 m_bNoValidate = FALSE;
00035 }
00036
00037 CIPAddrCtl::~CIPAddrCtl()
00038 {
00039 }
00040
00041
00042 BEGIN_MESSAGE_MAP(CIPAddrCtl, CWnd)
00043
00044 ON_WM_CREATE()
00045 ON_WM_NCDESTROY()
00046 ON_WM_SIZE()
00047 ON_WM_SETFOCUS()
00048 ON_WM_PAINT()
00049 ON_WM_ENABLE()
00050 ON_WM_ERASEBKGND()
00051 ON_MESSAGE(WM_SETFONT, OnSetFont)
00052 ON_MESSAGE(IPAM_GETADDRESS, OnGetAddress)
00053 ON_MESSAGE(IPAM_SETADDRESS, OnSetAddress)
00054 ON_MESSAGE(IPAM_SETREADONLY, OnSetReadOnly)
00055
00056 END_MESSAGE_MAP()
00057
00058
00060
00061
00062 BOOL CIPAddrCtl::Register()
00063 {
00064
00065 WNDCLASS wc;
00066 wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
00067 wc.lpfnWndProc = IPAddrWndProc;
00068 wc.cbClsExtra = 0;
00069 wc.cbWndExtra = 0;
00070 wc.hInstance = NULL;
00071 wc.hIcon = NULL;
00072 wc.hCursor = ::LoadCursor(NULL, IDC_IBEAM);
00073 wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
00074 wc.lpszMenuName = NULL;
00075 wc.lpszClassName = _T("IPAddr");
00076 if (!::RegisterClass(&wc))
00077 {
00078 ASSERT(FALSE);
00079 return FALSE;
00080 }
00081 else
00082 return TRUE;
00083 }
00084
00085 BOOL CIPAddrCtl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwExStyle)
00086 {
00087
00088 CString szWndClass = AfxRegisterWndClass(CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW,
00089 ::LoadCursor(NULL, IDC_IBEAM), (HBRUSH) COLOR_WINDOW+1);
00090
00091
00092 #if _MSC_VER >= 1100
00093
00094 return CWnd::CreateEx(dwExStyle, szWndClass, NULL, dwStyle, rect, pParentWnd, nID);
00095 #else
00096
00097 return CWnd::CreateEx(dwExStyle, szWndClass, NULL, dwStyle,
00098 rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
00099 pParentWnd->GetSafeHwnd(), (HMENU) nID);
00100 #endif
00101 }
00102
00103 LRESULT CALLBACK IPAddrWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
00104 {
00105 switch (uiMsg)
00106 {
00107 case WM_NCCREATE:
00108 {
00109 CIPAddrCtl* pCtl = new CIPAddrCtl;
00110 ASSERT(pCtl);
00111 BOOL b = pCtl->SubclassWindow(hWnd);
00112 ASSERT(b);
00113 return b;
00114 break;
00115 }
00116 default:
00117 return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
00118 }
00119 }
00120
00121 int CIPAddrCtl::OnCreate(LPCREATESTRUCT lpCreateStruct)
00122 {
00123 if (CWnd::OnCreate(lpCreateStruct) == -1)
00124 return -1;
00125
00126
00127 m_bNoValidate = (lpCreateStruct->style & IPAS_NOVALIDATE);
00128
00129
00130 ModifyStyleEx(0, WS_EX_CLIENTEDGE | WS_EX_NOPARENTNOTIFY);
00131
00132
00133
00134 for (int ii = 0; ii < 4; ii++)
00135 {
00136 m_Addr[ii].Create(WS_EDIT, CRect(0,0,0,0), this, IDC_ADDR1 + ii);
00137 m_Addr[ii].LimitText(3);
00138 m_Addr[ii].SetParent(this);
00139 }
00140
00141 return 0;
00142 }
00143
00144 void CIPAddrCtl::OnNcDestroy()
00145 {
00146 CWnd::OnNcDestroy();
00147
00148
00149 ASSERT(NULL == m_hWnd);
00150
00151
00152 delete this;
00153 }
00154
00155 void CIPAddrCtl::OnSize(UINT nType, int cx, int cy)
00156 {
00157 CWnd::OnSize(nType, cx, cy);
00158
00159
00160 CDC* pDC = GetDC();
00161 CSize szDot = pDC->GetTextExtent(_T("."), 1);
00162 int nDotWidth = szDot.cx;
00163 ReleaseDC(pDC);
00164
00165
00166
00167
00168 CRect rcClient;
00169 GetClientRect(&rcClient);
00170 int nEditWidth = (rcClient.Width() - (3 * nDotWidth)) / 4;
00171 int nEditHeight = rcClient.Height();
00172 int cyEdge = ::GetSystemMetrics(SM_CYEDGE);
00173
00174
00175 CRect rect = CRect(0, cyEdge, nEditWidth, nEditHeight);
00176 for (int ii = 0; ii < 4; ii++)
00177 {
00178 m_rcAddr[ii] = rect;
00179 m_Addr[ii].MoveWindow(rect);
00180 rect.OffsetRect(nEditWidth + nDotWidth, 0);
00181 }
00182
00183 rect = CRect(nEditWidth, 0, nEditWidth + nDotWidth, nEditHeight);
00184 for (ii = 0; ii < 3; ii++)
00185 {
00186 m_rcDot[ii] = rect;
00187 rect.OffsetRect(nEditWidth + nDotWidth, 0);
00188 }
00189 }
00190
00191 void CIPAddrCtl::OnSetFocus(CWnd* pOldWnd)
00192 {
00193 CWnd::OnSetFocus(pOldWnd);
00194
00195 m_Addr[0].SetFocus();
00196 m_Addr[0].SetSel(0, -1);
00197 }
00198
00199
00200
00201 void CIPAddrCtl::OnChildChar(UINT nChar, UINT nRepCnt, UINT nFlags, CIPAddrEdit& child)
00202 {
00203 switch (nChar)
00204 {
00205 case '.':
00206 case VK_RIGHT:
00207 case ' ':
00208 {
00209 UINT nIDC = child.GetDlgCtrlID();
00210 if (nIDC < IDC_ADDR4)
00211 {
00212 m_Addr[nIDC - IDC_ADDR1 + 1].SetFocus();
00213 if (VK_RIGHT != nChar)
00214 m_Addr[nIDC - IDC_ADDR1 + 1].SetSel(0, -1);
00215 }
00216 break;
00217 }
00218
00219 case VK_LEFT:
00220 {
00221 UINT nIDC = child.GetDlgCtrlID();
00222 if (nIDC > IDC_ADDR1)
00223 m_Addr[nIDC - IDC_ADDR1 - 1].SetFocus();
00224 break;
00225 }
00226
00227 case VK_TAB:
00228 {
00229 CWnd* pWnd;
00230 SHORT nShift = ::GetKeyState(VK_SHIFT);
00231 if (nShift < 0)
00232 pWnd = GetParent()->GetNextDlgTabItem(this, TRUE);
00233 else
00234 pWnd = GetParent()->GetNextDlgTabItem(this, FALSE);
00235 if (NULL != pWnd)
00236 pWnd->SetFocus();
00237 break;
00238 }
00239
00240 case VK_RETURN:
00241 {
00242 DWORD dw = ((CDialog*) GetParent())->GetDefID();
00243 if (DC_HASDEFID == HIWORD(dw))
00244 {
00245 CWnd* pWnd = GetParent()->GetDlgItem(LOWORD(dw));
00246 WPARAM wp = MAKEWPARAM(LOWORD(dw), BN_CLICKED);
00247 GetParent()->SendMessage(WM_COMMAND, wp, (LPARAM) pWnd->m_hWnd);
00248 }
00249 }
00250 break;
00251
00252 case '-':
00253
00254 if (!m_bNoValidate)
00255 {
00256 CString szText;
00257
00258 child.GetWindowText(szText);
00259 int n = _ttoi(szText);
00260 if (n < 0 || n > 255)
00261 {
00262 szText.Format(_T("%d is not a valid entry. Please specify a value between 0 and 255 for this field."), n);
00263 MessageBox(szText, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
00264 child.SetFocus();
00265 child.SetSel(0, -1);
00266 return;
00267 }
00268 }
00269
00270
00271 OnChildChar('.', 0, nFlags, child);
00272 break;
00273
00274 default:
00275 TRACE(_T("Unexpected call to CIPAddrCtl::OnChildChar!\n"));
00276 }
00277 }
00278
00279 void CIPAddrCtl::OnPaint()
00280 {
00281 CPaintDC dc(this);
00282
00283
00284 int nOldMode = dc.SetBkMode(TRANSPARENT);
00285
00286
00287 COLORREF crText;
00288 if (m_bEnabled)
00289 crText = ::GetSysColor(COLOR_WINDOWTEXT);
00290 else
00291 crText = ::GetSysColor(COLOR_GRAYTEXT);
00292 COLORREF crOldText = dc.SetTextColor(crText);
00293
00294
00295 for (int ii = 0; ii < 3; ii++)
00296 dc.DrawText(_T("."), 1, m_rcDot[ii], DT_CENTER | DT_SINGLELINE | DT_BOTTOM);
00297
00298
00299 dc.SetBkMode(nOldMode);
00300 dc.SetTextColor(crOldText);
00301
00302
00303 }
00304
00305 BOOL CIPAddrCtl::OnEraseBkgnd(CDC* pDC)
00306 {
00307 CRect rcClient;
00308 GetClientRect(&rcClient);
00309
00310 if (m_bEnabled && !m_bReadOnly)
00311 ::FillRect(pDC->m_hDC, rcClient, (HBRUSH) (COLOR_WINDOW+1));
00312 else
00313 ::FillRect(pDC->m_hDC, rcClient, (HBRUSH) (COLOR_BTNFACE+1));
00314
00315 return TRUE;
00316 }
00317
00318 void CIPAddrCtl::OnEnable(BOOL bEnable)
00319 {
00320 CWnd::OnEnable(bEnable);
00321
00322
00323 if (bEnable != m_bEnabled)
00324 {
00325
00326 m_bEnabled = bEnable;
00327
00328
00329 for (int ii = 0; ii < 4; ii++)
00330 m_Addr[ii].EnableWindow(bEnable);
00331 }
00332
00333 Invalidate();
00334 }
00335
00336 LONG CIPAddrCtl::OnSetFont(UINT wParam, LONG lParam)
00337 {
00338
00339
00340
00341
00342 for (int ii = 0; ii < 4; ii++)
00343 m_Addr[ii].SendMessage(WM_SETFONT, wParam, lParam);
00344
00345 return 0;
00346 }
00347
00348 LONG CIPAddrCtl::OnGetAddress(UINT wParam, LONG lParam)
00349 {
00350 BOOL bStatus;
00351 int i, nAddr[4], nInError = 0;
00352
00353 BOOL bPrintErrors = (BOOL) wParam;
00354 IPA_ADDR* lpIPAddr = (IPA_ADDR*) lParam;
00355 if (NULL == lpIPAddr)
00356 return FALSE;
00357 memset(lpIPAddr, 0, sizeof(IPA_ADDR));
00358
00359
00360 for (i = 0; i < 4; i++)
00361 {
00362 bStatus = ParseAddressPart(m_Addr[i], nAddr[i]);
00363 if (!bStatus)
00364 {
00365 nInError = i + 1;
00366 break;
00367 }
00368 }
00369 if (!bStatus)
00370 {
00371 lpIPAddr->nInError = nInError;
00372 if (bPrintErrors)
00373 {
00374 CString szText;
00375 if (nAddr[i] < 0)
00376 szText = _T("Missing value in IP address");
00377 else
00378 szText.Format(_T("%d is not a valid entry. Please specify a value between 0 and 255 for this field."), nAddr[i]);
00379 MessageBox(szText, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
00380 }
00381 m_Addr[i].SetFocus();
00382 m_Addr[i].SetSel(0, -1);
00383 return FALSE;
00384 }
00385
00386 lpIPAddr->nAddr1 = nAddr[0];
00387 lpIPAddr->nAddr2 = nAddr[1];
00388 lpIPAddr->nAddr3 = nAddr[2];
00389 lpIPAddr->nAddr4 = nAddr[3];
00390 lpIPAddr->nInError = 0;
00391 return TRUE;
00392 }
00393
00394 LONG CIPAddrCtl::OnSetAddress(UINT wParam, LONG lParam)
00395 {
00396 CString szText;
00397
00398 IPA_ADDR* lpIPAddr = (IPA_ADDR*) lParam;
00399
00400
00401 szText.Format(_T("%u"), lpIPAddr->nAddr1);
00402 m_Addr[0].SetWindowText(szText);
00403 szText.Format(_T("%u"), lpIPAddr->nAddr2);
00404 m_Addr[1].SetWindowText(szText);
00405 szText.Format(_T("%u"), lpIPAddr->nAddr3);
00406 m_Addr[2].SetWindowText(szText);
00407 szText.Format(_T("%u"), lpIPAddr->nAddr4);
00408 m_Addr[3].SetWindowText(szText);
00409 return TRUE;
00410 }
00411
00412 LONG CIPAddrCtl::OnSetReadOnly(UINT wParam, LONG lParam)
00413 {
00414 m_bReadOnly = (BOOL) wParam;
00415
00416 for (int ii = 0; ii < 4; ii++)
00417 m_Addr[ii].SetReadOnly(m_bReadOnly);
00418
00419 Invalidate();
00420 return TRUE;
00421 }
00422
00423 BOOL CIPAddrCtl::ParseAddressPart(CEdit& edit, int& n)
00424 {
00425 CString szText;
00426
00427 edit.GetWindowText(szText);
00428 if (szText.IsEmpty())
00429 {
00430 n = -1;
00431 return FALSE;
00432 }
00433
00434 n = _ttoi(szText);
00435 if (n < 0 || n > 255)
00436 return FALSE;
00437
00438 return TRUE;
00439 }
00440
00441 CIPAddrEdit* CIPAddrCtl::GetEditControl(int nIndex)
00442 {
00443 if (nIndex < 1 || nIndex > 4)
00444 return NULL;
00445 return &m_Addr[nIndex - 1];
00446 }
00447
00448
00450
00451
00452 CIPAddrEdit::CIPAddrEdit()
00453 {
00454 }
00455
00456 CIPAddrEdit::~CIPAddrEdit()
00457 {
00458 }
00459
00460 void CIPAddrEdit::SetParent(CIPAddrCtl* pParent)
00461 {
00462 m_pParent = pParent;
00463 }
00464
00465
00466 BEGIN_MESSAGE_MAP(CIPAddrEdit, CEdit)
00467
00468 ON_WM_CHAR()
00469 ON_WM_KEYDOWN()
00470
00471 END_MESSAGE_MAP()
00472
00474
00475
00476 void CIPAddrEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
00477 {
00478
00479
00480
00481
00482
00483
00484
00485 if (VK_TAB == nChar ||
00486 '.' == nChar ||
00487 ' ' == nChar ||
00488 VK_RETURN == nChar)
00489 m_pParent->OnChildChar(nChar, nRepCnt, nFlags, *this);
00490 else if (('0' <= nChar && '9'>= nChar) || iscntrl(nChar))
00491 {
00492 CEdit::OnChar(nChar, nRepCnt, nFlags);
00493
00494
00495
00496 if (3 == GetWindowTextLength())
00497 m_pParent->OnChildChar('-', 0, nFlags, *this);
00498 }
00499 else
00500 ::MessageBeep(0xFFFFFFFF);
00501 }
00502
00503 void CIPAddrEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
00504 {
00505
00506
00507
00508
00509
00510
00511 if (VK_LEFT == nChar || VK_RIGHT == nChar)
00512 {
00513 CPoint ptCaret = GetCaretPos();
00514 int nCharPos = LOWORD(CharFromPos(ptCaret));
00515 if ((VK_LEFT == nChar && nCharPos == 0) ||
00516 (VK_RIGHT == nChar && nCharPos == GetWindowTextLength()))
00517 m_pParent->OnChildChar(nChar, nRepCnt, nFlags, *this);
00518 }
00519 else if (VK_ESCAPE == nChar)
00520 {
00521
00522
00523
00524
00525
00526
00527
00528 TCHAR cClass1[12];
00529 TCHAR cClass2[12];
00530
00531
00532 memset(cClass1, 0, sizeof(cClass1));
00533 memset(cClass2, 0, sizeof(cClass2));
00534
00535
00536 CWnd* pDialog = m_pParent->GetParent();
00537 CWnd* pDialogParent = pDialog->GetParent();
00538
00539
00540 if (NULL != pDialog)
00541 ::GetClassName(pDialog->m_hWnd, cClass1, sizeof(cClass1)/sizeof(TCHAR));
00542 if (NULL != pDialogParent)
00543 ::GetClassName(pDialogParent->m_hWnd, cClass2, sizeof(cClass2)/sizeof(TCHAR));
00544
00545
00546 if (0 == _tcscmp(cClass1, szDialogClass) && 0 == _tcscmp(cClass2, szDialogClass))
00547 {
00548 CWnd* pCancel = pDialogParent->GetDlgItem(IDCANCEL);
00549 pDialogParent->SendMessage(WM_COMMAND,
00550 MAKEWPARAM(IDCANCEL, BN_CLICKED),
00551 (LPARAM) (NULL != pCancel->m_hWnd ? pCancel->m_hWnd : NULL));
00552 return;
00553 }
00554 }
00555 CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
00556 }
00557
00559
00560
00561 void DDX_IPAddr(CDataExchange* pDX, int nIDC, unsigned char* nAddr)
00562 {
00563 IPA_ADDR x;
00564
00565 HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
00566 ASSERT(hWndCtrl);
00567 CIPAddrCtl* pIPAddrCtl = (CIPAddrCtl*) CWnd::FromHandle(hWndCtrl);
00568 ASSERT(pIPAddrCtl);
00569
00570 if (!pDX->m_bSaveAndValidate)
00571 {
00572
00573 x.nAddr1 = nAddr[0];
00574 x.nAddr2 = nAddr[1];
00575 x.nAddr3 = nAddr[2];
00576 x.nAddr4 = nAddr[3];
00577 pIPAddrCtl->SetAddress(&x);
00578 }
00579 else
00580 {
00581
00582 BOOL bStatus = pIPAddrCtl->GetAddress(TRUE, &x);
00583 if (!bStatus)
00584 {
00585
00586 pDX->m_hWndLastControl = pIPAddrCtl->GetEditControl(x.nInError)->m_hWnd;
00587 pDX->m_bEditLastControl = TRUE;
00588 pDX->Fail();
00589 }
00590 nAddr[0] = x.nAddr1;
00591 nAddr[1] = x.nAddr2;
00592 nAddr[2] = x.nAddr3;
00593 nAddr[3] = x.nAddr4;
00594 }
00595 }
00596
00597 void DDX_IPAddr(CDataExchange* pDX, int nIDC, CString& szAddr)
00598 {
00599 IPA_ADDR x;
00600
00601 HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
00602 ASSERT(hWndCtrl);
00603 CIPAddrCtl* pIPAddrCtl = (CIPAddrCtl*) CWnd::FromHandle(hWndCtrl);
00604 ASSERT(pIPAddrCtl);
00605
00606 if (!pDX->m_bSaveAndValidate)
00607 {
00608
00609 unsigned char nAddr[4];
00610 memset(nAddr, 0, 4);
00611
00612
00613 for (int ii = 0; ii < 4; ii++)
00614 {
00615 if (ii < 3)
00616 {
00617 int nIndex = szAddr.Find(_T('.'));
00618 if (-1 != nIndex)
00619 {
00620 nAddr[ii] = (unsigned char) _ttoi(szAddr.Left(nIndex));
00621 szAddr = szAddr.Mid(nIndex + 1);
00622 }
00623 }
00624 else
00625 nAddr[ii] = (unsigned char) _ttoi(szAddr);
00626 }
00627
00628
00629 x.nAddr1 = nAddr[0];
00630 x.nAddr2 = nAddr[1];
00631 x.nAddr3 = nAddr[2];
00632 x.nAddr4 = nAddr[3];
00633 pIPAddrCtl->SetAddress(&x);
00634 }
00635 else
00636 {
00637
00638 BOOL bStatus = pIPAddrCtl->GetAddress(TRUE, &x);
00639 if (!bStatus)
00640 {
00641
00642 pDX->m_hWndLastControl = pIPAddrCtl->GetEditControl(x.nInError)->m_hWnd;
00643 pDX->m_bEditLastControl = TRUE;
00644 pDX->Fail();
00645 }
00646 szAddr.Format(_T("%d.%d.%d.%d"),
00647 (unsigned char) x.nAddr1, (unsigned char) x.nAddr2,
00648 (unsigned char) x.nAddr3, (unsigned char) x.nAddr4);
00649 }
00650 }