ipaddr.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 28k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /* Copyright (c) 1991, Microsoft Corporation, all rights reserved
  2.  ipaddr.c - TCP/IP Address custom control
  3.  November 9, 1992    Greg Strange
  4.  */
  5. #include "ctlspriv.h"
  6. // The character that is displayed between address fields.
  7. #define FILLER          TEXT('.')
  8. #define SZFILLER        TEXT(".")
  9. #define SPACE           TEXT(' ')
  10. #define BACK_SPACE      8
  11. /* Min, max values */
  12. #define NUM_FIELDS      4
  13. #define CHARS_PER_FIELD 3
  14. #define HEAD_ROOM       1       // space at top of control
  15. #define LEAD_ROOM       3       // space at front of control
  16. #define MIN_FIELD_VALUE 0       // default minimum allowable field value
  17. #define MAX_FIELD_VALUE 255     // default maximum allowable field value
  18. // All the information unique to one control is stuffed in one of these
  19. // structures in global memory and the handle to the memory is stored in the
  20. // Windows extra space.
  21. typedef struct tagFIELD {
  22.     HANDLE      hWnd;
  23.     WNDPROC     lpfnWndProc;
  24.     BYTE        byLow;  // lowest allowed value for this field.
  25.     BYTE        byHigh; // Highest allowed value for this field.
  26. } FIELD;
  27. typedef struct tagIPADDR {
  28.     HWND        hwndParent;
  29.     HWND        hwnd;
  30.     UINT        uiFieldWidth;
  31.     UINT        uiFillerWidth;
  32.     BOOL        fEnabled : 1;
  33.     BOOL        fPainted : 1;
  34.     BOOL        bControlInFocus : 1;        // TRUE if the control is already in focus, dont't send another focus command
  35.     BOOL        bCancelParentNotify : 1;    // Don't allow the edit controls to notify parent if TRUE
  36.     BOOL        fInMessageBox : 1;  // Set when a message box is displayed so that
  37.     BOOL        fFontCreated :1;
  38.     HFONT       hfont;
  39.     // we don't send a EN_KILLFOCUS message when
  40.     // we receive the EN_KILLFOCUS message for the
  41.     // current field.
  42.     FIELD       Children[NUM_FIELDS];
  43. } IPADDR;
  44. // The following macros extract and store the CONTROL structure for a control.
  45. #define    IPADDRESS_EXTRA            sizeof(DWORD)
  46. #define GET_IPADDR_HANDLE(hWnd)        ((HGLOBAL)(GetWindowLongPtr((hWnd), GWLP_USERDATA)))
  47. #define SAVE_IPADDR_HANDLE(hWnd,x)     (SetWindowLongPtr((hWnd), GWLP_USERDATA, (LONG_PTR)(x)))
  48. /* internal IPAddress function prototypes */
  49. LRESULT IPAddressWndFn( HWND, UINT, WPARAM, LPARAM );
  50. LRESULT IPAddressFieldProc(HWND, UINT, WPARAM, LPARAM);
  51. BOOL SwitchFields(IPADDR FAR *, int, int, WORD, WORD);
  52. void EnterField(FIELD FAR *, WORD, WORD);
  53. BOOL ExitField(IPADDR FAR *, int iField);
  54. int GetFieldValue(FIELD FAR *);
  55. void SetFieldValue(IPADDR *pipa, int iField, int iValue);
  56. BOOL IsDBCS();
  57. /*
  58.  IPAddrInit() - IPAddress custom control initialization
  59.  call
  60.  hInstance = library or application instance
  61.  return
  62.  TRUE on success, FALSE on failure.
  63.  This function does all the one time initialization of IPAddress custom
  64.  controls.  Specifically it creates the IPAddress window class.
  65.  */
  66. int InitIPAddr(HANDLE hInstance)
  67. {
  68.     WNDCLASS        wc;
  69.     if (!GetClassInfo(hInstance, WC_IPADDRESS, &wc)) {
  70.         /* define class attributes */
  71.         wc.lpszClassName = WC_IPADDRESS;
  72.         wc.hCursor =       LoadCursor(NULL,IDC_IBEAM);
  73.         wc.hIcon           = NULL;
  74.         wc.lpszMenuName =  (LPCTSTR)NULL;
  75.         wc.style =         CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS|CS_GLOBALCLASS;
  76.         wc.lpfnWndProc =   IPAddressWndFn;
  77.         wc.hInstance =     hInstance;
  78.         wc.hIcon =         NULL;
  79.         wc.cbWndExtra =    IPADDRESS_EXTRA;
  80.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
  81.         wc.cbClsExtra      = 0;
  82.         /* register IPAddress window class */
  83.         return RegisterClass(&wc);
  84.     }
  85.     return TRUE;
  86. }
  87. /*
  88.  IPAddressWndFn() - Main window function for an IPAddress control.
  89.  call
  90.  hWnd    handle to IPAddress window
  91.  wMsg    message number
  92.  wParam  word parameter
  93.  lParam  long parameter
  94.  */
  95. void FormatIPAddress(LPTSTR pszString, DWORD* dwValue)
  96. {
  97.     int nField, nPos;
  98.     BOOL fFinish = FALSE;
  99.     dwValue[0] = 0; dwValue[1] = 0; dwValue[2] = 0; dwValue[3] = 0;
  100.     if (pszString[0] == 0)
  101.         return;
  102.     for( nField = 0, nPos = 0; !fFinish; nPos++)
  103.     {
  104.         if (( pszString[nPos]<TEXT('0')) || (pszString[nPos]>TEXT('9')))
  105.         {
  106.             // not a number
  107.             nField++;
  108.             fFinish = (nField == 4);
  109.         }
  110.         else
  111.         {
  112.             dwValue[nField] *= 10;
  113.             dwValue[nField] += (pszString[nPos]-TEXT('0'));
  114.         }
  115.     }
  116. }
  117. void IP_OnSetFont(IPADDR* pipa, HFONT hfont, BOOL fRedraw)
  118. {
  119.     int i;
  120.     RECT rect;
  121.     HFONT OldFont;
  122.     BOOL fNewFont = FALSE;
  123.     UINT uiFieldStart;
  124.     HDC hdc;
  125.     
  126.     if (hfont) {
  127.         fNewFont = TRUE;
  128.     } else {
  129.         hfont = (HFONT)SendMessage(pipa->hwnd, WM_GETFONT, 0, 0);
  130.     }
  131.     
  132.     hdc = GetDC(pipa->hwnd);
  133.     OldFont = SelectObject(hdc, hfont);
  134.     GetCharWidth(hdc, FILLER, FILLER,
  135.                  (int *)(&pipa->uiFillerWidth));
  136.     SelectObject(hdc, OldFont);
  137.     ReleaseDC(pipa->hwnd, hdc);
  138.     
  139.     GetClientRect(pipa->hwnd, &rect);
  140.     pipa->hfont = hfont;
  141.     pipa->uiFieldWidth = (RECTWIDTH(rect)
  142.                           - LEAD_ROOM
  143.                           - pipa->uiFillerWidth
  144.                           *(NUM_FIELDS-1))
  145.         / NUM_FIELDS;
  146.     uiFieldStart = LEAD_ROOM;
  147.     for (i = 0; i < NUM_FIELDS; i++) {
  148.         HWND hwnd = pipa->Children[i].hWnd;
  149.         
  150.         if (fNewFont)
  151.             SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)fRedraw);
  152.         
  153.         SetWindowPos(hwnd, NULL,
  154.                      uiFieldStart,
  155.                      HEAD_ROOM,
  156.                      pipa->uiFieldWidth,
  157.                      (rect.bottom-rect.top),
  158.                      SWP_NOACTIVATE);
  159.         uiFieldStart += pipa->uiFieldWidth
  160.             + pipa->uiFillerWidth;
  161.     }
  162.     
  163. }
  164. LRESULT IPAddressWndFn( hWnd, wMsg, wParam, lParam )
  165.     HWND            hWnd;
  166.     UINT            wMsg;
  167.     WPARAM            wParam;
  168.     LPARAM            lParam;
  169. {
  170.     LRESULT lResult;
  171.     IPADDR *pipa;
  172.     int i;
  173.     pipa = (IPADDR *)GET_IPADDR_HANDLE(hWnd);
  174.     lResult = TRUE;
  175.     switch( wMsg )
  176.     {
  177.         // use empty string (not NULL) to set to blank
  178.         case WM_SETTEXT:
  179.         {
  180.             TCHAR szBuf[CHARS_PER_FIELD+1];
  181.             DWORD dwValue[4];
  182. #ifdef UNICODE_WIN9x
  183.             WCHAR szTemp[80];
  184.             LPTSTR pszString = szTemp;
  185.             ConvertAToWN(CP_ACP, szTemp, ARRAYSIZE(szTemp), (LPSTR)lParam, -1);
  186. #else
  187.             LPTSTR pszString = (LPTSTR)lParam;
  188. #endif
  189.             FormatIPAddress(pszString, &dwValue[0]);
  190.             pipa->bCancelParentNotify = TRUE;
  191.             for (i = 0; i < NUM_FIELDS; ++i)
  192.             {
  193.                 if (pszString[0] == 0)
  194.                 {
  195.                     szBuf[0] = 0;
  196.                 }
  197.                 else
  198.                 {
  199.                     wsprintf(szBuf, TEXT("%d"), dwValue[i]);
  200.                 }
  201.                 SendMessage(pipa->Children[i].hWnd, WM_SETTEXT,
  202.                             0, (LPARAM) (LPSTR) szBuf);
  203.             }
  204.             pipa->bCancelParentNotify = FALSE;
  205.             SendMessage(pipa->hwndParent, WM_COMMAND,
  206.                         MAKEWPARAM(GetDlgCtrlID(hWnd), EN_CHANGE), (LPARAM)hWnd);
  207.         }
  208.         break;
  209.     case WM_GETTEXTLENGTH:
  210.     case WM_GETTEXT:
  211.     {
  212.         int iFieldValue;
  213.         DWORD dwValue[4];
  214. #ifdef UNICODE_WIN9x
  215.         char pszResult[30];
  216.         char *pszDest = (char *)lParam;
  217. #else
  218.         TCHAR pszResult[30];
  219.         TCHAR *pszDest = (TCHAR *)lParam;
  220. #endif
  221.         lResult = 0;
  222.         dwValue[0] = 0;
  223.         dwValue[1] = 0;
  224.         dwValue[2] = 0;
  225.         dwValue[3] = 0;
  226.         for (i = 0; i < NUM_FIELDS; ++i)
  227.         {
  228.             iFieldValue = GetFieldValue(&(pipa->Children[i]));
  229.             if (iFieldValue == -1)
  230.                 iFieldValue = 0;
  231.             else
  232.                 ++lResult;
  233.             dwValue[i] = iFieldValue;
  234.         }
  235. #ifdef UNICODE_WIN9x
  236.         wsprintfA( pszResult, "%d.%d.%d.%d", dwValue[0], dwValue[1], dwValue[2], dwValue[3] );
  237. #else
  238.         wsprintf( pszResult, TEXT("%d.%d.%d.%d"), dwValue[0], dwValue[1], dwValue[2], dwValue[3] );
  239. #endif
  240.         if (wMsg == WM_GETTEXT) {
  241. #ifdef UNICODE_WIN9x
  242.             lstrcpynA(pszDest, pszResult, (int) wParam);
  243.             lResult = lstrlenA( pszDest );
  244. #else
  245.             StrCpyN(pszDest, pszResult, (int) wParam);
  246.             lResult = lstrlen( pszDest );
  247. #endif
  248.         } else {
  249. #ifdef UNICODE_WIN9x
  250.             lResult = lstrlenA( pszResult );
  251. #else
  252.             lResult = lstrlen( pszResult );
  253. #endif
  254.         }
  255.     }
  256.         break;
  257.     case WM_GETDLGCODE :
  258.         lResult = DLGC_WANTCHARS;
  259.         break;
  260.     case WM_NCCREATE:
  261.         SetWindowBits(hWnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);
  262.         lResult = TRUE;
  263.         break;
  264.     case WM_CREATE : /* create pallette window */
  265.     {
  266.         LONG id;
  267.         pipa = (IPADDR*)LocalAlloc(LPTR, sizeof(IPADDR));
  268.         if (pipa)
  269.         {
  270. #define LPCS    ((CREATESTRUCT *)lParam)
  271.             pipa->fEnabled = TRUE;
  272.             pipa->hwndParent = LPCS->hwndParent;
  273.             pipa->hwnd = hWnd;
  274.             id = GetDlgCtrlID(hWnd);
  275.             for (i = 0; i < NUM_FIELDS; ++i)
  276.             {
  277.                 pipa->Children[i].byLow = MIN_FIELD_VALUE;
  278.                 pipa->Children[i].byHigh = MAX_FIELD_VALUE;
  279.                 pipa->Children[i].hWnd = CreateWindowEx(0,
  280.                                                         TEXT("Edit"),
  281.                                                         NULL,
  282.                                                         WS_CHILD |
  283.                                                         ES_CENTER, 
  284.                                                         0, 10, 100, 100,
  285.                                                         hWnd,
  286.                                                         (HMENU)(LONG_PTR)id,
  287.                                                         LPCS->hInstance,
  288.                                                         (LPVOID)NULL);
  289.                 SAVE_IPADDR_HANDLE(pipa->Children[i].hWnd, i);
  290.                 SendMessage(pipa->Children[i].hWnd, EM_LIMITTEXT,
  291.                             CHARS_PER_FIELD, 0L);
  292.                 pipa->Children[i].lpfnWndProc =
  293.                     (WNDPROC) GetWindowLongPtr(pipa->Children[i].hWnd,
  294.                                                GWLP_WNDPROC);
  295.                 SetWindowLongPtr(pipa->Children[i].hWnd,
  296.                                  GWLP_WNDPROC, (LONG_PTR)IPAddressFieldProc);
  297.             }
  298.             SAVE_IPADDR_HANDLE(hWnd, pipa);
  299.             
  300.             IP_OnSetFont(pipa, NULL, FALSE);
  301.             for (i = 0; i < NUM_FIELDS; ++i)
  302.                 ShowWindow(pipa->Children[i].hWnd, SW_SHOW);
  303. #undef LPCS
  304.         }
  305.         else
  306.             DestroyWindow(hWnd);
  307.     }
  308.         lResult = 0;
  309.         break;
  310.     case WM_PAINT: /* paint IPADDR window */
  311.     {
  312.         PAINTSTRUCT Ps;
  313.         RECT rect;
  314.         COLORREF TextColor;
  315.         COLORREF cRef;
  316.         HFONT OldFont;
  317.         BeginPaint(hWnd, (LPPAINTSTRUCT)&Ps);
  318.         OldFont = SelectObject( Ps.hdc, pipa->hfont);
  319.         GetClientRect(hWnd, &rect);
  320.         if (pipa->fEnabled)
  321.         {
  322.             TextColor = GetSysColor(COLOR_WINDOWTEXT);
  323.             cRef = GetSysColor(COLOR_WINDOW);
  324.         }
  325.         else
  326.         {
  327.             TextColor = GetSysColor(COLOR_GRAYTEXT);
  328.             cRef = GetSysColor(COLOR_3DFACE);
  329.         }
  330.         FillRectClr(Ps.hdc, &rect, cRef);
  331.         SetRect(&rect, 0, HEAD_ROOM, pipa->uiFillerWidth, (rect.bottom-rect.top));
  332.         SetBkColor(Ps.hdc, cRef);
  333.         SetTextColor(Ps.hdc, TextColor);
  334.         for (i = 0; i < NUM_FIELDS-1; ++i)
  335.         {
  336.             rect.left += pipa->uiFieldWidth + pipa->uiFillerWidth;
  337.             rect.right += rect.left + pipa->uiFillerWidth;
  338.             ExtTextOut(Ps.hdc, rect.left, HEAD_ROOM, ETO_OPAQUE, &rect, SZFILLER, 1, NULL);
  339.         }
  340.         pipa->fPainted = TRUE;
  341.         SelectObject(Ps.hdc, OldFont);
  342.         EndPaint(hWnd, &Ps);
  343.     }
  344.         break;
  345.     case WM_SETFOCUS : /* get focus - display caret */
  346.         EnterField(&(pipa->Children[0]), 0, CHARS_PER_FIELD);
  347.         break;
  348.         
  349.         HANDLE_MSG(pipa, WM_SETFONT, IP_OnSetFont);
  350.     case WM_LBUTTONDOWN : /* left button depressed - fall through */
  351.         SetFocus(hWnd);
  352.         break;
  353.     case WM_ENABLE:
  354.     {
  355.         pipa->fEnabled = (BOOL)wParam;
  356.         for (i = 0; i < NUM_FIELDS; ++i)
  357.         {
  358.             EnableWindow(pipa->Children[i].hWnd, (BOOL)wParam);
  359.         }
  360.         if (pipa->fPainted)    
  361.             InvalidateRect(hWnd, NULL, FALSE);
  362.     }
  363.         break;
  364.     case WM_DESTROY :
  365.         // Restore all the child window procedures before we delete our memory block.
  366.         for (i = 0; i < NUM_FIELDS; ++i)
  367.         {
  368.             SendMessage(pipa->Children[i].hWnd, WM_DESTROY, 0, 0);
  369.             SetWindowLongPtr(pipa->Children[i].hWnd, GWLP_WNDPROC,
  370.                              (LONG_PTR)pipa->Children[i].lpfnWndProc);
  371.         }
  372.         LocalFree(pipa);
  373.         break;
  374.     case WM_COMMAND:
  375.         switch (HIWORD(wParam))
  376.         {
  377.             // One of the fields lost the focus, see if it lost the focus to another field
  378.             // of if we've lost the focus altogether.  If its lost altogether, we must send
  379.             // an EN_KILLFOCUS notification on up the ladder.
  380.             case EN_KILLFOCUS:
  381.             {
  382.                 HWND hFocus;
  383.                 if (!pipa->fInMessageBox)
  384.                 {
  385.                     hFocus = GetFocus();
  386.                     for (i = 0; i < NUM_FIELDS; ++i)
  387.                         if (pipa->Children[i].hWnd == hFocus)
  388.                             break;
  389.                     if (i >= NUM_FIELDS)
  390.                     {
  391.                         SendMessage(pipa->hwndParent, WM_COMMAND,
  392.                                     MAKEWPARAM(GetDlgCtrlID(hWnd),
  393.                                                EN_KILLFOCUS), (LPARAM)hWnd);
  394.                         pipa->bControlInFocus = FALSE;
  395.                     }
  396.                 }
  397.             }
  398.             break;
  399.         case EN_SETFOCUS:
  400.         {
  401.             HWND hFocus;
  402.             if (!pipa->fInMessageBox)
  403.             {
  404.                 hFocus = (HWND)lParam;
  405.                 for (i = 0; i < NUM_FIELDS; ++i)
  406.                     if (pipa->Children[i].hWnd == hFocus)
  407.                         break;
  408.                 // send a focus message when the
  409.                 if (i < NUM_FIELDS && pipa->bControlInFocus == FALSE)
  410.                 {
  411.                     SendMessage(pipa->hwndParent, WM_COMMAND,
  412.                                 MAKEWPARAM(GetDlgCtrlID(hWnd),
  413.                                            EN_SETFOCUS), (LPARAM)hWnd);
  414.                     pipa->bControlInFocus = TRUE; // only set the focus once
  415.                 }
  416.             }
  417.         }
  418.             break;
  419.         case EN_CHANGE:
  420.             if (pipa->bCancelParentNotify == FALSE)
  421.             {
  422.                 SendMessage(pipa->hwndParent, WM_COMMAND,
  423.                             MAKEWPARAM(GetDlgCtrlID(hWnd), EN_CHANGE), (LPARAM)hWnd);
  424.             }
  425.             break;
  426.         }
  427.         break;
  428.         // Get the value of the IP Address.  The address is placed in the DWORD pointed
  429.         // to by lParam and the number of non-blank fields is returned.
  430.         case IPM_GETADDRESS:
  431.         {
  432.             int iFieldValue;
  433.             DWORD dwValue;
  434.             lResult = 0;
  435.             dwValue = 0;
  436.             for (i = 0; i < NUM_FIELDS; ++i)
  437.             {
  438.                 iFieldValue = GetFieldValue(&(pipa->Children[i]));
  439.                 if (iFieldValue == -1)
  440.                     iFieldValue = 0;
  441.                 else
  442.                     ++lResult;
  443.                 dwValue = (dwValue << 8) + iFieldValue;
  444.             }
  445.             *((DWORD *)lParam) = dwValue;
  446.         }
  447.         break;
  448.         // Clear all fields to blanks.
  449.         case IPM_CLEARADDRESS:
  450.         {
  451.             pipa->bCancelParentNotify = TRUE;
  452.             for (i = 0; i < NUM_FIELDS; ++i)
  453.             {
  454.                 SendMessage(pipa->Children[i].hWnd, WM_SETTEXT,
  455.                             0, (LPARAM) (LPSTR) TEXT(""));
  456.             }
  457.             pipa->bCancelParentNotify = FALSE;
  458.             SendMessage(pipa->hwndParent, WM_COMMAND,
  459.                         MAKEWPARAM(GetDlgCtrlID(hWnd), EN_CHANGE), (LPARAM)hWnd);
  460.         }
  461.         break;
  462.         // Set the value of the IP Address.  The address is in the lParam with the
  463.         // first address byte being the high byte, the second being the second byte,
  464.         // and so on.  A lParam value of -1 removes the address.
  465.         case IPM_SETADDRESS:
  466.         {
  467.             pipa->bCancelParentNotify = TRUE;
  468.             for (i = 0; i < NUM_FIELDS; ++i)
  469.             {
  470.                 BYTE bVal = HIBYTE(HIWORD(lParam));
  471.                 if (pipa->Children[i].byLow <= bVal &&
  472.                     bVal <= pipa->Children[i].byHigh) {
  473.                     SetFieldValue(pipa, i, bVal);
  474.                 } else {
  475.                     lResult = FALSE;
  476.                 }
  477.                 lParam <<= 8;
  478.             }
  479.             pipa->bCancelParentNotify = FALSE;
  480.             SendMessage(pipa->hwndParent, WM_COMMAND,
  481.                         MAKEWPARAM(GetDlgCtrlID(hWnd), EN_CHANGE), (LPARAM)hWnd);
  482.         }
  483.         break;
  484.     case IPM_SETRANGE:
  485.         if (wParam < NUM_FIELDS && LOBYTE(LOWORD(lParam)) <= HIBYTE(LOWORD(lParam)))
  486.         {
  487.             lResult = MAKEIPRANGE(pipa->Children[wParam].byLow, pipa->Children[wParam].byHigh);
  488.             pipa->Children[wParam].byLow = LOBYTE(LOWORD(lParam));
  489.             pipa->Children[wParam].byHigh = HIBYTE(LOWORD(lParam));
  490.             break;
  491.         }
  492.         lResult = 0;
  493.         break;
  494.         // Set the focus to this IPADDR.
  495.         // wParam = the field number to set focus to, or -1 to set the focus to the
  496.         // first non-blank field.
  497.     case IPM_SETFOCUS:
  498.         if (wParam >= NUM_FIELDS)
  499.         {
  500.             for (wParam = 0; wParam < NUM_FIELDS; ++wParam)
  501.                 if (GetFieldValue(&(pipa->Children[wParam])) == -1)   break;
  502.             if (wParam >= NUM_FIELDS)    wParam = 0;
  503.         }
  504.         EnterField(&(pipa->Children[wParam]), 0, CHARS_PER_FIELD);
  505.         break;
  506.         // Determine whether all four subfields are blank
  507.     case IPM_ISBLANK:
  508.         lResult = TRUE;
  509.         for (i = 0; i < NUM_FIELDS; ++i)
  510.         {
  511.             if (GetFieldValue(&(pipa->Children[i])) != -1)
  512.             {
  513.                 lResult = FALSE;
  514.                 break;
  515.             }
  516.         }
  517.         break;
  518.     default:
  519.         lResult = DefWindowProc( hWnd, wMsg, wParam, lParam );
  520.         break;
  521.     }
  522.     return( lResult );
  523. }
  524. /*
  525.  IPAddressFieldProc() - Edit field window procedure
  526.  This function sub-classes each edit field.
  527.  */
  528. LRESULT IPAddressFieldProc(HWND hWnd,
  529.                                    UINT wMsg,
  530.                                    WPARAM wParam,
  531.                                    LPARAM lParam)
  532. {
  533.     IPADDR *pipa;
  534.     FIELD *pField;
  535.     HWND hIPADDRWindow;
  536.     WORD wChildID;
  537.     LRESULT lresult;
  538.     if (!(hIPADDRWindow = GetParent(hWnd)))
  539.         return 0;
  540.     pipa = (IPADDR *)GET_IPADDR_HANDLE(hIPADDRWindow);
  541.     if (!pipa)
  542.         return 0;
  543.     
  544.     wChildID = (WORD)GET_IPADDR_HANDLE(hWnd);
  545.     pField = &(pipa->Children[wChildID]);
  546.     if (pField->hWnd != hWnd)    
  547.         return 0;
  548.     switch (wMsg)
  549.     {
  550.     case WM_DESTROY:
  551.         DeleteObject((HGDIOBJ)SendMessage(hWnd, WM_GETFONT, 0, 0));
  552.         return 0;
  553.     case WM_CHAR:
  554.         // Typing in the last digit in a field, skips to the next field.
  555.         if (wParam >= TEXT('0') && wParam <= TEXT('9'))
  556.         {
  557.             LRESULT lResult;
  558.             lResult = CallWindowProc(pipa->Children[wChildID].lpfnWndProc,
  559.                                       hWnd, wMsg, wParam, lParam);
  560.             lResult = SendMessage(hWnd, EM_GETSEL, 0, 0L);
  561.             if (lResult == MAKELPARAM(CHARS_PER_FIELD, CHARS_PER_FIELD)
  562.                 && ExitField(pipa, wChildID)
  563.                 && wChildID < NUM_FIELDS-1)
  564.             {
  565.                 EnterField(&(pipa->Children[wChildID+1]),
  566.                            0, CHARS_PER_FIELD);
  567.             }
  568.             return lResult;
  569.         }
  570.         // spaces and periods fills out the current field and then if possible,
  571.         // goes to the next field.
  572.         else if (wParam == FILLER || wParam == SPACE )
  573.         {
  574.             LRESULT lResult;
  575.             lResult = SendMessage(hWnd, EM_GETSEL, 0, 0L);
  576.             if (lResult != 0L && HIWORD(lResult) == LOWORD(lResult)
  577.                 && ExitField(pipa, wChildID))
  578.             {
  579.                 if (wChildID >= NUM_FIELDS-1)
  580.                     MessageBeep((UINT)-1);
  581.                 else
  582.                 {
  583.                     EnterField(&(pipa->Children[wChildID+1]),
  584.                                0, CHARS_PER_FIELD);
  585.                 }
  586.             }
  587.             return 0;
  588.         }
  589.         // Backspaces go to the previous field if at the beginning of the current field.
  590.         // Also, if the focus shifts to the previous field, the backspace must be
  591.         // processed by that field.
  592.         else if (wParam == BACK_SPACE)
  593.         {
  594.             if (wChildID > 0 && SendMessage(hWnd, EM_GETSEL, 0, 0L) == 0L)
  595.             {
  596.                 if (SwitchFields(pipa, wChildID, wChildID-1,
  597.                                  CHARS_PER_FIELD, CHARS_PER_FIELD)
  598.                     && SendMessage(pipa->Children[wChildID-1].hWnd,
  599.                                    EM_LINELENGTH, 0, 0L) != 0L)
  600.                 {
  601.                     SendMessage(pipa->Children[wChildID-1].hWnd,
  602.                                 wMsg, wParam, lParam);
  603.                 }
  604.                 return 0;
  605.             }
  606.         }
  607.         // Any other printable characters are not allowed.
  608.         else if (wParam > SPACE)
  609.         {
  610.             MessageBeep((UINT)-1);
  611.             return 0;
  612.         }
  613.         break;
  614.     case WM_KEYDOWN:
  615.         switch (wParam)
  616.         {
  617.             // Arrow keys move between fields when the end of a field is reached.
  618.             case VK_LEFT:
  619.         case VK_RIGHT:
  620.         case VK_UP:
  621.         case VK_DOWN:
  622.             if (GetKeyState(VK_CONTROL) < 0)
  623.             {
  624.                 if ((wParam == VK_LEFT || wParam == VK_UP) && wChildID > 0)
  625.                 {
  626.                     SwitchFields(pipa, wChildID, wChildID-1,
  627.                                  0, CHARS_PER_FIELD);
  628.                     return 0;
  629.                 }
  630.                 else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
  631.                          && wChildID < NUM_FIELDS-1)
  632.                 {
  633.                     SwitchFields(pipa, wChildID, wChildID+1,
  634.                                  0, CHARS_PER_FIELD);
  635.                     return 0;
  636.                 }
  637.             }
  638.             else
  639.             {
  640.                 DWORD dwResult;
  641.                 WORD wStart, wEnd;
  642.                 dwResult = (DWORD)SendMessage(hWnd, EM_GETSEL, 0, 0L);
  643.                 wStart = LOWORD(dwResult);
  644.                 wEnd = HIWORD(dwResult);
  645.                 if (wStart == wEnd)
  646.                 {
  647.                     if ((wParam == VK_LEFT || wParam == VK_UP)
  648.                         && wStart == 0
  649.                         && wChildID > 0)
  650.                     {
  651.                         SwitchFields(pipa, wChildID, wChildID-1,
  652.                                      CHARS_PER_FIELD, CHARS_PER_FIELD);
  653.                         return 0;
  654.                     }
  655.                     else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
  656.                              && wChildID < NUM_FIELDS-1)
  657.                     {
  658.                         dwResult = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0L);
  659.                         if (wStart >= dwResult)
  660.                         {
  661.                             SwitchFields(pipa, wChildID, wChildID+1, 0, 0);
  662.                             return 0;
  663.                         }
  664.                     }
  665.                 }
  666.             }
  667.             break;
  668.             // Home jumps back to the beginning of the first field.
  669.             case VK_HOME:
  670.                 if (wChildID > 0)
  671.                 {
  672.                     SwitchFields(pipa, wChildID, 0, 0, 0);
  673.                     return 0;
  674.                 }
  675.             break;
  676.             // End scoots to the end of the last field.
  677.             case VK_END:
  678.                 if (wChildID < NUM_FIELDS-1)
  679.                 {
  680.                     SwitchFields(pipa, wChildID, NUM_FIELDS-1,
  681.                                  CHARS_PER_FIELD, CHARS_PER_FIELD);
  682.                     return 0;
  683.                 }
  684.             break;
  685.         } // switch (wParam)
  686.         break;
  687.     case WM_KILLFOCUS:
  688.         if ( !ExitField( pipa, wChildID ))
  689.         {
  690.             return 0;
  691.         }
  692.     } // switch (wMsg)
  693.     lresult = CallWindowProc( pipa->Children[wChildID].lpfnWndProc,
  694.                              hWnd, wMsg, wParam, lParam);
  695.     return lresult;
  696. }
  697. /*
  698.  Switch the focus from one field to another.
  699.  call
  700.  pipa = Pointer to the IPADDR structure.
  701.  iOld = Field we're leaving.
  702.  iNew = Field we're entering.
  703.  hNew = Window of field to goto
  704.  wStart = First character selected
  705.  wEnd = Last character selected + 1
  706.  returns
  707.  TRUE on success, FALSE on failure.
  708.  Only switches fields if the current field can be validated.
  709.  */
  710. BOOL SwitchFields(IPADDR *pipa, int iOld, int iNew, WORD wStart, WORD wEnd)
  711. {
  712.     if (!ExitField(pipa, iOld))    return FALSE;
  713.     EnterField(&(pipa->Children[iNew]), wStart, wEnd);
  714.     return TRUE;
  715. }
  716. /*
  717.  Set the focus to a specific field's window.
  718.  call
  719.  pField = pointer to field structure for the field.
  720.  wStart = First character selected
  721.  wEnd = Last character selected + 1
  722.  */
  723. void EnterField(FIELD *pField, WORD wStart, WORD wEnd)
  724. {
  725.     SetFocus(pField->hWnd);
  726.     SendMessage(pField->hWnd, EM_SETSEL, wStart, wEnd);
  727. }
  728. void SetFieldValue(IPADDR *pipa, int iField, int iValue)
  729. {
  730.     TCHAR szBuf[CHARS_PER_FIELD+1];
  731.     FIELD* pField = &(pipa->Children[iField]);
  732.     wsprintf(szBuf, TEXT("%d"), iValue);
  733.     SendMessage(pField->hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf);
  734. }
  735. /*
  736.  Exit a field.
  737.  call
  738.  pipa = pointer to IPADDR structure.
  739.  iField = field number being exited.
  740.  returns
  741.  TRUE if the user may exit the field.
  742.  FALSE if he may not.
  743.  */
  744. BOOL ExitField(IPADDR  *pipa, int iField)
  745. {
  746.     FIELD *pField;
  747.     int i;
  748.     NMIPADDRESS nm;
  749.     int iOldValue;
  750.     pField = &(pipa->Children[iField]);
  751.     i = GetFieldValue(pField);
  752.     iOldValue = i;
  753.     
  754.     nm.iField = iField;
  755.     nm.iValue = i;
  756.     
  757.     SendNotifyEx(pipa->hwndParent, pipa->hwnd, IPN_FIELDCHANGED, &nm.hdr, FALSE);
  758.     i = nm.iValue;
  759.     
  760.     if (i != -1) {
  761.         if (i < (int)(UINT)pField->byLow || i > (int)(UINT)pField->byHigh)
  762.         {
  763.             
  764.             if ( i < (int)(UINT) pField->byLow )
  765.             {
  766.                 /* too small */
  767.                 i = (int)(UINT)pField->byLow;
  768.             }
  769.             else
  770.             {
  771.                 /* must be bigger */
  772.                 i = (int)(UINT)pField->byHigh;
  773.             }
  774.             SetFieldValue(pipa, iField, i);
  775.             // CHEEBUGBUG: send notify up
  776.             return FALSE;
  777.         }
  778.     } 
  779.     if (iOldValue != i) {
  780.         SetFieldValue(pipa, iField, i);
  781.     }
  782.     return TRUE;
  783. }
  784. /*
  785.  Get the value stored in a field.
  786.  call
  787.  pField = pointer to the FIELD structure for the field.
  788.  returns
  789.  The value (0..255) or -1 if the field has not value.
  790.  */
  791. int GetFieldValue(FIELD *pField)
  792. {
  793.     WORD wLength;
  794.     TCHAR szBuf[CHARS_PER_FIELD+1];
  795.     INT i;
  796.     *(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
  797.     wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)(LPSTR)szBuf);
  798.     if (wLength != 0)
  799.     {
  800.         szBuf[wLength] = TEXT('');
  801.         i = StrToInt(szBuf);
  802.         return i;
  803.     }
  804.     else
  805.         return -1;
  806. }
  807. BOOL IsDBCS()
  808. {
  809.     LANGID langid;
  810.     langid = PRIMARYLANGID(GetThreadLocale());
  811.     if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
  812.     {
  813.         return (TRUE);
  814.     }
  815.     else
  816.     {
  817.         return (FALSE);
  818.     }
  819. }