Source code of Windows XP (NT5)
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.

1335 lines
39 KiB

  1. /* Copyright (C) 1991, Microsoft Corporation, all rights reserved
  2. ipaddr.c - TCP/IP Address custom control
  3. November 9, 1992 Greg Strange
  4. February 11, 1997 - Marco Chierotti (extend to IPv6 and TTL for DNS snapin)
  5. */
  6. #pragma hdrstop
  7. #include <windows.h>
  8. #include <stdlib.h>
  9. #include "maskctrl.h" // Global IPAddress definitions
  10. #define BUFFER_LEN 128 // length for static buffers
  11. #define SPACE TEXT(' ')
  12. #define BACK_SPACE 8
  13. #define HEAD_ROOM 1 // space at top of control
  14. #define LEAD_ROOM 0 // space at front of control
  15. // All the information unique to one control is stuffed in one of these
  16. // structures in global memory and the handle to the memory is stored in the
  17. // Windows extra space.
  18. typedef struct tagFIELD {
  19. HANDLE hWnd;
  20. FARPROC lpfnWndProc;
  21. DWORD dwLow; // lowest allowed value for this field.
  22. DWORD dwHigh; // Highest allowed value for this field.
  23. UINT nChars; // # of chars for the field
  24. UINT uiWidth; // width of the field in pixels
  25. } FIELD;
  26. /* class info struct for different types of control */
  27. typedef struct tagCLS_INFO
  28. {
  29. TCHAR chFiller; //The character that is displayed between address fields.
  30. LPCTSTR lpszFiller;
  31. UINT nNumFields; // number of fields in the control
  32. void (*lpfnInit)(int, FIELD*); // function to initialize the FIELD structs for a given field
  33. BOOL (*lpfnValChar)(TCHAR); // function for field validation
  34. DWORD (*lpfnStringToNumber)(LPTSTR, int); // function to change a field string into a number
  35. void (*lpfnNumberToString)(LPTSTR, DWORD); // function to change a number into a field string
  36. UINT (*lpfnMaxCharWidth)(HDC hDC); // function to get the max width of a char in edit fields
  37. } CLS_INFO;
  38. typedef struct tagCONTROL {
  39. HWND hwndParent;
  40. UINT uiMaxCharWidth;
  41. UINT uiFillerWidth;
  42. BOOL fEnabled;
  43. BOOL fPainted;
  44. BOOL bControlInFocus; // TRUE if the control is already in focus, dont't send another focus command
  45. BOOL bCancelParentNotify; // Don't allow the edit controls to notify parent if TRUE
  46. BOOL fInMessageBox; // Set when a message box is displayed so that
  47. // we don't send a EN_KILLFOCUS message when
  48. // we receive the EN_KILLFOCUS message for the
  49. // current field.
  50. FIELD* ChildrenArr; // array of structs with info about each field
  51. CLS_INFO* pClsInfo; // struct with info about the constrol type
  52. int (*lpfnAlert)(HWND, DWORD, DWORD, DWORD);
  53. } CONTROL;
  54. // The following macros extract and store the CONTROL structure for a control.
  55. #define IPADDRESS_EXTRA sizeof(DWORD)
  56. #define GET_CONTROL_HANDLE(hWnd) ((HGLOBAL)(GetWindowLongPtr((hWnd), GWLP_USERDATA)))
  57. #define SAVE_CONTROL_HANDLE(hWnd,x) (SetWindowLongPtr((hWnd), GWLP_USERDATA, (LONG_PTR)x))
  58. /* internal IPAddress function prototypes */
  59. LRESULT FAR PASCAL IPv4WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
  60. LRESULT FAR PASCAL IPv6WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
  61. LRESULT FAR PASCAL TTLWndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
  62. LRESULT FAR PASCAL IPAddressFieldProc(HWND, UINT, WPARAM, LPARAM);
  63. BOOL SwitchFields(CONTROL FAR *, LONG_PTR, LONG_PTR, UINT, UINT);
  64. void EnterField(FIELD FAR *, UINT, UINT);
  65. BOOL ExitField(CONTROL FAR *, LONG_PTR);
  66. DWORD GetFieldValue(FIELD*, CLS_INFO*);
  67. LOGFONT logfont;
  68. BOOL g_bFontInitialized = FALSE;
  69. void SetDefaultFont(LPCWSTR lpFontName, int nFontSize)
  70. {
  71. HDC dc;
  72. logfont.lfWidth = 0;
  73. logfont.lfEscapement = 0;
  74. logfont.lfOrientation = 0;
  75. logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  76. logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  77. logfont.lfQuality = DEFAULT_QUALITY;
  78. logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  79. logfont.lfUnderline = 0;
  80. logfont.lfStrikeOut = 0;
  81. logfont.lfItalic = 0;
  82. logfont.lfWeight = FW_NORMAL;
  83. if (g_bFontInitialized)
  84. return; // do it only once
  85. dc = GetDC(NULL);
  86. if (dc != NULL)
  87. {
  88. logfont.lfHeight = -(nFontSize*GetDeviceCaps(dc,LOGPIXELSY)/72);
  89. logfont.lfCharSet = ANSI_CHARSET;
  90. lstrcpy( logfont.lfFaceName, lpFontName);
  91. ReleaseDC(NULL, dc);
  92. }
  93. g_bFontInitialized = TRUE;
  94. }
  95. /////////////////////////////////////////////////////////////////////////////
  96. BOOL PASCAL DNS_ControlsInitialize(HANDLE hInstance, LPCWSTR lpFontName, int nFontSize)
  97. {
  98. return DNS_ControlInit(hInstance, DNS_IP_V4_ADDRESS_CLASS, IPv4WndFn, lpFontName, nFontSize) &&
  99. DNS_ControlInit(hInstance, DNS_IP_V6_ADDRESS_CLASS, IPv6WndFn, lpFontName, nFontSize) &&
  100. DNS_ControlInit(hInstance, DNS_TTL_CLASS, TTLWndFn, lpFontName, nFontSize);
  101. }
  102. /*
  103. DNS_ControlInit() - DNS custom controls initialization
  104. call
  105. hInstance = application instance
  106. return
  107. TRUE on success, FALSE on failure.
  108. This function does all the one time initialization of custom
  109. controls.
  110. */
  111. BOOL PASCAL DNS_ControlInit(HANDLE hInstance, LPCTSTR lpszClassName, WNDPROC lpfnWndProc,
  112. LPCWSTR lpFontName, int nFontSize)
  113. {
  114. LPWNDCLASS lpClassStruct;
  115. BOOL bRes;
  116. bRes = FALSE;
  117. /* allocate memory for class structure */
  118. lpClassStruct = (LPWNDCLASS)GlobalAlloc(GPTR, (DWORD)sizeof(WNDCLASS));
  119. if (lpClassStruct)
  120. {
  121. /* define class attributes */
  122. lpClassStruct->lpszClassName = lpszClassName;
  123. lpClassStruct->hCursor = LoadCursor(NULL,IDC_IBEAM);
  124. lpClassStruct->lpszMenuName = (LPCTSTR)NULL;
  125. lpClassStruct->style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;//|CS_GLOBALCLASS;
  126. lpClassStruct->lpfnWndProc = lpfnWndProc;
  127. lpClassStruct->hInstance = hInstance;
  128. lpClassStruct->hIcon = NULL;
  129. lpClassStruct->cbWndExtra = IPADDRESS_EXTRA;
  130. lpClassStruct->hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
  131. /* register window class */
  132. bRes = RegisterClass(lpClassStruct);
  133. if (!bRes)
  134. {
  135. DWORD dwError = GetLastError();
  136. if (HRESULT_CODE(dwError) == ERROR_CLASS_ALREADY_EXISTS)
  137. bRes = TRUE;
  138. }
  139. GlobalFree(lpClassStruct);
  140. }
  141. SetDefaultFont(lpFontName, nFontSize);
  142. return bRes;
  143. }
  144. /*
  145. IPAddressWndFn() - Main window function for an IPAddress control.
  146. call
  147. hWnd handle to IPAddress window
  148. wMsg message number
  149. wParam word parameter
  150. lParam long parameter
  151. */
  152. void FormatIPAddress(LPTSTR pszString, DWORD* dwValue)
  153. {
  154. static TCHAR szBuf[3+1]; // 3 characters per octet + 1 for the '/0'
  155. int nField, nPos;
  156. BOOL fFinish = FALSE;
  157. dwValue[0] = 0; dwValue[1] = 0; dwValue[2] = 0; dwValue[3] = 0;
  158. if (pszString[0] == 0)
  159. return;
  160. for( nField = 0, nPos = 0; !fFinish; nPos++)
  161. {
  162. if (( pszString[nPos]<TEXT('0')) || (pszString[nPos]>TEXT('9')))
  163. {
  164. // not a number
  165. nField++;
  166. fFinish = (nField == 4);
  167. }
  168. else
  169. {
  170. dwValue[nField] *= 10;
  171. dwValue[nField] += (pszString[nPos]-TEXT('0'));
  172. }
  173. }
  174. }
  175. LRESULT FAR PASCAL IPAddressWndFnEx(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam, CLS_INFO* pClsInfo )
  176. {
  177. LRESULT lResult;
  178. CONTROL *pControl;
  179. UINT i;
  180. lResult = TRUE;
  181. switch( wMsg )
  182. {
  183. // use empty string (not NULL) to set to blank
  184. case WM_SETTEXT:
  185. {
  186. /*
  187. static TCHAR szBuf[CHARS_PER_FIELD+1];
  188. DWORD dwValue[4];
  189. LPTSTR pszString = (LPTSTR)lParam;
  190. FormatIPAddress(pszString, &dwValue[0]);
  191. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  192. pControl->bCancelParentNotify = TRUE;
  193. for (i = 0; i < pClsInfo->nNumFields; ++i)
  194. {
  195. if (pszString[0] == 0)
  196. {
  197. szBuf[0] = 0;
  198. }
  199. else
  200. {
  201. wsprintf(szBuf, TEXT("%d"), dwValue[i]);
  202. }
  203. SendMessage(pControl->ChildrenArr[i].hWnd, WM_SETTEXT,
  204. 0, (LPARAM) (LPSTR) szBuf);
  205. }
  206. pControl->bCancelParentNotify = FALSE;
  207. SendMessage(pControl->hwndParent, WM_COMMAND,
  208. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  209. */
  210. }
  211. break;
  212. case WM_GETTEXTLENGTH:
  213. case WM_GETTEXT:
  214. {
  215. /*
  216. int iFieldValue;
  217. int srcPos, desPos;
  218. DWORD dwValue[4];
  219. TCHAR pszResult[30];
  220. TCHAR *pszDest = (TCHAR *)lParam;
  221. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  222. lResult = 0;
  223. dwValue[0] = 0;
  224. dwValue[1] = 0;
  225. dwValue[2] = 0;
  226. dwValue[3] = 0;
  227. for (i = 0; i < pClsInfo->nNumFields; ++i)
  228. {
  229. iFieldValue = GetFieldValue(&(pControl->ChildrenArr[i]));
  230. if (iFieldValue == -1)
  231. iFieldValue = 0;
  232. else
  233. ++lResult;
  234. dwValue[i] = iFieldValue;
  235. }
  236. wsprintf( pszResult, TEXT("%d.%d.%d.%d"), dwValue[0], dwValue[1], dwValue[2], dwValue[3] );
  237. if ( wMsg == WM_GETTEXTLENGTH )
  238. {
  239. lResult = lstrlen( pszResult );
  240. }
  241. else
  242. {
  243. for ( srcPos=0, desPos=0; (srcPos+1<(INT)wParam) && (pszResult[srcPos]!=TEXT('\0')); )
  244. {
  245. pszDest[desPos++] = pszResult[srcPos++];
  246. }
  247. pszDest[desPos]=TEXT('\0');
  248. lResult = desPos;
  249. }
  250. */
  251. }
  252. break;
  253. case WM_GETDLGCODE :
  254. lResult = DLGC_WANTCHARS;
  255. break;
  256. case WM_NCCREATE:
  257. SetWindowLong(hWnd, GWL_EXSTYLE, (GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_CLIENTEDGE));
  258. lResult = TRUE;
  259. break;
  260. case WM_CREATE : /* create pallette window */
  261. {
  262. HDC hdc;
  263. HMENU id;
  264. UINT uiFieldStart;
  265. FARPROC lpfnFieldProc;
  266. pControl = (CONTROL*)GlobalAlloc(GMEM_FIXED, sizeof(CONTROL));
  267. if (pControl)
  268. {
  269. HFONT OldFont;
  270. RECT rect;
  271. LPCREATESTRUCT lpCreateStruct;
  272. lpCreateStruct = ((CREATESTRUCT *)lParam);
  273. pControl->fEnabled = TRUE;
  274. pControl->fPainted = FALSE;
  275. pControl->fInMessageBox = FALSE;
  276. pControl->hwndParent = lpCreateStruct->hwndParent;
  277. pControl->bControlInFocus = FALSE;
  278. pControl->bCancelParentNotify = FALSE;
  279. pControl->pClsInfo = pClsInfo;
  280. pControl->ChildrenArr = (FIELD*)GlobalAlloc(GMEM_FIXED, sizeof(FIELD)*(pClsInfo->nNumFields));
  281. pControl->lpfnAlert = NULL;
  282. if (!pControl->ChildrenArr)
  283. {
  284. GlobalFree(pControl);
  285. pControl = 0;
  286. DestroyWindow(hWnd);
  287. return 0;
  288. }
  289. for (i = 0; i < pClsInfo->nNumFields; ++i)
  290. {
  291. (*(pClsInfo->lpfnInit))(i,&(pControl->ChildrenArr[i]));
  292. }
  293. hdc = GetDC(hWnd);
  294. if (hdc != NULL)
  295. {
  296. GetClientRect(hWnd, &rect);
  297. OldFont = SelectObject(hdc, CreateFontIndirect(&logfont));
  298. pControl->uiMaxCharWidth = (*(pClsInfo->lpfnMaxCharWidth))(hdc);
  299. GetCharWidth(hdc, pClsInfo->chFiller, pClsInfo->chFiller,
  300. (int *)(&pControl->uiFillerWidth));
  301. DeleteObject(SelectObject(hdc, OldFont ));
  302. ReleaseDC(hWnd, hdc);
  303. uiFieldStart = LEAD_ROOM;
  304. lpfnFieldProc = MakeProcInstance((FARPROC)IPAddressFieldProc,
  305. LPCS->hInstance);
  306. id = (HMENU)GetWindowLongPtr(hWnd, GWLP_ID);
  307. for (i = 0; i < pClsInfo->nNumFields; ++i)
  308. {
  309. pControl->ChildrenArr[i].uiWidth =
  310. (pControl->ChildrenArr[i].nChars) * (pControl->uiMaxCharWidth+2);
  311. pControl->ChildrenArr[i].hWnd = CreateWindowEx(0,
  312. TEXT("Edit"),
  313. NULL,
  314. WS_CHILD | WS_VISIBLE,
  315. uiFieldStart,
  316. HEAD_ROOM,
  317. pControl->ChildrenArr[i].uiWidth,
  318. (rect.bottom-rect.top),
  319. hWnd,
  320. id,
  321. lpCreateStruct->hInstance,
  322. (LPVOID)NULL);
  323. SAVE_CONTROL_HANDLE(pControl->ChildrenArr[i].hWnd, i);
  324. SendMessage(pControl->ChildrenArr[i].hWnd, EM_LIMITTEXT,
  325. pControl->ChildrenArr[i].nChars, 0L);
  326. SendMessage(pControl->ChildrenArr[i].hWnd, WM_SETFONT,
  327. (WPARAM)CreateFontIndirect(&logfont), TRUE);
  328. // Disable IME support for the ip editor
  329. ImmAssociateContext(pControl->ChildrenArr[i].hWnd, NULL);
  330. pControl->ChildrenArr[i].lpfnWndProc =
  331. (FARPROC) GetWindowLongPtr(pControl->ChildrenArr[i].hWnd,
  332. GWLP_WNDPROC);
  333. SetWindowLongPtr(pControl->ChildrenArr[i].hWnd,
  334. GWLP_WNDPROC, (LONG_PTR)lpfnFieldProc);
  335. uiFieldStart += pControl->ChildrenArr[i].uiWidth
  336. + pControl->uiFillerWidth;
  337. } // for
  338. SAVE_CONTROL_HANDLE(hWnd, pControl);
  339. //
  340. // need to make control wider
  341. //
  342. uiFieldStart -= pControl->uiFillerWidth;
  343. {
  344. RECT r;
  345. POINT p1;
  346. POINT p2;
  347. GetWindowRect(hWnd, &r); // screen coords
  348. p1.x = r.left;
  349. p1.y = r.top;
  350. p2.x = r.right;
  351. p2.y = r.bottom;
  352. ScreenToClient(lpCreateStruct->hwndParent, &p1);
  353. ScreenToClient(lpCreateStruct->hwndParent, &p2);
  354. p2.x = p1.x + uiFieldStart + 2;
  355. MoveWindow(hWnd, p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, FALSE);
  356. }
  357. }
  358. } // if
  359. else
  360. {
  361. DestroyWindow(hWnd);
  362. }
  363. }
  364. lResult = 0;
  365. break;
  366. case WM_PAINT: /* paint control window */
  367. {
  368. PAINTSTRUCT Ps;
  369. RECT rect;
  370. RECT headRect; /* area before the first edit box */
  371. COLORREF TextColor;
  372. COLORREF cRef;
  373. HFONT OldFont;
  374. HBRUSH hbr;
  375. BOOL fPaintAsEnabled;
  376. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  377. fPaintAsEnabled = pControl->fEnabled;
  378. if (fPaintAsEnabled)
  379. {
  380. /* onlys some of the edit controls might be enabled */
  381. for (i = 0; i < pClsInfo->nNumFields; ++i)
  382. {
  383. if (!IsWindowEnabled(pControl->ChildrenArr[i].hWnd))
  384. {
  385. fPaintAsEnabled = FALSE; /* need disabled background */
  386. break;
  387. } // if
  388. } // for
  389. } // if
  390. BeginPaint(hWnd, (LPPAINTSTRUCT)&Ps);
  391. OldFont = SelectObject( Ps.hdc, CreateFontIndirect(&logfont));
  392. GetClientRect(hWnd, &rect);
  393. if (fPaintAsEnabled)
  394. {
  395. TextColor = GetSysColor(COLOR_WINDOWTEXT);
  396. cRef = GetSysColor(COLOR_WINDOW);
  397. }
  398. else
  399. {
  400. TextColor = GetSysColor(COLOR_GRAYTEXT);
  401. cRef = GetSysColor(COLOR_3DFACE);
  402. }
  403. SetBkColor(Ps.hdc, cRef);
  404. SetTextColor(Ps.hdc, TextColor);
  405. hbr = CreateSolidBrush(cRef);
  406. if (hbr != NULL)
  407. {
  408. FillRect(Ps.hdc, &rect, hbr);
  409. DeleteObject(hbr);
  410. SetRect(&headRect, 0, HEAD_ROOM, LEAD_ROOM, (rect.bottom-rect.top));
  411. CopyRect(&rect, &headRect);
  412. for (i = 0; i < pClsInfo->nNumFields-1; ++i)
  413. {
  414. rect.left += pControl->ChildrenArr[i].uiWidth;
  415. rect.right = rect.left + pControl->uiFillerWidth;
  416. if (IsWindowEnabled(pControl->ChildrenArr[i].hWnd))
  417. {
  418. TextColor = GetSysColor(COLOR_WINDOWTEXT);
  419. cRef = GetSysColor(COLOR_WINDOW);
  420. }
  421. else
  422. {
  423. TextColor = GetSysColor(COLOR_GRAYTEXT);
  424. cRef = GetSysColor(COLOR_3DFACE);
  425. }
  426. SetBkColor(Ps.hdc, cRef);
  427. SetTextColor(Ps.hdc, TextColor);
  428. hbr = CreateSolidBrush(cRef);
  429. if (hbr != NULL)
  430. {
  431. if (i == 0)
  432. FillRect(Ps.hdc, &headRect, hbr);
  433. FillRect(Ps.hdc, &rect, hbr);
  434. DeleteObject(hbr);
  435. }
  436. ExtTextOut(Ps.hdc, rect.left, HEAD_ROOM, ETO_OPAQUE, &rect, pClsInfo->lpszFiller, 1, NULL);
  437. rect.left = rect.right;
  438. }
  439. }
  440. pControl->fPainted = TRUE;
  441. DeleteObject(SelectObject(Ps.hdc, OldFont));
  442. EndPaint(hWnd, &Ps);
  443. }
  444. break;
  445. case WM_SETFOCUS : /* get focus - display caret */
  446. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  447. /* set the focus on the first enabled field */
  448. for (i = 0; i < pClsInfo->nNumFields; ++i)
  449. {
  450. if (IsWindowEnabled(pControl->ChildrenArr[i].hWnd))
  451. {
  452. EnterField(&(pControl->ChildrenArr[i]), 0, pControl->ChildrenArr[i].nChars);
  453. break;
  454. }
  455. }
  456. break;
  457. case WM_LBUTTONDOWN : /* left button depressed - fall through */
  458. SetFocus(hWnd);
  459. break;
  460. case WM_ENABLE:
  461. {
  462. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  463. pControl->fEnabled = (BOOL)wParam;
  464. for (i = 0; i < pClsInfo->nNumFields; ++i)
  465. {
  466. EnableWindow(pControl->ChildrenArr[i].hWnd, (BOOL)wParam);
  467. }
  468. if (pControl->fPainted)
  469. InvalidateRect(hWnd, NULL, FALSE);
  470. }
  471. break;
  472. case WM_DESTROY :
  473. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  474. if (pControl == NULL)
  475. break; // memory already freed (MFC DestroyWindow() call)
  476. // Restore all the child window procedures before we delete our memory block.
  477. for (i = 0; i < pClsInfo->nNumFields; ++i)
  478. {
  479. SendMessage(pControl->ChildrenArr[i].hWnd, WM_DESTROY, 0, 0);
  480. SetWindowLongPtr(pControl->ChildrenArr[i].hWnd, GWLP_WNDPROC,
  481. (LONG_PTR)pControl->ChildrenArr[i].lpfnWndProc);
  482. }
  483. // free memory and reset window long
  484. GlobalFree(pControl->ChildrenArr);
  485. GlobalFree(pControl);
  486. SAVE_CONTROL_HANDLE(hWnd, NULL);
  487. break;
  488. case WM_COMMAND:
  489. switch (HIWORD(wParam))
  490. {
  491. // One of the fields lost the focus, see if it lost the focus to another field
  492. // of if we've lost the focus altogether. If its lost altogether, we must send
  493. // an EN_KILLFOCUS notification on up the ladder.
  494. case EN_KILLFOCUS:
  495. {
  496. HWND hFocus;
  497. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  498. if (!pControl->fInMessageBox)
  499. {
  500. hFocus = GetFocus();
  501. for (i = 0; i < pClsInfo->nNumFields; ++i)
  502. if (pControl->ChildrenArr[i].hWnd == hFocus)
  503. break;
  504. if (i >= pClsInfo->nNumFields)
  505. {
  506. SendMessage(pControl->hwndParent, WM_COMMAND,
  507. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID),
  508. EN_KILLFOCUS), (LPARAM)hWnd);
  509. pControl->bControlInFocus = FALSE;
  510. }
  511. }
  512. }
  513. break;
  514. case EN_SETFOCUS:
  515. {
  516. HWND hFocus;
  517. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  518. if (!pControl->fInMessageBox)
  519. {
  520. hFocus = (HWND)lParam;
  521. for (i = 0; i < pClsInfo->nNumFields; ++i)
  522. if (pControl->ChildrenArr[i].hWnd == hFocus)
  523. break;
  524. // send a focus message when the
  525. if (i < pClsInfo->nNumFields && pControl->bControlInFocus == FALSE)
  526. {
  527. SendMessage(pControl->hwndParent, WM_COMMAND,
  528. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID),
  529. EN_SETFOCUS), (LPARAM)hWnd);
  530. pControl->bControlInFocus = TRUE; // only set the focus once
  531. }
  532. }
  533. }
  534. break;
  535. case EN_CHANGE:
  536. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  537. if (pControl->bCancelParentNotify == FALSE)
  538. {
  539. SendMessage(pControl->hwndParent, WM_COMMAND,
  540. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  541. }
  542. break;
  543. }
  544. break;
  545. // Get the value of the control fields.
  546. case DNS_MASK_CTRL_GET:
  547. {
  548. DWORD* dwArr;
  549. UINT nArrSize;
  550. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  551. dwArr = (DWORD*)wParam;
  552. nArrSize = (UINT)lParam;
  553. lResult = 0;
  554. for (i = 0; (i < pClsInfo->nNumFields) && ( i < nArrSize); ++i)
  555. {
  556. dwArr[i] = GetFieldValue(&(pControl->ChildrenArr[i]), pClsInfo);
  557. if (dwArr[i] != FIELD_EMPTY)
  558. ++lResult;
  559. }
  560. }
  561. break;
  562. // Clear all fields to blanks.
  563. case DNS_MASK_CTRL_CLEAR:
  564. {
  565. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  566. pControl->bCancelParentNotify = TRUE;
  567. if (wParam == -1)
  568. {
  569. for (i = 0; i < pClsInfo->nNumFields; ++i)
  570. {
  571. SendMessage(pControl->ChildrenArr[i].hWnd, WM_SETTEXT,
  572. 0, (LPARAM) (LPSTR) TEXT(""));
  573. }
  574. }
  575. else
  576. {
  577. SendMessage(pControl->ChildrenArr[wParam].hWnd, WM_SETTEXT,
  578. 0, (LPARAM)(LPSTR) TEXT(""));
  579. }
  580. pControl->bCancelParentNotify = FALSE;
  581. SendMessage(pControl->hwndParent, WM_COMMAND,
  582. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  583. }
  584. break;
  585. // Set the value of the IP Address. The address is in the lParam with the
  586. // first address byte being the high byte, the second being the second byte,
  587. // and so on. A lParam value of -1 removes the address.
  588. case DNS_MASK_CTRL_SET:
  589. {
  590. DWORD* dwArr;
  591. UINT nArrSize;
  592. static TCHAR szBuf[BUFFER_LEN+1];
  593. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  594. pControl->bCancelParentNotify = TRUE;
  595. dwArr = (DWORD*)wParam;
  596. nArrSize = (UINT)lParam;
  597. for (i = 0; i < (pClsInfo->nNumFields) && ( i < nArrSize); ++i)
  598. {
  599. (*(pControl->pClsInfo->lpfnNumberToString))(szBuf,dwArr[i]);
  600. SendMessage(pControl->ChildrenArr[i].hWnd, WM_SETTEXT,
  601. 0, (LPARAM) (LPSTR) szBuf);
  602. }
  603. pControl->bCancelParentNotify = FALSE;
  604. SendMessage(pControl->hwndParent, WM_COMMAND,
  605. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  606. }
  607. break;
  608. case DNS_MASK_CTRL_SET_LOW_RANGE:
  609. case DNS_MASK_CTRL_SET_HI_RANGE:
  610. if (wParam < pClsInfo->nNumFields)
  611. {
  612. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  613. if (wMsg == DNS_MASK_CTRL_SET_LOW_RANGE)
  614. pControl->ChildrenArr[wParam].dwLow = (DWORD)lParam;
  615. else
  616. pControl->ChildrenArr[wParam].dwHigh = (DWORD)lParam;
  617. }
  618. break;
  619. // Set the focus to this control.
  620. // wParam = the field number to set focus to, or -1 to set the focus to the
  621. // first non-blank field.
  622. case DNS_MASK_CTRL_SETFOCUS:
  623. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  624. if (wParam >= pClsInfo->nNumFields)
  625. {
  626. for (wParam = 0; wParam < pClsInfo->nNumFields; ++wParam)
  627. if (GetFieldValue(&(pControl->ChildrenArr[wParam]), pControl->pClsInfo) == FIELD_EMPTY) break;
  628. if (wParam >= pClsInfo->nNumFields) wParam = 0;
  629. }
  630. EnterField(&(pControl->ChildrenArr[wParam]), 0, pControl->ChildrenArr[wParam].nChars);
  631. break;
  632. // Determine whether all four subfields are blank
  633. case DNS_MASK_CTRL_ISBLANK:
  634. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  635. lResult = TRUE;
  636. for (i = 0; i < pClsInfo->nNumFields; ++i)
  637. {
  638. if (GetFieldValue(&(pControl->ChildrenArr[i]), pControl->pClsInfo) != FIELD_EMPTY)
  639. {
  640. lResult = FALSE;
  641. break;
  642. }
  643. }
  644. break;
  645. case DNS_MASK_CTRL_SET_ALERT:
  646. {
  647. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  648. pControl->lpfnAlert = (int (*)(HWND, DWORD, DWORD, DWORD))(wParam);
  649. lResult = TRUE;
  650. }
  651. break;
  652. case DNS_MASK_CTRL_ENABLE_FIELD:
  653. {
  654. pControl = (CONTROL *)GET_CONTROL_HANDLE(hWnd);
  655. //int nField = (int)wParam;
  656. if ( ((int)wParam >= 0) && ((UINT)wParam < pClsInfo->nNumFields) )
  657. {
  658. EnableWindow(pControl->ChildrenArr[(int)wParam].hWnd, (BOOL)lParam);
  659. }
  660. if (pControl->fPainted)
  661. InvalidateRect(hWnd, NULL, FALSE);
  662. }
  663. break;
  664. default:
  665. lResult = DefWindowProc( hWnd, wMsg, wParam, lParam );
  666. break;
  667. }
  668. return( lResult );
  669. }
  670. /*
  671. IPAddressFieldProc() - Edit field window procedure
  672. This function sub-classes each edit field.
  673. */
  674. LRESULT FAR PASCAL IPAddressFieldProc(HWND hWnd,
  675. UINT wMsg,
  676. WPARAM wParam,
  677. LPARAM lParam)
  678. {
  679. CONTROL *pControl;
  680. FIELD *pField;
  681. HWND hControlWindow;
  682. LONG_PTR nChildID;
  683. LRESULT lresult;
  684. hControlWindow = GetParent(hWnd);
  685. if (!hControlWindow)
  686. return 0;
  687. pControl = (CONTROL *)GET_CONTROL_HANDLE(hControlWindow);
  688. nChildID = (LONG_PTR)GET_CONTROL_HANDLE(hWnd);
  689. pField = &(pControl->ChildrenArr[nChildID]);
  690. if (pField->hWnd != hWnd)
  691. return 0;
  692. switch (wMsg)
  693. {
  694. case WM_DESTROY:
  695. DeleteObject((HGDIOBJ)SendMessage(hWnd, WM_GETFONT, 0, 0));
  696. return 0;
  697. case WM_CHAR:
  698. // Typing in the last digit in a field, skips to the next field.
  699. //if (wParam >= TEXT('0') && wParam <= TEXT('9'))
  700. if ( (*(pControl->pClsInfo->lpfnValChar))((TCHAR)wParam))
  701. {
  702. DWORD dwResult;
  703. dwResult = (DWORD)CallWindowProc((WNDPROC)pControl->ChildrenArr[nChildID].lpfnWndProc,
  704. hWnd, wMsg, wParam, lParam);
  705. dwResult = (DWORD)SendMessage(hWnd, EM_GETSEL, 0, 0L);
  706. if (dwResult == (DWORD)MAKELPARAM((WORD)(pField->nChars), (WORD)(pField->nChars))
  707. && ExitField(pControl, (UINT)nChildID)
  708. && nChildID < (int)pControl->pClsInfo->nNumFields-1)
  709. {
  710. EnterField(&(pControl->ChildrenArr[nChildID+1]),
  711. 0, pField->nChars);
  712. }
  713. return dwResult;
  714. }
  715. // spaces and periods fills out the current field and then if possible,
  716. // goes to the next field.
  717. else if ((TCHAR)wParam == pControl->pClsInfo->chFiller || wParam == SPACE )
  718. {
  719. DWORD dwResult;
  720. dwResult = (DWORD)SendMessage(hWnd, EM_GETSEL, 0, 0L);
  721. if (dwResult != 0L && HIWORD(dwResult) == LOWORD(dwResult)
  722. && ExitField(pControl, nChildID))
  723. {
  724. if (nChildID >= (int)pControl->pClsInfo->nNumFields-1)
  725. MessageBeep((UINT)-1);
  726. else
  727. {
  728. EnterField(&(pControl->ChildrenArr[nChildID+1]),
  729. 0, pControl->ChildrenArr[nChildID+1].nChars);
  730. }
  731. }
  732. return 0;
  733. }
  734. // Backspaces go to the previous field if at the beginning of the current field.
  735. // Also, if the focus shifts to the previous field, the backspace must be
  736. // processed by that field.
  737. else if (wParam == BACK_SPACE)
  738. {
  739. if (nChildID > 0 && SendMessage(hWnd, EM_GETSEL, 0, 0L) == 0L)
  740. {
  741. if (SwitchFields(pControl,
  742. nChildID,
  743. nChildID-1,
  744. pControl->ChildrenArr[nChildID-1].nChars,
  745. pControl->ChildrenArr[nChildID-1].nChars)
  746. && SendMessage(pControl->ChildrenArr[nChildID-1].hWnd,
  747. EM_LINELENGTH,
  748. (WPARAM)0,
  749. (LPARAM)0L) != 0L
  750. && IsWindowEnabled(pControl->ChildrenArr[nChildID-1].hWnd))
  751. {
  752. SendMessage(pControl->ChildrenArr[nChildID-1].hWnd,
  753. wMsg, wParam, lParam);
  754. }
  755. return 0;
  756. }
  757. }
  758. // Any other printable characters are not allowed.
  759. else if (wParam > SPACE)
  760. {
  761. MessageBeep((UINT)-1);
  762. return 0;
  763. }
  764. break;
  765. case WM_KEYDOWN:
  766. switch (wParam)
  767. {
  768. // Arrow keys move between fields when the end of a field is reached.
  769. case VK_LEFT:
  770. case VK_RIGHT:
  771. case VK_UP:
  772. case VK_DOWN:
  773. if (GetKeyState(VK_CONTROL) < 0)
  774. {
  775. if ((wParam == VK_LEFT || wParam == VK_UP) && nChildID > 0)
  776. {
  777. SwitchFields(pControl, nChildID, nChildID-1, 0, pField->nChars);
  778. return 0;
  779. }
  780. else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
  781. && nChildID < (int)pControl->pClsInfo->nNumFields-1)
  782. {
  783. SwitchFields(pControl, nChildID, nChildID+1, 0, pField->nChars);
  784. return 0;
  785. }
  786. }
  787. else
  788. {
  789. DWORD dwResult;
  790. WORD wStart, wEnd;
  791. dwResult = (DWORD)SendMessage(hWnd, EM_GETSEL, 0, 0L);
  792. wStart = LOWORD(dwResult);
  793. wEnd = HIWORD(dwResult);
  794. if (wStart == wEnd)
  795. {
  796. if ((wParam == VK_LEFT || wParam == VK_UP)
  797. && wStart == 0
  798. && nChildID > 0)
  799. {
  800. SwitchFields(pControl, nChildID, nChildID-1, pField->nChars, pField->nChars);
  801. return 0;
  802. }
  803. else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
  804. && nChildID < (int)pControl->pClsInfo->nNumFields-1)
  805. {
  806. dwResult = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0L);
  807. if (wStart >= dwResult)
  808. {
  809. SwitchFields(pControl, nChildID, nChildID+1, 0, 0);
  810. return 0;
  811. }
  812. }
  813. }
  814. }
  815. break;
  816. // Home jumps back to the beginning of the first field.
  817. case VK_HOME:
  818. if (nChildID > 0)
  819. {
  820. SwitchFields(pControl, nChildID, 0, 0, 0);
  821. return 0;
  822. }
  823. break;
  824. // End scoots to the end of the last field.
  825. case VK_END:
  826. if (nChildID < (int)pControl->pClsInfo->nNumFields-1)
  827. {
  828. SwitchFields(pControl, nChildID, (pControl->pClsInfo->nNumFields)-1, pField->nChars, pField->nChars);
  829. return 0;
  830. }
  831. break;
  832. } // switch (wParam)
  833. break;
  834. case WM_KILLFOCUS:
  835. if ( !ExitField( pControl, nChildID ))
  836. {
  837. return 0;
  838. }
  839. } // switch (wMsg)
  840. lresult = CallWindowProc( (WNDPROC)pControl->ChildrenArr[nChildID].lpfnWndProc,
  841. hWnd, wMsg, wParam, lParam);
  842. return lresult;
  843. }
  844. /*
  845. Switch the focus from one field to another.
  846. call
  847. pControl = Pointer to the CONTROL structure.
  848. iOld = Field we're leaving.
  849. iNew = Field we're entering.
  850. hNew = Window of field to goto
  851. wStart = First character selected
  852. wEnd = Last character selected + 1
  853. returns
  854. TRUE on success, FALSE on failure.
  855. Only switches fields if the current field can be validated.
  856. */
  857. BOOL SwitchFields(CONTROL *pControl, LONG_PTR nOld, LONG_PTR nNew, UINT nStart, UINT nEnd)
  858. {
  859. if (!ExitField(pControl, nOld)) return FALSE;
  860. EnterField(&(pControl->ChildrenArr[nNew]), nStart, nEnd);
  861. return TRUE;
  862. }
  863. /*
  864. Set the focus to a specific field's window.
  865. call
  866. pField = pointer to field structure for the field.
  867. wStart = First character selected
  868. wEnd = Last character selected + 1
  869. */
  870. void EnterField(FIELD *pField, UINT nStart, UINT nEnd)
  871. {
  872. SetFocus(pField->hWnd);
  873. SendMessage(pField->hWnd, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
  874. }
  875. /*
  876. Exit a field.
  877. call
  878. pControl = pointer to CONTROL structure.
  879. iField = field number being exited.
  880. returns
  881. TRUE if the user may exit the field.
  882. FALSE if he may not.
  883. */
  884. BOOL ExitField(CONTROL *pControl, LONG_PTR nField)
  885. {
  886. HWND hControlWnd;
  887. HWND hDialog;
  888. WORD wLength;
  889. FIELD *pField;
  890. static TCHAR szBuf[BUFFER_LEN+1];
  891. DWORD xVal;
  892. pField = &(pControl->ChildrenArr[nField]);
  893. *(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
  894. wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)(LPSTR)szBuf);
  895. if (wLength != 0)
  896. {
  897. szBuf[wLength] = TEXT('\0');
  898. xVal = (*(pControl->pClsInfo->lpfnStringToNumber))(szBuf,(int)wLength);
  899. if (xVal < pField->dwLow || xVal > pField->dwHigh)
  900. {
  901. if ( xVal < pField->dwLow )
  902. {
  903. /* too small */
  904. wsprintf(szBuf, TEXT("%d"), pField->dwLow );
  905. }
  906. else
  907. {
  908. /* must be bigger */
  909. wsprintf(szBuf, TEXT("%d"), pField->dwHigh );
  910. }
  911. SendMessage(pField->hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf);
  912. if ((hControlWnd = GetParent(pField->hWnd)) != NULL
  913. && (hDialog = GetParent(hControlWnd)) != NULL)
  914. {
  915. pControl->fInMessageBox = TRUE;
  916. if (pControl->lpfnAlert != NULL) // call user provided hook
  917. {
  918. (*(pControl->lpfnAlert))(hDialog, xVal, pField->dwLow, pField->dwHigh);
  919. }
  920. else
  921. {
  922. MessageBeep(MB_ICONEXCLAMATION);
  923. }
  924. pControl->fInMessageBox = FALSE;
  925. SendMessage(pField->hWnd, EM_SETSEL, 0, pField->nChars);
  926. return FALSE;
  927. }
  928. }
  929. }
  930. return TRUE;
  931. }
  932. /*
  933. Get the value stored in a field.
  934. call
  935. pField = pointer to the FIELD structure for the field.
  936. returns
  937. The value (0..255) or -1 if the field has not value.
  938. */
  939. DWORD GetFieldValue(FIELD *pField, CLS_INFO* pClsInfo)
  940. {
  941. WORD wLength;
  942. static TCHAR szBuf[BUFFER_LEN+1];
  943. *(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
  944. wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)(LPSTR)szBuf);
  945. if (wLength != 0)
  946. {
  947. return (*(pClsInfo->lpfnStringToNumber))(szBuf,wLength);
  948. }
  949. else
  950. return FIELD_EMPTY;
  951. }
  952. ////////////////////////////////////////////////////////////////////////////////////////////////
  953. DWORD DecimalStringToNumber(LPCTSTR lpszBuf, int nLen)
  954. {
  955. DWORD x;
  956. int j;
  957. for (x=0, j=0;j<nLen;j++)
  958. {
  959. x = x*10+lpszBuf[j]-TEXT('0'); // assume valid char
  960. }
  961. return x;
  962. }
  963. void NumberToDecimalString(LPTSTR lpszBuf, DWORD dwX)
  964. {
  965. if (dwX == FIELD_EMPTY)
  966. {
  967. lpszBuf[0] = 0x0; //NULL
  968. }
  969. else
  970. {
  971. wsprintf(lpszBuf, TEXT("%d"), (UINT)dwX);
  972. }
  973. }
  974. void NumberToHexString(LPTSTR lpszBuf, DWORD dwX)
  975. {
  976. wsprintf(lpszBuf, TEXT("%x"), (UINT)dwX);
  977. }
  978. DWORD HexStringToNumber(LPCTSTR lpszBuf, int nLen)
  979. {
  980. DWORD x;
  981. int j;
  982. for (x=0, j=0;j<nLen;j++)
  983. {
  984. DWORD digit = 0;
  985. if (lpszBuf[j] >= TEXT('0') && lpszBuf[j] <= TEXT('9'))
  986. digit = lpszBuf[j]-TEXT('0');
  987. else if (lpszBuf[j] >= TEXT('A') && lpszBuf[j] <= TEXT('F'))
  988. digit = lpszBuf[j]-TEXT('A') + 10;
  989. else// assume 'a' to 'f'
  990. digit = lpszBuf[j]-TEXT('a') + 10;
  991. x = x*16+digit;
  992. }
  993. return x;
  994. }
  995. BOOL ValidateDecimalChar(TCHAR ch)
  996. {
  997. // allow only digits
  998. WCHAR sz[2];
  999. BOOL b;
  1000. sz[0]=ch;
  1001. sz[1]=L'';
  1002. b = (ch >= TEXT('0') && ch <= TEXT('9'));
  1003. return b;
  1004. }
  1005. BOOL ValidateHexChar(TCHAR ch)
  1006. {
  1007. // allow only digits
  1008. return ( (ch >= TEXT('0') && ch <= TEXT('9')) ||
  1009. (ch >= TEXT('a') && ch <= TEXT('f')) ||
  1010. (ch >= TEXT('A') && ch <= TEXT('F')) );
  1011. }
  1012. void InitIPv4Field(int nIndex, FIELD* pField)
  1013. {
  1014. nIndex; // Must use formal parameters for /W4
  1015. pField->dwLow = 0;//MIN_FIELD_VALUE;
  1016. pField->dwHigh = 255; //MAX_FIELD_VALUE;
  1017. pField->nChars = 3; //CHARS_PER_FIELD;
  1018. }
  1019. void InitIPv6Field(int nIndex, FIELD* pField)
  1020. {
  1021. nIndex; // Must user formal parameters for /W4
  1022. pField->dwLow = 0; //MIN_FIELD_VALUE;
  1023. pField->dwHigh = 0xFFFF; //MAX_FIELD_VALUE;
  1024. pField->nChars = 4; //CHARS_PER_FIELD;
  1025. }
  1026. void InitTTLField(int nIndex, FIELD* pField)
  1027. {
  1028. pField->dwLow = 0;
  1029. switch (nIndex)
  1030. {
  1031. case 0: // days
  1032. pField->dwHigh = 49710;
  1033. pField->nChars = 5;
  1034. break;
  1035. case 1: // hours
  1036. pField->dwHigh = 23;
  1037. pField->nChars = 2;
  1038. break;
  1039. case 2: // minutes
  1040. pField->dwHigh = 59;
  1041. pField->nChars = 2;
  1042. break;
  1043. case 3: // seconds
  1044. pField->dwHigh = 59;
  1045. pField->nChars = 2;
  1046. break;
  1047. default:
  1048. ;
  1049. }
  1050. }
  1051. UINT _MaxCharWidthHelper(HDC hDC, UINT iFirstChar, UINT iLastChar)
  1052. {
  1053. FLOAT fFract[10] = {0};
  1054. INT nWidth[10] = {0};
  1055. int i;
  1056. FLOAT maxVal;
  1057. FLOAT curWidth;
  1058. UINT retVal;
  1059. retVal = 8; // good default if we fail
  1060. if (GetCharWidthFloat(hDC, iFirstChar, iLastChar,fFract) &&
  1061. GetCharWidth(hDC,iFirstChar, iLastChar, nWidth))
  1062. {
  1063. maxVal = 0.0;
  1064. for (i=0;i<10;i++)
  1065. {
  1066. curWidth = fFract[i] + (FLOAT)nWidth[i];
  1067. if (curWidth > maxVal)
  1068. maxVal = curWidth;
  1069. }
  1070. if (maxVal > ((FLOAT)((UINT)maxVal)))
  1071. retVal = (UINT) (maxVal+1);
  1072. else
  1073. retVal = (UINT)maxVal;
  1074. }
  1075. return retVal;
  1076. }
  1077. UINT MaxCharWidthDecimal(HDC hDC)
  1078. {
  1079. return _MaxCharWidthHelper(hDC,TEXT('0'), TEXT('9'));
  1080. }
  1081. UINT MaxCharWidthHex(HDC hDC)
  1082. {
  1083. UINT retVal;
  1084. UINT nMax1;
  1085. UINT nMax2;
  1086. UINT nMax3;
  1087. retVal = 0;
  1088. nMax1 = _MaxCharWidthHelper(hDC,TEXT('0'), TEXT('9'));
  1089. if (nMax1 > retVal)
  1090. retVal = nMax1;
  1091. nMax2 = _MaxCharWidthHelper(hDC,TEXT('a'), TEXT('f'));
  1092. if (nMax2 > retVal)
  1093. retVal = nMax2;
  1094. nMax3 = _MaxCharWidthHelper(hDC,TEXT('A'), TEXT('F'));
  1095. if (nMax3 > retVal)
  1096. retVal = nMax3;
  1097. return retVal;
  1098. }
  1099. /* class info structs for the various types */
  1100. CLS_INFO _IPv4ClsInfo = { TEXT('.'),
  1101. TEXT("."),
  1102. 4,
  1103. InitIPv4Field,
  1104. ValidateDecimalChar,
  1105. DecimalStringToNumber,
  1106. NumberToDecimalString,
  1107. MaxCharWidthDecimal
  1108. };
  1109. CLS_INFO _IPv6ClsInfo = { TEXT(':'),
  1110. TEXT(":"),
  1111. 8,
  1112. InitIPv6Field,
  1113. ValidateHexChar,
  1114. HexStringToNumber,
  1115. NumberToHexString,
  1116. MaxCharWidthHex
  1117. };
  1118. CLS_INFO _TTLClsInfo = { TEXT(':'),
  1119. TEXT(":"),
  1120. 4,
  1121. InitTTLField,
  1122. ValidateDecimalChar,
  1123. DecimalStringToNumber,
  1124. NumberToDecimalString,
  1125. MaxCharWidthDecimal
  1126. };
  1127. LRESULT FAR PASCAL IPv4WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
  1128. {
  1129. return IPAddressWndFnEx( hWnd, wMsg, wParam, lParam , &_IPv4ClsInfo);
  1130. }
  1131. LRESULT FAR PASCAL IPv6WndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
  1132. {
  1133. return IPAddressWndFnEx( hWnd, wMsg, wParam, lParam , &_IPv6ClsInfo);
  1134. }
  1135. LRESULT FAR PASCAL TTLWndFn(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
  1136. {
  1137. return IPAddressWndFnEx( hWnd, wMsg, wParam, lParam , &_TTLClsInfo);
  1138. }