1336 lines
39 KiB
C
1336 lines
39 KiB
C
/* Copyright (C) 1991, Microsoft Corporation, all rights reserved
|
|
|
|
ipaddr.c - TCP/IP Address custom control
|
|
|
|
November 9, 1992 Greg Strange
|
|
February 11, 1997 - Marco Chierotti (extend to IPv6 and TTL for DNS snapin)
|
|
*/
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "maskctrl.h" // Global IPAddress definitions
|
|
|
|
#define BUFFER_LEN 128 // length for static buffers
|
|
|
|
#define SPACE TEXT(' ')
|
|
#define BACK_SPACE 8
|
|
|
|
#define HEAD_ROOM 1 // space at top of control
|
|
#define LEAD_ROOM 0 // space at front of control
|
|
|
|
// 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;
|
|
FARPROC lpfnWndProc;
|
|
DWORD dwLow; // lowest allowed value for this field.
|
|
DWORD dwHigh; // Highest allowed value for this field.
|
|
UINT nChars; // # of chars for the field
|
|
UINT uiWidth; // width of the field in pixels
|
|
} FIELD;
|
|
|
|
|
|
/* class info struct for different types of control */
|
|
typedef struct tagCLS_INFO
|
|
{
|
|
TCHAR chFiller; //The character that is displayed between address fields.
|
|
LPCTSTR lpszFiller;
|
|
UINT nNumFields; // number of fields in the control
|
|
void (*lpfnInit)(int, FIELD*); // function to initialize the FIELD structs for a given field
|
|
BOOL (*lpfnValChar)(TCHAR); // function for field validation
|
|
DWORD (*lpfnStringToNumber)(LPTSTR, int); // function to change a field string into a number
|
|
void (*lpfnNumberToString)(LPTSTR, DWORD); // function to change a number into a field string
|
|
UINT (*lpfnMaxCharWidth)(HDC hDC); // function to get the max width of a char in edit fields
|
|
} CLS_INFO;
|
|
|
|
|
|
typedef struct tagCONTROL {
|
|
HWND hwndParent;
|
|
UINT uiMaxCharWidth;
|
|
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* ChildrenArr; // array of structs with info about each field
|
|
CLS_INFO* pClsInfo; // struct with info about the constrol type
|
|
int (*lpfnAlert)(HWND, DWORD, DWORD, DWORD);
|
|
} CONTROL;
|
|
|
|
|
|
// The following macros extract and store the CONTROL structure for a control.
|
|
#define IPADDRESS_EXTRA sizeof(DWORD)
|
|
|
|
#define GET_CONTROL_HANDLE(hWnd) ((HGLOBAL)(GetWindowLongPtr((hWnd), GWLP_USERDATA)))
|
|
#define SAVE_CONTROL_HANDLE(hWnd,x) (SetWindowLongPtr((hWnd), GWLP_USERDATA, (LONG_PTR)x))
|
|
|
|
|
|
/* internal IPAddress function prototypes */
|
|
|
|
LRESULT FAR PASCAL IPv4WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
|
|
LRESULT FAR PASCAL IPv6WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
|
|
LRESULT FAR PASCAL TTLWndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
|
|
|
|
LRESULT FAR PASCAL IPAddressFieldProc(HWND, UINT, WPARAM, LPARAM);
|
|
BOOL SwitchFields(CONTROL FAR *, LONG_PTR, LONG_PTR, UINT, UINT);
|
|
void EnterField(FIELD FAR *, UINT, UINT);
|
|
BOOL ExitField(CONTROL FAR *, LONG_PTR);
|
|
DWORD GetFieldValue(FIELD*, CLS_INFO*);
|
|
|
|
|
|
LOGFONT logfont;
|
|
BOOL g_bFontInitialized = FALSE;
|
|
|
|
|
|
void SetDefaultFont(LPCWSTR lpFontName, int nFontSize)
|
|
{
|
|
HDC dc;
|
|
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 (g_bFontInitialized)
|
|
return; // do it only once
|
|
|
|
dc = GetDC(NULL);
|
|
if (dc != NULL)
|
|
{
|
|
logfont.lfHeight = -(nFontSize*GetDeviceCaps(dc,LOGPIXELSY)/72);
|
|
logfont.lfCharSet = ANSI_CHARSET;
|
|
lstrcpy( logfont.lfFaceName, lpFontName);
|
|
|
|
ReleaseDC(NULL, dc);
|
|
}
|
|
g_bFontInitialized = TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL DNS_ControlsInitialize(HANDLE hInstance, LPCWSTR lpFontName, int nFontSize)
|
|
{
|
|
return DNS_ControlInit(hInstance, DNS_IP_V4_ADDRESS_CLASS, IPv4WndFn, lpFontName, nFontSize) &&
|
|
DNS_ControlInit(hInstance, DNS_IP_V6_ADDRESS_CLASS, IPv6WndFn, lpFontName, nFontSize) &&
|
|
DNS_ControlInit(hInstance, DNS_TTL_CLASS, TTLWndFn, lpFontName, nFontSize);
|
|
}
|
|
|
|
/*
|
|
DNS_ControlInit() - DNS custom controls initialization
|
|
call
|
|
hInstance = application instance
|
|
return
|
|
TRUE on success, FALSE on failure.
|
|
|
|
This function does all the one time initialization of custom
|
|
controls.
|
|
*/
|
|
BOOL PASCAL DNS_ControlInit(HANDLE hInstance, LPCTSTR lpszClassName, WNDPROC lpfnWndProc,
|
|
LPCWSTR lpFontName, int nFontSize)
|
|
{
|
|
LPWNDCLASS lpClassStruct;
|
|
BOOL bRes;
|
|
|
|
bRes = FALSE;
|
|
/* allocate memory for class structure */
|
|
lpClassStruct = (LPWNDCLASS)GlobalAlloc(GPTR, (DWORD)sizeof(WNDCLASS));
|
|
if (lpClassStruct)
|
|
{
|
|
/* define class attributes */
|
|
lpClassStruct->lpszClassName = lpszClassName;
|
|
lpClassStruct->hCursor = LoadCursor(NULL,IDC_IBEAM);
|
|
lpClassStruct->lpszMenuName = (LPCTSTR)NULL;
|
|
lpClassStruct->style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;//|CS_GLOBALCLASS;
|
|
lpClassStruct->lpfnWndProc = lpfnWndProc;
|
|
lpClassStruct->hInstance = hInstance;
|
|
lpClassStruct->hIcon = NULL;
|
|
lpClassStruct->cbWndExtra = IPADDRESS_EXTRA;
|
|
lpClassStruct->hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
|
|
|
|
/* register window class */
|
|
bRes = RegisterClass(lpClassStruct);
|
|
if (!bRes)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
if (HRESULT_CODE(dwError) == ERROR_CLASS_ALREADY_EXISTS)
|
|
bRes = TRUE;
|
|
}
|
|
GlobalFree(lpClassStruct);
|
|
}
|
|
SetDefaultFont(lpFontName, nFontSize);
|
|
return bRes;
|
|
}
|
|
|
|
|
|
/*
|
|
IPAddressWndFn() - Main window function for an IPAddress control.
|
|
|
|
call
|
|
hWnd handle to IPAddress window
|
|
wMsg message number
|
|
wParam word parameter
|
|
lParam long parameter
|
|
*/
|
|
|
|
void FormatIPAddress(LPTSTR pszString, DWORD* dwValue)
|
|
{
|
|
static TCHAR szBuf[3+1]; // 3 characters per octet + 1 for the '/0'
|
|
|
|
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'));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT FAR PASCAL IPAddressWndFnEx(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam, CLS_INFO* pClsInfo )
|
|
{
|
|
LRESULT lResult;
|
|
CONTROL *pControl;
|
|
UINT i;
|
|
|
|
lResult = TRUE;
|
|
|
|
switch( wMsg )
|
|
{
|
|
|
|
// 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;
|
|
|
|
FormatIPAddress(pszString, &dwValue[0]);
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
pControl->bCancelParentNotify = TRUE;
|
|
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
if (pszString[0] == 0)
|
|
{
|
|
szBuf[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szBuf, TEXT("%d"), dwValue[i]);
|
|
}
|
|
SendMessage(pControl->ChildrenArr[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);
|
|
*/
|
|
}
|
|
break;
|
|
|
|
case WM_GETTEXTLENGTH:
|
|
case WM_GETTEXT:
|
|
{
|
|
/*
|
|
int iFieldValue;
|
|
int srcPos, desPos;
|
|
DWORD dwValue[4];
|
|
TCHAR pszResult[30];
|
|
TCHAR *pszDest = (TCHAR *)lParam;
|
|
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
lResult = 0;
|
|
dwValue[0] = 0;
|
|
dwValue[1] = 0;
|
|
dwValue[2] = 0;
|
|
dwValue[3] = 0;
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
iFieldValue = GetFieldValue(&(pControl->ChildrenArr[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;
|
|
}
|
|
*/
|
|
}
|
|
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;
|
|
HMENU id;
|
|
UINT uiFieldStart;
|
|
FARPROC lpfnFieldProc;
|
|
|
|
pControl = (CONTROL*)GlobalAlloc(GMEM_FIXED, sizeof(CONTROL));
|
|
|
|
if (pControl)
|
|
{
|
|
HFONT OldFont;
|
|
RECT rect;
|
|
LPCREATESTRUCT lpCreateStruct;
|
|
|
|
lpCreateStruct = ((CREATESTRUCT *)lParam);
|
|
|
|
pControl->fEnabled = TRUE;
|
|
pControl->fPainted = FALSE;
|
|
pControl->fInMessageBox = FALSE;
|
|
pControl->hwndParent = lpCreateStruct->hwndParent;
|
|
pControl->bControlInFocus = FALSE;
|
|
pControl->bCancelParentNotify = FALSE;
|
|
pControl->pClsInfo = pClsInfo;
|
|
pControl->ChildrenArr = (FIELD*)GlobalAlloc(GMEM_FIXED, sizeof(FIELD)*(pClsInfo->nNumFields));
|
|
pControl->lpfnAlert = NULL;
|
|
|
|
if (!pControl->ChildrenArr)
|
|
{
|
|
GlobalFree(pControl);
|
|
pControl = 0;
|
|
|
|
DestroyWindow(hWnd);
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
(*(pClsInfo->lpfnInit))(i,&(pControl->ChildrenArr[i]));
|
|
}
|
|
|
|
hdc = GetDC(hWnd);
|
|
if (hdc != NULL)
|
|
{
|
|
GetClientRect(hWnd, &rect);
|
|
|
|
OldFont = SelectObject(hdc, CreateFontIndirect(&logfont));
|
|
pControl->uiMaxCharWidth = (*(pClsInfo->lpfnMaxCharWidth))(hdc);
|
|
GetCharWidth(hdc, pClsInfo->chFiller, pClsInfo->chFiller,
|
|
(int *)(&pControl->uiFillerWidth));
|
|
DeleteObject(SelectObject(hdc, OldFont ));
|
|
ReleaseDC(hWnd, hdc);
|
|
|
|
uiFieldStart = LEAD_ROOM;
|
|
lpfnFieldProc = MakeProcInstance((FARPROC)IPAddressFieldProc,
|
|
LPCS->hInstance);
|
|
|
|
id = (HMENU)GetWindowLongPtr(hWnd, GWLP_ID);
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
pControl->ChildrenArr[i].uiWidth =
|
|
(pControl->ChildrenArr[i].nChars) * (pControl->uiMaxCharWidth+2);
|
|
|
|
pControl->ChildrenArr[i].hWnd = CreateWindowEx(0,
|
|
TEXT("Edit"),
|
|
NULL,
|
|
WS_CHILD | WS_VISIBLE,
|
|
uiFieldStart,
|
|
HEAD_ROOM,
|
|
pControl->ChildrenArr[i].uiWidth,
|
|
(rect.bottom-rect.top),
|
|
hWnd,
|
|
id,
|
|
lpCreateStruct->hInstance,
|
|
(LPVOID)NULL);
|
|
|
|
SAVE_CONTROL_HANDLE(pControl->ChildrenArr[i].hWnd, i);
|
|
SendMessage(pControl->ChildrenArr[i].hWnd, EM_LIMITTEXT,
|
|
pControl->ChildrenArr[i].nChars, 0L);
|
|
|
|
SendMessage(pControl->ChildrenArr[i].hWnd, WM_SETFONT,
|
|
(WPARAM)CreateFontIndirect(&logfont), TRUE);
|
|
|
|
// Disable IME support for the ip editor
|
|
ImmAssociateContext(pControl->ChildrenArr[i].hWnd, NULL);
|
|
|
|
pControl->ChildrenArr[i].lpfnWndProc =
|
|
(FARPROC) GetWindowLongPtr(pControl->ChildrenArr[i].hWnd,
|
|
GWLP_WNDPROC);
|
|
|
|
SetWindowLongPtr(pControl->ChildrenArr[i].hWnd,
|
|
GWLP_WNDPROC, (LONG_PTR)lpfnFieldProc);
|
|
|
|
uiFieldStart += pControl->ChildrenArr[i].uiWidth
|
|
+ pControl->uiFillerWidth;
|
|
} // for
|
|
|
|
SAVE_CONTROL_HANDLE(hWnd, pControl);
|
|
|
|
//
|
|
// need to make control wider
|
|
//
|
|
uiFieldStart -= pControl->uiFillerWidth;
|
|
{
|
|
RECT r;
|
|
POINT p1;
|
|
POINT p2;
|
|
|
|
GetWindowRect(hWnd, &r); // screen coords
|
|
p1.x = r.left;
|
|
p1.y = r.top;
|
|
p2.x = r.right;
|
|
p2.y = r.bottom;
|
|
ScreenToClient(lpCreateStruct->hwndParent, &p1);
|
|
ScreenToClient(lpCreateStruct->hwndParent, &p2);
|
|
p2.x = p1.x + uiFieldStart + 2;
|
|
MoveWindow(hWnd, p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, FALSE);
|
|
}
|
|
}
|
|
} // if
|
|
else
|
|
{
|
|
DestroyWindow(hWnd);
|
|
}
|
|
}
|
|
lResult = 0;
|
|
break;
|
|
|
|
case WM_PAINT: /* paint control window */
|
|
{
|
|
PAINTSTRUCT Ps;
|
|
RECT rect;
|
|
RECT headRect; /* area before the first edit box */
|
|
COLORREF TextColor;
|
|
COLORREF cRef;
|
|
HFONT OldFont;
|
|
HBRUSH hbr;
|
|
BOOL fPaintAsEnabled;
|
|
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
fPaintAsEnabled = pControl->fEnabled;
|
|
if (fPaintAsEnabled)
|
|
{
|
|
/* onlys some of the edit controls might be enabled */
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
if (!IsWindowEnabled(pControl->ChildrenArr[i].hWnd))
|
|
{
|
|
fPaintAsEnabled = FALSE; /* need disabled background */
|
|
break;
|
|
} // if
|
|
} // for
|
|
} // if
|
|
|
|
BeginPaint(hWnd, (LPPAINTSTRUCT)&Ps);
|
|
OldFont = SelectObject( Ps.hdc, CreateFontIndirect(&logfont));
|
|
GetClientRect(hWnd, &rect);
|
|
|
|
if (fPaintAsEnabled)
|
|
{
|
|
TextColor = GetSysColor(COLOR_WINDOWTEXT);
|
|
cRef = GetSysColor(COLOR_WINDOW);
|
|
}
|
|
else
|
|
{
|
|
TextColor = GetSysColor(COLOR_GRAYTEXT);
|
|
cRef = GetSysColor(COLOR_3DFACE);
|
|
}
|
|
|
|
SetBkColor(Ps.hdc, cRef);
|
|
SetTextColor(Ps.hdc, TextColor);
|
|
|
|
hbr = CreateSolidBrush(cRef);
|
|
if (hbr != NULL)
|
|
{
|
|
FillRect(Ps.hdc, &rect, hbr);
|
|
DeleteObject(hbr);
|
|
|
|
SetRect(&headRect, 0, HEAD_ROOM, LEAD_ROOM, (rect.bottom-rect.top));
|
|
CopyRect(&rect, &headRect);
|
|
|
|
for (i = 0; i < pClsInfo->nNumFields-1; ++i)
|
|
{
|
|
rect.left += pControl->ChildrenArr[i].uiWidth;
|
|
rect.right = rect.left + pControl->uiFillerWidth;
|
|
|
|
if (IsWindowEnabled(pControl->ChildrenArr[i].hWnd))
|
|
{
|
|
TextColor = GetSysColor(COLOR_WINDOWTEXT);
|
|
cRef = GetSysColor(COLOR_WINDOW);
|
|
}
|
|
else
|
|
{
|
|
TextColor = GetSysColor(COLOR_GRAYTEXT);
|
|
cRef = GetSysColor(COLOR_3DFACE);
|
|
}
|
|
SetBkColor(Ps.hdc, cRef);
|
|
SetTextColor(Ps.hdc, TextColor);
|
|
hbr = CreateSolidBrush(cRef);
|
|
if (hbr != NULL)
|
|
{
|
|
if (i == 0)
|
|
FillRect(Ps.hdc, &headRect, hbr);
|
|
FillRect(Ps.hdc, &rect, hbr);
|
|
DeleteObject(hbr);
|
|
}
|
|
ExtTextOut(Ps.hdc, rect.left, HEAD_ROOM, ETO_OPAQUE, &rect, pClsInfo->lpszFiller, 1, NULL);
|
|
rect.left = rect.right;
|
|
}
|
|
}
|
|
|
|
pControl->fPainted = TRUE;
|
|
|
|
DeleteObject(SelectObject(Ps.hdc, OldFont));
|
|
EndPaint(hWnd, &Ps);
|
|
}
|
|
break;
|
|
|
|
case WM_SETFOCUS : /* get focus - display caret */
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
/* set the focus on the first enabled field */
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
if (IsWindowEnabled(pControl->ChildrenArr[i].hWnd))
|
|
{
|
|
EnterField(&(pControl->ChildrenArr[i]), 0, pControl->ChildrenArr[i].nChars);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN : /* left button depressed - fall through */
|
|
SetFocus(hWnd);
|
|
break;
|
|
|
|
case WM_ENABLE:
|
|
{
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
pControl->fEnabled = (BOOL)wParam;
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
EnableWindow(pControl->ChildrenArr[i].hWnd, (BOOL)wParam);
|
|
}
|
|
if (pControl->fPainted)
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY :
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
if (pControl == NULL)
|
|
break; // memory already freed (MFC DestroyWindow() call)
|
|
|
|
// Restore all the child window procedures before we delete our memory block.
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
SendMessage(pControl->ChildrenArr[i].hWnd, WM_DESTROY, 0, 0);
|
|
SetWindowLongPtr(pControl->ChildrenArr[i].hWnd, GWLP_WNDPROC,
|
|
(LONG_PTR)pControl->ChildrenArr[i].lpfnWndProc);
|
|
}
|
|
// free memory and reset window long
|
|
GlobalFree(pControl->ChildrenArr);
|
|
GlobalFree(pControl);
|
|
SAVE_CONTROL_HANDLE(hWnd, NULL);
|
|
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;
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
if (!pControl->fInMessageBox)
|
|
{
|
|
hFocus = GetFocus();
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
if (pControl->ChildrenArr[i].hWnd == hFocus)
|
|
break;
|
|
|
|
if (i >= pClsInfo->nNumFields)
|
|
{
|
|
SendMessage(pControl->hwndParent, WM_COMMAND,
|
|
MAKEWPARAM(GetWindowLong(hWnd, GWL_ID),
|
|
EN_KILLFOCUS), (LPARAM)hWnd);
|
|
pControl->bControlInFocus = FALSE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EN_SETFOCUS:
|
|
{
|
|
HWND hFocus;
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
if (!pControl->fInMessageBox)
|
|
{
|
|
hFocus = (HWND)lParam;
|
|
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
if (pControl->ChildrenArr[i].hWnd == hFocus)
|
|
break;
|
|
|
|
// send a focus message when the
|
|
if (i < pClsInfo->nNumFields && 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
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EN_CHANGE:
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
if (pControl->bCancelParentNotify == FALSE)
|
|
{
|
|
SendMessage(pControl->hwndParent, WM_COMMAND,
|
|
MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
|
|
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// Get the value of the control fields.
|
|
case DNS_MASK_CTRL_GET:
|
|
{
|
|
DWORD* dwArr;
|
|
UINT nArrSize;
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
dwArr = (DWORD*)wParam;
|
|
nArrSize = (UINT)lParam;
|
|
lResult = 0;
|
|
for (i = 0; (i < pClsInfo->nNumFields) && ( i < nArrSize); ++i)
|
|
{
|
|
dwArr[i] = GetFieldValue(&(pControl->ChildrenArr[i]), pClsInfo);
|
|
if (dwArr[i] != FIELD_EMPTY)
|
|
++lResult;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Clear all fields to blanks.
|
|
case DNS_MASK_CTRL_CLEAR:
|
|
{
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
pControl->bCancelParentNotify = TRUE;
|
|
if (wParam == -1)
|
|
{
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
SendMessage(pControl->ChildrenArr[i].hWnd, WM_SETTEXT,
|
|
0, (LPARAM) (LPSTR) TEXT(""));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendMessage(pControl->ChildrenArr[wParam].hWnd, WM_SETTEXT,
|
|
0, (LPARAM)(LPSTR) TEXT(""));
|
|
}
|
|
pControl->bCancelParentNotify = FALSE;
|
|
SendMessage(pControl->hwndParent, WM_COMMAND,
|
|
MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
|
|
}
|
|
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 DNS_MASK_CTRL_SET:
|
|
{
|
|
DWORD* dwArr;
|
|
UINT nArrSize;
|
|
static TCHAR szBuf[BUFFER_LEN+1];
|
|
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
pControl->bCancelParentNotify = TRUE;
|
|
dwArr = (DWORD*)wParam;
|
|
nArrSize = (UINT)lParam;
|
|
|
|
for (i = 0; i < (pClsInfo->nNumFields) && ( i < nArrSize); ++i)
|
|
{
|
|
(*(pControl->pClsInfo->lpfnNumberToString))(szBuf,dwArr[i]);
|
|
SendMessage(pControl->ChildrenArr[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);
|
|
}
|
|
break;
|
|
|
|
case DNS_MASK_CTRL_SET_LOW_RANGE:
|
|
case DNS_MASK_CTRL_SET_HI_RANGE:
|
|
if (wParam < pClsInfo->nNumFields)
|
|
{
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
if (wMsg == DNS_MASK_CTRL_SET_LOW_RANGE)
|
|
pControl->ChildrenArr[wParam].dwLow = (DWORD)lParam;
|
|
else
|
|
pControl->ChildrenArr[wParam].dwHigh = (DWORD)lParam;
|
|
}
|
|
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 DNS_MASK_CTRL_SETFOCUS:
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
if (wParam >= pClsInfo->nNumFields)
|
|
{
|
|
for (wParam = 0; wParam < pClsInfo->nNumFields; ++wParam)
|
|
if (GetFieldValue(&(pControl->ChildrenArr[wParam]), pControl->pClsInfo) == FIELD_EMPTY) break;
|
|
if (wParam >= pClsInfo->nNumFields) wParam = 0;
|
|
}
|
|
EnterField(&(pControl->ChildrenArr[wParam]), 0, pControl->ChildrenArr[wParam].nChars);
|
|
break;
|
|
|
|
// Determine whether all four subfields are blank
|
|
case DNS_MASK_CTRL_ISBLANK:
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
|
|
lResult = TRUE;
|
|
for (i = 0; i < pClsInfo->nNumFields; ++i)
|
|
{
|
|
if (GetFieldValue(&(pControl->ChildrenArr[i]), pControl->pClsInfo) != FIELD_EMPTY)
|
|
{
|
|
lResult = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case DNS_MASK_CTRL_SET_ALERT:
|
|
{
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
pControl->lpfnAlert = (int (*)(HWND, DWORD, DWORD, DWORD))(wParam);
|
|
lResult = TRUE;
|
|
}
|
|
break;
|
|
case DNS_MASK_CTRL_ENABLE_FIELD:
|
|
{
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
|
|
//int nField = (int)wParam;
|
|
if ( ((int)wParam >= 0) && ((UINT)wParam < pClsInfo->nNumFields) )
|
|
{
|
|
EnableWindow(pControl->ChildrenArr[(int)wParam].hWnd, (BOOL)lParam);
|
|
}
|
|
if (pControl->fPainted)
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
}
|
|
break;
|
|
default:
|
|
lResult = 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)
|
|
{
|
|
CONTROL *pControl;
|
|
FIELD *pField;
|
|
HWND hControlWindow;
|
|
LONG_PTR nChildID;
|
|
LRESULT lresult;
|
|
|
|
hControlWindow = GetParent(hWnd);
|
|
if (!hControlWindow)
|
|
return 0;
|
|
|
|
pControl = (CONTROL *)GET_CONTROL_HANDLE(hControlWindow);
|
|
nChildID = (LONG_PTR)GET_CONTROL_HANDLE(hWnd);
|
|
pField = &(pControl->ChildrenArr[nChildID]);
|
|
|
|
|
|
if (pField->hWnd != hWnd)
|
|
return 0;
|
|
|
|
switch (wMsg)
|
|
{
|
|
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'))
|
|
if ( (*(pControl->pClsInfo->lpfnValChar))((TCHAR)wParam))
|
|
{
|
|
DWORD dwResult;
|
|
|
|
dwResult = (DWORD)CallWindowProc((WNDPROC)pControl->ChildrenArr[nChildID].lpfnWndProc,
|
|
hWnd, wMsg, wParam, lParam);
|
|
dwResult = (DWORD)SendMessage(hWnd, EM_GETSEL, 0, 0L);
|
|
|
|
if (dwResult == (DWORD)MAKELPARAM((WORD)(pField->nChars), (WORD)(pField->nChars))
|
|
&& ExitField(pControl, (UINT)nChildID)
|
|
&& nChildID < (int)pControl->pClsInfo->nNumFields-1)
|
|
{
|
|
EnterField(&(pControl->ChildrenArr[nChildID+1]),
|
|
0, pField->nChars);
|
|
}
|
|
return dwResult;
|
|
}
|
|
|
|
// spaces and periods fills out the current field and then if possible,
|
|
// goes to the next field.
|
|
else if ((TCHAR)wParam == pControl->pClsInfo->chFiller || wParam == SPACE )
|
|
{
|
|
DWORD dwResult;
|
|
dwResult = (DWORD)SendMessage(hWnd, EM_GETSEL, 0, 0L);
|
|
if (dwResult != 0L && HIWORD(dwResult) == LOWORD(dwResult)
|
|
&& ExitField(pControl, nChildID))
|
|
{
|
|
if (nChildID >= (int)pControl->pClsInfo->nNumFields-1)
|
|
MessageBeep((UINT)-1);
|
|
else
|
|
{
|
|
EnterField(&(pControl->ChildrenArr[nChildID+1]),
|
|
0, pControl->ChildrenArr[nChildID+1].nChars);
|
|
}
|
|
}
|
|
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 (nChildID > 0 && SendMessage(hWnd, EM_GETSEL, 0, 0L) == 0L)
|
|
{
|
|
if (SwitchFields(pControl,
|
|
nChildID,
|
|
nChildID-1,
|
|
pControl->ChildrenArr[nChildID-1].nChars,
|
|
pControl->ChildrenArr[nChildID-1].nChars)
|
|
&& SendMessage(pControl->ChildrenArr[nChildID-1].hWnd,
|
|
EM_LINELENGTH,
|
|
(WPARAM)0,
|
|
(LPARAM)0L) != 0L
|
|
&& IsWindowEnabled(pControl->ChildrenArr[nChildID-1].hWnd))
|
|
{
|
|
SendMessage(pControl->ChildrenArr[nChildID-1].hWnd,
|
|
wMsg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Any other printable characters are not allowed.
|
|
else if (wParam > SPACE)
|
|
{
|
|
MessageBeep((UINT)-1);
|
|
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) && nChildID > 0)
|
|
{
|
|
SwitchFields(pControl, nChildID, nChildID-1, 0, pField->nChars);
|
|
return 0;
|
|
}
|
|
else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
|
|
&& nChildID < (int)pControl->pClsInfo->nNumFields-1)
|
|
{
|
|
SwitchFields(pControl, nChildID, nChildID+1, 0, pField->nChars);
|
|
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
|
|
&& nChildID > 0)
|
|
{
|
|
SwitchFields(pControl, nChildID, nChildID-1, pField->nChars, pField->nChars);
|
|
return 0;
|
|
}
|
|
else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
|
|
&& nChildID < (int)pControl->pClsInfo->nNumFields-1)
|
|
{
|
|
dwResult = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0L);
|
|
if (wStart >= dwResult)
|
|
{
|
|
SwitchFields(pControl, nChildID, nChildID+1, 0, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Home jumps back to the beginning of the first field.
|
|
case VK_HOME:
|
|
if (nChildID > 0)
|
|
{
|
|
SwitchFields(pControl, nChildID, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
// End scoots to the end of the last field.
|
|
case VK_END:
|
|
if (nChildID < (int)pControl->pClsInfo->nNumFields-1)
|
|
{
|
|
SwitchFields(pControl, nChildID, (pControl->pClsInfo->nNumFields)-1, pField->nChars, pField->nChars);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
|
|
} // switch (wParam)
|
|
|
|
break;
|
|
|
|
case WM_KILLFOCUS:
|
|
if ( !ExitField( pControl, nChildID ))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
} // switch (wMsg)
|
|
|
|
lresult = CallWindowProc( (WNDPROC)pControl->ChildrenArr[nChildID].lpfnWndProc,
|
|
hWnd, wMsg, wParam, lParam);
|
|
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, LONG_PTR nOld, LONG_PTR nNew, UINT nStart, UINT nEnd)
|
|
{
|
|
if (!ExitField(pControl, nOld)) return FALSE;
|
|
EnterField(&(pControl->ChildrenArr[nNew]), nStart, nEnd);
|
|
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, UINT nStart, UINT nEnd)
|
|
{
|
|
SetFocus(pField->hWnd);
|
|
SendMessage(pField->hWnd, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
|
|
}
|
|
|
|
|
|
/*
|
|
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, LONG_PTR nField)
|
|
{
|
|
HWND hControlWnd;
|
|
HWND hDialog;
|
|
WORD wLength;
|
|
FIELD *pField;
|
|
static TCHAR szBuf[BUFFER_LEN+1];
|
|
DWORD xVal;
|
|
|
|
pField = &(pControl->ChildrenArr[nField]);
|
|
|
|
*(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
|
|
wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)(LPSTR)szBuf);
|
|
if (wLength != 0)
|
|
{
|
|
szBuf[wLength] = TEXT('\0');
|
|
xVal = (*(pControl->pClsInfo->lpfnStringToNumber))(szBuf,(int)wLength);
|
|
if (xVal < pField->dwLow || xVal > pField->dwHigh)
|
|
{
|
|
if ( xVal < pField->dwLow )
|
|
{
|
|
/* too small */
|
|
wsprintf(szBuf, TEXT("%d"), pField->dwLow );
|
|
}
|
|
else
|
|
{
|
|
/* must be bigger */
|
|
wsprintf(szBuf, TEXT("%d"), pField->dwHigh );
|
|
}
|
|
SendMessage(pField->hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf);
|
|
if ((hControlWnd = GetParent(pField->hWnd)) != NULL
|
|
&& (hDialog = GetParent(hControlWnd)) != NULL)
|
|
{
|
|
pControl->fInMessageBox = TRUE;
|
|
if (pControl->lpfnAlert != NULL) // call user provided hook
|
|
{
|
|
(*(pControl->lpfnAlert))(hDialog, xVal, pField->dwLow, pField->dwHigh);
|
|
}
|
|
else
|
|
{
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
}
|
|
pControl->fInMessageBox = FALSE;
|
|
SendMessage(pField->hWnd, EM_SETSEL, 0, pField->nChars);
|
|
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.
|
|
*/
|
|
DWORD GetFieldValue(FIELD *pField, CLS_INFO* pClsInfo)
|
|
{
|
|
WORD wLength;
|
|
static TCHAR szBuf[BUFFER_LEN+1];
|
|
|
|
*(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
|
|
wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)(LPSTR)szBuf);
|
|
if (wLength != 0)
|
|
{
|
|
return (*(pClsInfo->lpfnStringToNumber))(szBuf,wLength);
|
|
}
|
|
else
|
|
return FIELD_EMPTY;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD DecimalStringToNumber(LPCTSTR lpszBuf, int nLen)
|
|
{
|
|
DWORD x;
|
|
int j;
|
|
for (x=0, j=0;j<nLen;j++)
|
|
{
|
|
x = x*10+lpszBuf[j]-TEXT('0'); // assume valid char
|
|
}
|
|
return x;
|
|
}
|
|
|
|
void NumberToDecimalString(LPTSTR lpszBuf, DWORD dwX)
|
|
{
|
|
if (dwX == FIELD_EMPTY)
|
|
{
|
|
lpszBuf[0] = 0x0; //NULL
|
|
}
|
|
else
|
|
{
|
|
wsprintf(lpszBuf, TEXT("%d"), (UINT)dwX);
|
|
}
|
|
}
|
|
|
|
void NumberToHexString(LPTSTR lpszBuf, DWORD dwX)
|
|
{
|
|
wsprintf(lpszBuf, TEXT("%x"), (UINT)dwX);
|
|
}
|
|
|
|
|
|
DWORD HexStringToNumber(LPCTSTR lpszBuf, int nLen)
|
|
{
|
|
DWORD x;
|
|
int j;
|
|
for (x=0, j=0;j<nLen;j++)
|
|
{
|
|
DWORD digit = 0;
|
|
if (lpszBuf[j] >= TEXT('0') && lpszBuf[j] <= TEXT('9'))
|
|
digit = lpszBuf[j]-TEXT('0');
|
|
else if (lpszBuf[j] >= TEXT('A') && lpszBuf[j] <= TEXT('F'))
|
|
digit = lpszBuf[j]-TEXT('A') + 10;
|
|
else// assume 'a' to 'f'
|
|
digit = lpszBuf[j]-TEXT('a') + 10;
|
|
x = x*16+digit;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
|
|
|
|
BOOL ValidateDecimalChar(TCHAR ch)
|
|
{
|
|
// allow only digits
|
|
WCHAR sz[2];
|
|
BOOL b;
|
|
|
|
sz[0]=ch;
|
|
sz[1]=L'';
|
|
b = (ch >= TEXT('0') && ch <= TEXT('9'));
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL ValidateHexChar(TCHAR ch)
|
|
{
|
|
// allow only digits
|
|
return ( (ch >= TEXT('0') && ch <= TEXT('9')) ||
|
|
(ch >= TEXT('a') && ch <= TEXT('f')) ||
|
|
(ch >= TEXT('A') && ch <= TEXT('F')) );
|
|
}
|
|
|
|
|
|
void InitIPv4Field(int nIndex, FIELD* pField)
|
|
{
|
|
nIndex; // Must use formal parameters for /W4
|
|
pField->dwLow = 0;//MIN_FIELD_VALUE;
|
|
pField->dwHigh = 255; //MAX_FIELD_VALUE;
|
|
pField->nChars = 3; //CHARS_PER_FIELD;
|
|
}
|
|
|
|
void InitIPv6Field(int nIndex, FIELD* pField)
|
|
{
|
|
nIndex; // Must user formal parameters for /W4
|
|
pField->dwLow = 0; //MIN_FIELD_VALUE;
|
|
pField->dwHigh = 0xFFFF; //MAX_FIELD_VALUE;
|
|
pField->nChars = 4; //CHARS_PER_FIELD;
|
|
}
|
|
|
|
|
|
void InitTTLField(int nIndex, FIELD* pField)
|
|
{
|
|
pField->dwLow = 0;
|
|
switch (nIndex)
|
|
{
|
|
case 0: // days
|
|
pField->dwHigh = 49710;
|
|
pField->nChars = 5;
|
|
break;
|
|
case 1: // hours
|
|
pField->dwHigh = 23;
|
|
pField->nChars = 2;
|
|
break;
|
|
case 2: // minutes
|
|
pField->dwHigh = 59;
|
|
pField->nChars = 2;
|
|
break;
|
|
case 3: // seconds
|
|
pField->dwHigh = 59;
|
|
pField->nChars = 2;
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
UINT _MaxCharWidthHelper(HDC hDC, UINT iFirstChar, UINT iLastChar)
|
|
{
|
|
FLOAT fFract[10] = {0};
|
|
INT nWidth[10] = {0};
|
|
int i;
|
|
FLOAT maxVal;
|
|
FLOAT curWidth;
|
|
UINT retVal;
|
|
|
|
retVal = 8; // good default if we fail
|
|
|
|
if (GetCharWidthFloat(hDC, iFirstChar, iLastChar,fFract) &&
|
|
GetCharWidth(hDC,iFirstChar, iLastChar, nWidth))
|
|
{
|
|
maxVal = 0.0;
|
|
for (i=0;i<10;i++)
|
|
{
|
|
curWidth = fFract[i] + (FLOAT)nWidth[i];
|
|
if (curWidth > maxVal)
|
|
maxVal = curWidth;
|
|
}
|
|
if (maxVal > ((FLOAT)((UINT)maxVal)))
|
|
retVal = (UINT) (maxVal+1);
|
|
else
|
|
retVal = (UINT)maxVal;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
UINT MaxCharWidthDecimal(HDC hDC)
|
|
{
|
|
return _MaxCharWidthHelper(hDC,TEXT('0'), TEXT('9'));
|
|
}
|
|
|
|
UINT MaxCharWidthHex(HDC hDC)
|
|
{
|
|
UINT retVal;
|
|
UINT nMax1;
|
|
UINT nMax2;
|
|
UINT nMax3;
|
|
|
|
retVal = 0;
|
|
nMax1 = _MaxCharWidthHelper(hDC,TEXT('0'), TEXT('9'));
|
|
if (nMax1 > retVal)
|
|
retVal = nMax1;
|
|
nMax2 = _MaxCharWidthHelper(hDC,TEXT('a'), TEXT('f'));
|
|
if (nMax2 > retVal)
|
|
retVal = nMax2;
|
|
nMax3 = _MaxCharWidthHelper(hDC,TEXT('A'), TEXT('F'));
|
|
if (nMax3 > retVal)
|
|
retVal = nMax3;
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/* class info structs for the various types */
|
|
CLS_INFO _IPv4ClsInfo = { TEXT('.'),
|
|
TEXT("."),
|
|
4,
|
|
InitIPv4Field,
|
|
ValidateDecimalChar,
|
|
DecimalStringToNumber,
|
|
NumberToDecimalString,
|
|
MaxCharWidthDecimal
|
|
};
|
|
|
|
CLS_INFO _IPv6ClsInfo = { TEXT(':'),
|
|
TEXT(":"),
|
|
8,
|
|
InitIPv6Field,
|
|
ValidateHexChar,
|
|
HexStringToNumber,
|
|
NumberToHexString,
|
|
MaxCharWidthHex
|
|
};
|
|
CLS_INFO _TTLClsInfo = { TEXT(':'),
|
|
TEXT(":"),
|
|
4,
|
|
InitTTLField,
|
|
ValidateDecimalChar,
|
|
DecimalStringToNumber,
|
|
NumberToDecimalString,
|
|
MaxCharWidthDecimal
|
|
};
|
|
|
|
|
|
|
|
|
|
LRESULT FAR PASCAL IPv4WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
return IPAddressWndFnEx( hWnd, wMsg, wParam, lParam , &_IPv4ClsInfo);
|
|
}
|
|
|
|
LRESULT FAR PASCAL IPv6WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
return IPAddressWndFnEx( hWnd, wMsg, wParam, lParam , &_IPv6ClsInfo);
|
|
}
|
|
|
|
LRESULT FAR PASCAL TTLWndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
return IPAddressWndFnEx( hWnd, wMsg, wParam, lParam , &_TTLClsInfo);
|
|
}
|