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.

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