Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1257 lines
41 KiB

/* 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;
}