|
|
/* Copyright (c) 1991, Microsoft Corporation, all rights reserved
** ** ipaddr.c ** IP Address custom edit control ** ** 11/09/92 Greg Strange ** Original code ** ** 09/07/95 Steve Cobb ** Lifted TerryK/TRomano-updated version from NCPA, deleting IPDLL ** stuff, and making minor RAS-related customizations. */
#include <windows.h> // Win32 core
#include <uiutil.h> // Our public header
#include <debug.h> // Trace and assert
#define IPADDRESS_CLASS TEXT("RasIpAddress")
// Extended style bit causes the ip address control to
// correct the ip address so that it is contiguous (for submasks)
#define IPADDR_EX_STYLE_CONTIGUOUS 0x1
/* Module instance handle set when custom control is initialized.
*/ static HANDLE g_hLibInstance = NULL;
/* String ID of message displayed when user enters a field value that is out
** of range. Something like "You must choose a value from %1 to %2 for this ** field." Set when the custom control is initialized. */ static DWORD g_dwBadIpAddrRange = 0;
/* String ID of the popup title when the range error above is displayed. Set
** when the custom control is initialized. */ static DWORD g_dwErrorTitle = 0;
// The character that is displayed between address fields.
#define FILLER TEXT('.')
#define SZFILLER TEXT(".")
#define SPACE TEXT(' ')
#define BACK_SPACE 8
/* Min, max values */ #define NUM_FIELDS 4
#define CHARS_PER_FIELD 3
#define HEAD_ROOM 1 // space at top of control
#define LEAD_ROOM 3 // space at front of control
#define MIN_FIELD_VALUE 0 // default minimum allowable field value
#define MAX_FIELD_VALUE 255 // default maximum allowable field value
// All the information unique to one control is stuffed in one of these
// structures in global memory and the handle to the memory is stored in the
// Windows extra space.
typedef struct tagFIELD { HANDLE hWnd; WNDPROC lpfnWndProc; BYTE byLow; // lowest allowed value for this field.
BYTE byHigh; // Highest allowed value for this field.
} FIELD;
typedef struct tagCONTROL { HWND hwndParent; UINT uiFieldWidth; UINT uiFillerWidth; BOOL fEnabled; BOOL fPainted; BOOL bControlInFocus; // TRUE if the control is already in focus, dont't send another focus command
BOOL bCancelParentNotify; // Don't allow the edit controls to notify parent if TRUE
BOOL fInMessageBox; // Set when a message box is displayed so that
// we don't send a EN_KILLFOCUS message when
// we receive the EN_KILLFOCUS message for the
// current field.
FIELD Children[NUM_FIELDS]; } CONTROL;
// The following macros extract and store the CONTROL structure for a control.
#define IPADDRESS_EXTRA (sizeof(DWORD) + sizeof(DWORD))
#define GET_CONTROL_HANDLE(hWnd) ((HGLOBAL)(GetWindowLongPtr((hWnd), GWLP_USERDATA)))
#define SAVE_CONTROL_HANDLE(hWnd,x) (SetWindowLongPtr((hWnd), GWLP_USERDATA, (ULONG_PTR)x))
#define IPADDR_GET_SUBSTYLE(hwnd) (GetWindowLong((hwnd), 4))
#define IPADDR_SET_SUBSTYLE(hwnd, style) (SetWindowLong((hwnd), 4, (style)))
/* internal IPAddress function prototypes */ LRESULT FAR PASCAL IPAddressWndFn( HWND, UINT, WPARAM, LPARAM ); LRESULT FAR PASCAL IPAddressFieldProc(HWND, UINT, WPARAM, LPARAM); BOOL SwitchFields(CONTROL FAR *, int, int, WORD, WORD); void EnterField(FIELD FAR *, WORD, WORD); BOOL ExitField(CONTROL FAR *, int iField); int GetFieldValue(FIELD FAR *);
LOGFONT logfont;
void SetDefaultFont( ) { LANGID langid = PRIMARYLANGID(GetThreadLocale()); BOOL fIsDbcs = (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN); HDC hdc = GetDC(NULL);
if(NULL == hdc) { return; }
logfont.lfWidth = 0; logfont.lfEscapement = 0; logfont.lfOrientation = 0; logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logfont.lfQuality = DEFAULT_QUALITY; logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS; logfont.lfUnderline = 0; logfont.lfStrikeOut = 0; logfont.lfItalic = 0; logfont.lfWeight = FW_NORMAL;
if (fIsDbcs) { logfont.lfHeight = -(9*GetDeviceCaps(hdc,LOGPIXELSY)/72); logfont.lfCharSet = DEFAULT_CHARSET; } else { logfont.lfHeight = -(8*GetDeviceCaps(hdc,LOGPIXELSY)/72); logfont.lfCharSet = ANSI_CHARSET; } lstrcpy( logfont.lfFaceName,TEXT("MS Shell Dlg"));
ReleaseDC(NULL, hdc); }
/*
IpAddrInit() - IPAddress custom control initialization call hInstance = library or application instance dwErrorTitle = String ID of error popup title dwBadIpAddrRange = String ID of bad range popup text, e.g. "You must choose a value between %1 and %2 for this field." return TRUE on success, FALSE on failure.
This function does all the one time initialization of IPAddress custom controls. Specifically it creates the IPAddress window class. */ int FAR PASCAL IpAddrInit( IN HANDLE hInstance, IN DWORD dwErrorTitle, IN DWORD dwBadIpAddrRange ) { HGLOBAL hClassStruct; LPWNDCLASS lpClassStruct;
/* register IPAddress window if necessary */ if ( g_hLibInstance == NULL ) {
/* allocate memory for class structure */ hClassStruct = GlobalAlloc( GHND, (DWORD)sizeof(WNDCLASS) ); if ( hClassStruct ) {
/* lock it down */ lpClassStruct = (LPWNDCLASS)GlobalLock( hClassStruct ); if ( lpClassStruct ) {
/* define class attributes */ lpClassStruct->lpszClassName = IPADDRESS_CLASS; lpClassStruct->hCursor = LoadCursor(NULL,IDC_IBEAM); lpClassStruct->lpszMenuName = (LPCTSTR)NULL; lpClassStruct->style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS|CS_GLOBALCLASS; lpClassStruct->lpfnWndProc = IPAddressWndFn; lpClassStruct->hInstance = hInstance; lpClassStruct->hIcon = NULL; lpClassStruct->cbWndExtra = IPADDRESS_EXTRA; lpClassStruct->hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
/* register IPAddress window class */ g_hLibInstance = ( RegisterClass(lpClassStruct) ) ? hInstance : NULL; GlobalUnlock( hClassStruct ); } GlobalFree( hClassStruct ); } } SetDefaultFont();
g_dwErrorTitle = dwErrorTitle; g_dwBadIpAddrRange = dwBadIpAddrRange;
return( g_hLibInstance ? 1:0 ); }
// Use this function to force the ip address entered to
// be contiguous (series of 1's followed by a series of 0's).
// This is useful for entering valid submasks
//
// Returns NO_ERROR if successful, error code otherwise
//
DWORD APIENTRY IpAddr_ForceContiguous(HWND hwndIpAddr) { DWORD dwOldStyle;
// Set the last error information so that we can
// return an error correctly
SetLastError(NO_ERROR);
// Set the extended style of the given window so
// that it descriminates the address entered.
dwOldStyle = IPADDR_GET_SUBSTYLE(hwndIpAddr); IPADDR_SET_SUBSTYLE(hwndIpAddr, dwOldStyle | IPADDR_EX_STYLE_CONTIGUOUS);
return GetLastError(); }
void FormatIPAddress(LPTSTR pszString, DWORD* dwValue) { static TCHAR szBuf[CHARS_PER_FIELD+1]; int nField, nPos; BOOL fFinish = FALSE;
dwValue[0] = 0; dwValue[1] = 0; dwValue[2] = 0; dwValue[3] = 0;
if (pszString[0] == 0) return;
for( nField = 0, nPos = 0; !fFinish; nPos++) { if (( pszString[nPos]<TEXT('0')) || (pszString[nPos]>TEXT('9'))) { // not a number
nField++; fFinish = (nField == 4); } else { dwValue[nField] *= 10; dwValue[nField] += (pszString[nPos]-TEXT('0')); } } }
// This function causes the ip address entered into hwndIpAddr to be
// corrected so that it is contiguous.
DWORD IpAddrMakeContiguous(HWND hwndIpAddr) { DWORD i, dwNewMask, dwMask;
// Read in the current address
SendMessage(hwndIpAddr, IP_GETADDRESS, 0, (LPARAM)&dwMask);
// Find out where the first '1' is in binary going right to left
dwNewMask = 0; for (i = 0; i < sizeof(dwMask)*8; i++) { dwNewMask |= 1 << i; if (dwNewMask & dwMask) { break; } }
// At this point, dwNewMask is 000...0111... If we inverse it,
// we get a mask that can be or'd with dwMask to fill in all of
// the holes.
dwNewMask = dwMask | ~dwNewMask;
// If the new mask is different, correct it here
if (dwMask != dwNewMask) { WCHAR pszAddr[32]; wsprintfW(pszAddr, L"%d.%d.%d.%d", FIRST_IPADDRESS (dwNewMask), SECOND_IPADDRESS(dwNewMask), THIRD_IPADDRESS (dwNewMask), FOURTH_IPADDRESS(dwNewMask)); SendMessage(hwndIpAddr, IP_SETADDRESS, 0, (LPARAM)pszAddr); }
return NO_ERROR; }
LRESULT FAR PASCAL IPAddressWndFn( hWnd, wMsg, wParam, lParam ) HWND hWnd; UINT wMsg; WPARAM wParam; LPARAM lParam; { LONG lResult; HGLOBAL hControl; CONTROL *pControl; int i;
lResult = TRUE;
switch( wMsg ) {
case WM_HELP: { HWND hwndParent = GetParent(hWnd); HELPINFO* p = (HELPINFO*)lParam;
p->hItemHandle = hWnd; p->iCtrlId = (INT) GetWindowLongPtr(hWnd, GWLP_ID); TRACE4( "IPAddressWndFn(HLP,t=%d,id=%d,h=$%08x,p=$%08x)", p->iContextType,p->iCtrlId,p->hItemHandle,hwndParent);
SendMessage(hwndParent, WM_HELP, wParam, lParam); return 0; } break; case WM_CONTEXTMENU: { SendMessage(GetParent(hWnd), WM_CONTEXTMENU, (WPARAM)GetParent(hWnd), 0); return 0; } break; // use empty string (not NULL) to set to blank
case WM_SETTEXT: { static TCHAR szBuf[CHARS_PER_FIELD+1]; DWORD dwValue[4]; LPTSTR pszString = (LPTSTR)lParam;
if (!pszString) pszString = TEXT("0.0.0.0");
FormatIPAddress(pszString, &dwValue[0]);
hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl); pControl->bCancelParentNotify = TRUE;
for (i = 0; i < NUM_FIELDS; ++i) { if (pszString[0] == 0) { szBuf[0] = 0; } else { wsprintf(szBuf, TEXT("%d"), dwValue[i]); } SendMessage(pControl->Children[i].hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf); }
pControl->bCancelParentNotify = FALSE;
SendMessage(pControl->hwndParent, WM_COMMAND, MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
GlobalUnlock(hControl); } break;
case WM_GETTEXTLENGTH: case WM_GETTEXT: { int iFieldValue; int srcPos, desPos; DWORD dwValue[4]; TCHAR pszResult[30]; TCHAR *pszDest = (TCHAR *)lParam;
hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
lResult = 0; dwValue[0] = 0; dwValue[1] = 0; dwValue[2] = 0; dwValue[3] = 0; for (i = 0; i < NUM_FIELDS; ++i) { iFieldValue = GetFieldValue(&(pControl->Children[i])); if (iFieldValue == -1) iFieldValue = 0; else ++lResult; dwValue[i] = iFieldValue; } wsprintf( pszResult, TEXT("%d.%d.%d.%d"), dwValue[0], dwValue[1], dwValue[2], dwValue[3] ); if ( wMsg == WM_GETTEXTLENGTH ) { lResult = lstrlen( pszResult ); } else { for ( srcPos=0, desPos=0; (srcPos+1<(INT)wParam) && (pszResult[srcPos]!=TEXT('\0')); ) { pszDest[desPos++] = pszResult[srcPos++]; } pszDest[desPos]=TEXT('\0'); lResult = desPos; } GlobalUnlock(hControl); } break;
case WM_GETDLGCODE : lResult = DLGC_WANTCHARS; break;
case WM_NCCREATE: SetWindowLong(hWnd, GWL_EXSTYLE, (GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_CLIENTEDGE)); lResult = TRUE; break;
case WM_CREATE : /* create pallette window */ { HDC hdc; UINT uiFieldStart; FARPROC lpfnFieldProc;
hControl = GlobalAlloc(GMEM_MOVEABLE, sizeof(CONTROL)); if (hControl) { HFONT OldFont; RECT rect;
#define LPCS ((CREATESTRUCT *)lParam)
pControl = (CONTROL *)GlobalLock(hControl); pControl->fEnabled = TRUE; pControl->fPainted = FALSE; pControl->fInMessageBox = FALSE; pControl->hwndParent = LPCS->hwndParent; pControl->uiFillerWidth = 1; pControl->bControlInFocus = FALSE; pControl->bCancelParentNotify = FALSE;
hdc = GetDC(hWnd); GetClientRect(hWnd, &rect); OldFont = SelectObject( hdc, CreateFontIndirect(&logfont) ); if( NULL != OldFont ) { HFONT NewFont; GetCharWidth(hdc, FILLER, FILLER, (int *)(&pControl->uiFillerWidth)); NewFont = SelectObject(hdc, OldFont ); if( NULL != NewFont ) { DeleteObject( NewFont ); } } ReleaseDC(hWnd, hdc);
pControl->uiFieldWidth = (LPCS->cx - LEAD_ROOM - pControl->uiFillerWidth *(NUM_FIELDS-1)) / NUM_FIELDS; uiFieldStart = LEAD_ROOM;
lpfnFieldProc = MakeProcInstance((FARPROC)IPAddressFieldProc, LPCS->hInstance);
for (i = 0; i < NUM_FIELDS; ++i) { pControl->Children[i].byLow = MIN_FIELD_VALUE; pControl->Children[i].byHigh = MAX_FIELD_VALUE;
pControl->Children[i].hWnd = CreateWindowEx(0, TEXT("Edit"), NULL, WS_CHILD | WS_VISIBLE | ES_CENTER, uiFieldStart, HEAD_ROOM, pControl->uiFieldWidth, (rect.bottom-rect.top), hWnd, (HMENU)UlongToPtr(i), LPCS->hInstance, (LPVOID)NULL);
SendMessage(pControl->Children[i].hWnd, EM_LIMITTEXT, CHARS_PER_FIELD, 0L);
SendMessage(pControl->Children[i].hWnd, WM_SETFONT, (WPARAM)CreateFontIndirect(&logfont), TRUE);
pControl->Children[i].lpfnWndProc = (WNDPROC)GetWindowLongPtr(pControl->Children[i].hWnd, GWLP_WNDPROC);
SetWindowLongPtr(pControl->Children[i].hWnd, GWLP_WNDPROC, (ULONG_PTR)lpfnFieldProc);
uiFieldStart += pControl->uiFieldWidth + pControl->uiFillerWidth; }
GlobalUnlock(hControl); SAVE_CONTROL_HANDLE(hWnd, hControl);
#undef LPCS
} else DestroyWindow(hWnd); } lResult = 0; break;
case WM_PAINT: /* paint control window */ { PAINTSTRUCT Ps; RECT rect; UINT uiFieldStart; COLORREF TextColor; COLORREF cRef; HFONT OldFont, NewFont, TmpFont; HBRUSH hbr;
//Add return value check for bug 199026
if ( BeginPaint(hWnd, (LPPAINTSTRUCT)&Ps) ) { NewFont = CreateFontIndirect(&logfont); if (NewFont) { OldFont = SelectObject( Ps.hdc, NewFont ); if (OldFont) { GetClientRect(hWnd, &rect); hControl = GET_CONTROL_HANDLE(hWnd); if (hControl) { pControl = (CONTROL *)GlobalLock(hControl); if (pControl) { if (pControl->fEnabled) { TextColor = GetSysColor(COLOR_WINDOWTEXT); cRef = GetSysColor(COLOR_WINDOW);
} else { TextColor = GetSysColor(COLOR_GRAYTEXT); cRef = GetSysColor(COLOR_3DFACE); }
if (cRef) SetBkColor(Ps.hdc, cRef);
if (TextColor) SetTextColor(Ps.hdc, TextColor);
hbr = CreateSolidBrush(cRef); if ( NULL != hbr ) { FillRect(Ps.hdc, &rect, hbr); DeleteObject(hbr); }
SetRect(&rect, 0, HEAD_ROOM, pControl->uiFillerWidth, (rect.bottom-rect.top));
ExtTextOut(Ps.hdc, rect.left, HEAD_ROOM, ETO_OPAQUE, &rect, L" ", 1, NULL);
for (i = 0; i < NUM_FIELDS-1; ++i) { rect.left += pControl->uiFieldWidth + pControl->uiFillerWidth;
rect.right += rect.left + pControl->uiFillerWidth;
ExtTextOut(Ps.hdc, rect.left, HEAD_ROOM, ETO_OPAQUE, &rect, SZFILLER, 1, NULL); }
pControl->fPainted = TRUE;
GlobalUnlock(hControl); } } TmpFont = SelectObject(Ps.hdc, OldFont);
if (TmpFont) { NewFont = TmpFont; } else { NewFont = OldFont; } }
DeleteObject(NewFont); } EndPaint(hWnd, &Ps); } } break;
case WM_SETFOCUS : /* get focus - display caret */ hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl); EnterField(&(pControl->Children[0]), 0, CHARS_PER_FIELD); GlobalUnlock(hControl); break;
case WM_LBUTTONDOWN : /* left button depressed - fall through */ SetFocus(hWnd); break;
case WM_ENABLE: { hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl); pControl->fEnabled = (BOOL)wParam; for (i = 0; i < NUM_FIELDS; ++i) { EnableWindow(pControl->Children[i].hWnd, (BOOL)wParam); } if (pControl->fPainted) InvalidateRect(hWnd, NULL, FALSE); GlobalUnlock(hControl); } break;
case WM_DESTROY : hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
// Restore all the child window procedures before we delete our memory block.
for (i = 0; i < NUM_FIELDS; ++i) { SetWindowLongPtr(pControl->Children[i].hWnd, GWLP_WNDPROC, (ULONG_PTR)pControl->Children[i].lpfnWndProc); }
GlobalUnlock(hControl); GlobalFree(hControl); break;
case WM_COMMAND: switch (HIWORD(wParam)) { // One of the fields lost the focus, see if it lost the focus to another field
// of if we've lost the focus altogether. If its lost altogether, we must send
// an EN_KILLFOCUS notification on up the ladder.
case EN_KILLFOCUS: { HWND hFocus;
hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
if (!pControl->fInMessageBox) { hFocus = GetFocus(); for (i = 0; i < NUM_FIELDS; ++i) if (pControl->Children[i].hWnd == hFocus) break;
if (i >= NUM_FIELDS) { // Before sending the message up the ladder, make sure that
// the ip address is contiguous if needed
if (IPADDR_GET_SUBSTYLE(hWnd) & IPADDR_EX_STYLE_CONTIGUOUS) IpAddrMakeContiguous(hWnd);
SendMessage(pControl->hwndParent, WM_COMMAND, MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_KILLFOCUS), (LPARAM)hWnd); pControl->bControlInFocus = FALSE; } } GlobalUnlock(hControl); } break;
case EN_SETFOCUS: { HWND hFocus;
hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
if (!pControl->fInMessageBox) { hFocus = (HWND)lParam;
for (i = 0; i < NUM_FIELDS; ++i) if (pControl->Children[i].hWnd == hFocus) break;
// send a focus message when the
if (i < NUM_FIELDS && pControl->bControlInFocus == FALSE) { SendMessage(pControl->hwndParent, WM_COMMAND, MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_SETFOCUS), (LPARAM)hWnd);
pControl->bControlInFocus = TRUE; // only set the focus once
} } GlobalUnlock(hControl); } break;
case EN_CHANGE: hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
if (pControl->bCancelParentNotify == FALSE) { SendMessage(pControl->hwndParent, WM_COMMAND, MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
}
GlobalUnlock(hControl);
break; } break;
// Get the value of the IP Address. The address is placed in the DWORD pointed
// to by lParam and the number of non-blank fields is returned.
case IP_GETADDRESS: { int iFieldValue; DWORD dwValue;
hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
lResult = 0; dwValue = 0; for (i = 0; i < NUM_FIELDS; ++i) { iFieldValue = GetFieldValue(&(pControl->Children[i])); if (iFieldValue == -1) iFieldValue = 0; else ++lResult; dwValue = (dwValue << 8) + iFieldValue; } *((DWORD *)lParam) = dwValue;
GlobalUnlock(hControl); } break;
// Clear all fields to blanks.
case IP_CLEARADDRESS: { hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl); pControl->bCancelParentNotify = TRUE; for (i = 0; i < NUM_FIELDS; ++i) { SendMessage(pControl->Children[i].hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) TEXT("")); } pControl->bCancelParentNotify = FALSE; SendMessage(pControl->hwndParent, WM_COMMAND, MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
GlobalUnlock(hControl); } break;
// Set the value of the IP Address. The address is in the lParam with the
// first address byte being the high byte, the second being the second byte,
// and so on. A lParam value of -1 removes the address.
case IP_SETADDRESS: { static TCHAR szBuf[CHARS_PER_FIELD+1]; DWORD dwValue[4]; LPTSTR pszString = (LPTSTR)lParam;
FormatIPAddress(pszString, &dwValue[0]);
hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
pControl->bCancelParentNotify = TRUE;
for (i = 0; i < NUM_FIELDS; ++i) { if (pszString[0] == 0) { szBuf[0] =0; } else { wsprintf(szBuf, TEXT("%d"), dwValue[i]); } SendMessage(pControl->Children[i].hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf); }
pControl->bCancelParentNotify = FALSE;
SendMessage(pControl->hwndParent, WM_COMMAND, MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
GlobalUnlock(hControl); } break;
case IP_SETRANGE: if (wParam < NUM_FIELDS) { hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
pControl->Children[wParam].byLow = LOBYTE(LOWORD(lParam)); pControl->Children[wParam].byHigh = HIBYTE(LOWORD(lParam));
GlobalUnlock(hControl); } break;
// Set the focus to this control.
// wParam = the field number to set focus to, or -1 to set the focus to the
// first non-blank field.
case IP_SETFOCUS: hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
if (wParam >= NUM_FIELDS) { for (wParam = 0; wParam < NUM_FIELDS; ++wParam) if (GetFieldValue(&(pControl->Children[wParam])) == -1) break; if (wParam >= NUM_FIELDS) wParam = 0; } EnterField(&(pControl->Children[wParam]), 0, CHARS_PER_FIELD);
GlobalUnlock(hControl); break;
// Determine whether all four subfields are blank
case IP_ISBLANK: hControl = GET_CONTROL_HANDLE(hWnd); pControl = (CONTROL *)GlobalLock(hControl);
lResult = TRUE; for (i = 0; i < NUM_FIELDS; ++i) { if (GetFieldValue(&(pControl->Children[i])) != -1) { lResult = FALSE; break; } }
GlobalUnlock(hControl); break;
default: lResult = (LONG) DefWindowProc( hWnd, wMsg, wParam, lParam ); break; } return( lResult ); }
/*
IPAddressFieldProc() - Edit field window procedure
This function sub-classes each edit field. */ LRESULT FAR PASCAL IPAddressFieldProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { HANDLE hControl; CONTROL *pControl; FIELD *pField; HWND hControlWindow; WORD wChildID; LRESULT lresult;
if (!(hControlWindow = GetParent(hWnd))) return 0;
hControl = GET_CONTROL_HANDLE(hControlWindow); pControl = (CONTROL *)GlobalLock(hControl); wChildID = (WORD)GetWindowLong(hWnd, GWL_ID); pField = &(pControl->Children[wChildID]); if (pField->hWnd != hWnd) return 0;
switch (wMsg) { case WM_CONTEXTMENU: { SendMessage(GetParent(hWnd), WM_CONTEXTMENU, (WPARAM)GetParent(hWnd), 0); return 0; } break; case WM_HELP: { HWND hwndParent = GetParent(hWnd); HELPINFO* p = (HELPINFO*)lParam;
p->hItemHandle = hWnd; p->iCtrlId = (INT) GetWindowLongPtr(hWnd, GWLP_ID); TRACE4( "IPAddressFieldProc(HLP,t=%d,id=%d,h=$%08x,p=$%08x)", p->iContextType,p->iCtrlId,p->hItemHandle,hwndParent);
SendMessage(hwndParent, WM_HELP, wParam, lParam); return 0; } break; case WM_DESTROY: DeleteObject( (HGDIOBJ)SendMessage( hWnd, WM_GETFONT, 0, 0 )); return 0; case WM_CHAR:
// Typing in the last digit in a field, skips to the next field.
if (wParam >= TEXT('0') && wParam <= TEXT('9')) { DWORD dwResult;
dwResult = (DWORD)CallWindowProc(pControl->Children[wChildID].lpfnWndProc, hWnd, wMsg, wParam, lParam); dwResult = (DWORD) SendMessage(hWnd, EM_GETSEL, 0, 0L);
if (dwResult == MAKELPARAM(CHARS_PER_FIELD, CHARS_PER_FIELD) && ExitField(pControl, wChildID) && wChildID < NUM_FIELDS-1) { EnterField(&(pControl->Children[wChildID+1]), 0, CHARS_PER_FIELD); } GlobalUnlock( hControl ); return dwResult; }
// spaces and periods fills out the current field and then if possible,
// goes to the next field.
else if (wParam == FILLER || wParam == SPACE ) { DWORD dwResult; dwResult = (DWORD) SendMessage(hWnd, EM_GETSEL, 0, 0L); if (dwResult != 0L && HIWORD(dwResult) == LOWORD(dwResult) && ExitField(pControl, wChildID)) { if (wChildID >= NUM_FIELDS-1) MessageBeep((UINT)-1); else { EnterField(&(pControl->Children[wChildID+1]), 0, CHARS_PER_FIELD); } } GlobalUnlock( hControl ); return 0; }
// Backspaces go to the previous field if at the beginning of the current field.
// Also, if the focus shifts to the previous field, the backspace must be
// processed by that field.
else if (wParam == BACK_SPACE) { if (wChildID > 0 && SendMessage(hWnd, EM_GETSEL, 0, 0L) == 0L) { if (SwitchFields(pControl, wChildID, wChildID-1, CHARS_PER_FIELD, CHARS_PER_FIELD) && SendMessage(pControl->Children[wChildID-1].hWnd, EM_LINELENGTH, 0, 0L) != 0L) { SendMessage(pControl->Children[wChildID-1].hWnd, wMsg, wParam, lParam); } GlobalUnlock( hControl ); return 0; } }
// Any other printable characters are not allowed.
else if (wParam > SPACE) { MessageBeep((UINT)-1); GlobalUnlock( hControl ); return 0; } break;
case WM_KEYDOWN: switch (wParam) {
// Arrow keys move between fields when the end of a field is reached.
case VK_LEFT: case VK_RIGHT: case VK_UP: case VK_DOWN: if (GetKeyState(VK_CONTROL) < 0) { if ((wParam == VK_LEFT || wParam == VK_UP) && wChildID > 0) { SwitchFields(pControl, wChildID, wChildID-1, 0, CHARS_PER_FIELD); GlobalUnlock( hControl ); return 0; } else if ((wParam == VK_RIGHT || wParam == VK_DOWN) && wChildID < NUM_FIELDS-1) { SwitchFields(pControl, wChildID, wChildID+1, 0, CHARS_PER_FIELD); GlobalUnlock( hControl ); return 0; } } else { DWORD dwResult; WORD wStart, wEnd;
dwResult = (DWORD) SendMessage(hWnd, EM_GETSEL, 0, 0L); wStart = LOWORD(dwResult); wEnd = HIWORD(dwResult); if (wStart == wEnd) { if ((wParam == VK_LEFT || wParam == VK_UP) && wStart == 0 && wChildID > 0) { SwitchFields(pControl, wChildID, wChildID-1, CHARS_PER_FIELD, CHARS_PER_FIELD); GlobalUnlock( hControl ); return 0; } else if ((wParam == VK_RIGHT || wParam == VK_DOWN) && wChildID < NUM_FIELDS-1) { dwResult = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0L); if (wStart >= dwResult) { SwitchFields(pControl, wChildID, wChildID+1, 0, 0); GlobalUnlock( hControl ); return 0; } } } } break;
// Home jumps back to the beginning of the first field.
case VK_HOME: if (wChildID > 0) { SwitchFields(pControl, wChildID, 0, 0, 0); GlobalUnlock( hControl ); return 0; } break;
// End scoots to the end of the last field.
case VK_END: if (wChildID < NUM_FIELDS-1) { SwitchFields(pControl, wChildID, NUM_FIELDS-1, CHARS_PER_FIELD, CHARS_PER_FIELD); GlobalUnlock( hControl ); return 0; } break;
} // switch (wParam)
break;
case WM_KILLFOCUS: if ( !ExitField( pControl, wChildID )) { GlobalUnlock( hControl ); return 0; }
} // switch (wMsg)
lresult = CallWindowProc(pControl->Children[wChildID].lpfnWndProc, hWnd, wMsg, wParam, lParam); GlobalUnlock( hControl ); return lresult; }
/*
Switch the focus from one field to another. call pControl = Pointer to the CONTROL structure. iOld = Field we're leaving. iNew = Field we're entering. hNew = Window of field to goto wStart = First character selected wEnd = Last character selected + 1 returns TRUE on success, FALSE on failure.
Only switches fields if the current field can be validated. */ BOOL SwitchFields(CONTROL *pControl, int iOld, int iNew, WORD wStart, WORD wEnd) { if (!ExitField(pControl, iOld)) return FALSE; EnterField(&(pControl->Children[iNew]), wStart, wEnd); return TRUE; }
/*
Set the focus to a specific field's window. call pField = pointer to field structure for the field. wStart = First character selected wEnd = Last character selected + 1 */ void EnterField(FIELD *pField, WORD wStart, WORD wEnd) { SetFocus(pField->hWnd); SendMessage(pField->hWnd, EM_SETSEL, wStart, wEnd); }
/*
Exit a field. call pControl = pointer to CONTROL structure. iField = field number being exited. returns TRUE if the user may exit the field. FALSE if he may not. */ BOOL ExitField(CONTROL *pControl, int iField) { HWND hControlWnd; HWND hDialog; WORD wLength; FIELD *pField; static TCHAR szBuf[CHARS_PER_FIELD+1]; int i,j;
pField = &(pControl->Children[iField]); *(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1; wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)szBuf); if (wLength != 0) { szBuf[wLength] = TEXT('\0'); for (j=0,i=0;j<(INT)wLength;j++) { i=i*10+szBuf[j]-TEXT('0'); } if (i < (int)(UINT)pField->byLow || i > (int)(UINT)pField->byHigh) { if ( i < (int)(UINT) pField->byLow ) { /* too small */ wsprintf(szBuf, TEXT("%d"), (int)(UINT)pField->byLow ); } else { /* must be bigger */ wsprintf(szBuf, TEXT("%d"), (int)(UINT)pField->byHigh ); } SendMessage(pField->hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf); if ((hControlWnd = GetParent(pField->hWnd)) != NULL && (hDialog = GetParent(hControlWnd)) != NULL) { MSGARGS msgargs; TCHAR szLow[ 50 ]; TCHAR szHigh[ 50 ];
pControl->fInMessageBox = TRUE;
ZeroMemory( &msgargs, sizeof(msgargs) ); msgargs.dwFlags = MB_ICONEXCLAMATION + MB_OK; wsprintf( szLow, TEXT("%d"), (int )pField->byLow ); msgargs.apszArgs[ 0 ] = szLow; wsprintf( szHigh, TEXT("%d"), (int )pField->byHigh ); msgargs.apszArgs[ 1 ] = szHigh;
MsgDlgUtil( hDialog, g_dwBadIpAddrRange, &msgargs, g_hLibInstance, g_dwErrorTitle );
pControl->fInMessageBox = FALSE; SendMessage(pField->hWnd, EM_SETSEL, 0, CHARS_PER_FIELD); return FALSE; } } } return TRUE; }
/*
Get the value stored in a field. call pField = pointer to the FIELD structure for the field. returns The value (0..255) or -1 if the field has not value. */ int GetFieldValue(FIELD *pField) { WORD wLength; static TCHAR szBuf[CHARS_PER_FIELD+1]; INT i,j;
*(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1; wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)szBuf); if (wLength != 0) { szBuf[wLength] = TEXT('\0'); for (j=0,i=0;j<(INT)wLength;j++) { i=i*10+szBuf[j]-TEXT('0'); } return i; } else return -1; }
|