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

1257 lines
41 KiB

  1. /* Copyright (c) 1991, Microsoft Corporation, all rights reserved
  2. **
  3. ** ipaddr.c
  4. ** IP Address custom edit control
  5. **
  6. ** 11/09/92 Greg Strange
  7. ** Original code
  8. **
  9. ** 09/07/95 Steve Cobb
  10. ** Lifted TerryK/TRomano-updated version from NCPA, deleting IPDLL
  11. ** stuff, and making minor RAS-related customizations.
  12. */
  13. #include <windows.h> // Win32 core
  14. #include <uiutil.h> // Our public header
  15. #include <debug.h> // Trace and assert
  16. #define IPADDRESS_CLASS TEXT("RasIpAddress")
  17. // Extended style bit causes the ip address control to
  18. // correct the ip address so that it is contiguous (for submasks)
  19. #define IPADDR_EX_STYLE_CONTIGUOUS 0x1
  20. /* Module instance handle set when custom control is initialized.
  21. */
  22. static HANDLE g_hLibInstance = NULL;
  23. /* String ID of message displayed when user enters a field value that is out
  24. ** of range. Something like "You must choose a value from %1 to %2 for this
  25. ** field." Set when the custom control is initialized.
  26. */
  27. static DWORD g_dwBadIpAddrRange = 0;
  28. /* String ID of the popup title when the range error above is displayed. Set
  29. ** when the custom control is initialized.
  30. */
  31. static DWORD g_dwErrorTitle = 0;
  32. // The character that is displayed between address fields.
  33. #define FILLER TEXT('.')
  34. #define SZFILLER TEXT(".")
  35. #define SPACE TEXT(' ')
  36. #define BACK_SPACE 8
  37. /* Min, max values */
  38. #define NUM_FIELDS 4
  39. #define CHARS_PER_FIELD 3
  40. #define HEAD_ROOM 1 // space at top of control
  41. #define LEAD_ROOM 3 // space at front of control
  42. #define MIN_FIELD_VALUE 0 // default minimum allowable field value
  43. #define MAX_FIELD_VALUE 255 // default maximum allowable field value
  44. // All the information unique to one control is stuffed in one of these
  45. // structures in global memory and the handle to the memory is stored in the
  46. // Windows extra space.
  47. typedef struct tagFIELD {
  48. HANDLE hWnd;
  49. WNDPROC lpfnWndProc;
  50. BYTE byLow; // lowest allowed value for this field.
  51. BYTE byHigh; // Highest allowed value for this field.
  52. } FIELD;
  53. typedef struct tagCONTROL {
  54. HWND hwndParent;
  55. UINT uiFieldWidth;
  56. UINT uiFillerWidth;
  57. BOOL fEnabled;
  58. BOOL fPainted;
  59. BOOL bControlInFocus; // TRUE if the control is already in focus, dont't send another focus command
  60. BOOL bCancelParentNotify; // Don't allow the edit controls to notify parent if TRUE
  61. BOOL fInMessageBox; // Set when a message box is displayed so that
  62. // we don't send a EN_KILLFOCUS message when
  63. // we receive the EN_KILLFOCUS message for the
  64. // current field.
  65. FIELD Children[NUM_FIELDS];
  66. } CONTROL;
  67. // The following macros extract and store the CONTROL structure for a control.
  68. #define IPADDRESS_EXTRA (sizeof(DWORD) + sizeof(DWORD))
  69. #define GET_CONTROL_HANDLE(hWnd) ((HGLOBAL)(GetWindowLongPtr((hWnd), GWLP_USERDATA)))
  70. #define SAVE_CONTROL_HANDLE(hWnd,x) (SetWindowLongPtr((hWnd), GWLP_USERDATA, (ULONG_PTR)x))
  71. #define IPADDR_GET_SUBSTYLE(hwnd) (GetWindowLong((hwnd), 4))
  72. #define IPADDR_SET_SUBSTYLE(hwnd, style) (SetWindowLong((hwnd), 4, (style)))
  73. /* internal IPAddress function prototypes */
  74. LRESULT FAR PASCAL IPAddressWndFn( HWND, UINT, WPARAM, LPARAM );
  75. LRESULT FAR PASCAL IPAddressFieldProc(HWND, UINT, WPARAM, LPARAM);
  76. BOOL SwitchFields(CONTROL FAR *, int, int, WORD, WORD);
  77. void EnterField(FIELD FAR *, WORD, WORD);
  78. BOOL ExitField(CONTROL FAR *, int iField);
  79. int GetFieldValue(FIELD FAR *);
  80. LOGFONT logfont;
  81. void SetDefaultFont( )
  82. {
  83. LANGID langid = PRIMARYLANGID(GetThreadLocale());
  84. BOOL fIsDbcs = (langid == LANG_CHINESE ||
  85. langid == LANG_JAPANESE ||
  86. langid == LANG_KOREAN);
  87. HDC hdc = GetDC(NULL);
  88. if(NULL == hdc)
  89. {
  90. return;
  91. }
  92. logfont.lfWidth = 0;
  93. logfont.lfEscapement = 0;
  94. logfont.lfOrientation = 0;
  95. logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  96. logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  97. logfont.lfQuality = DEFAULT_QUALITY;
  98. logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  99. logfont.lfUnderline = 0;
  100. logfont.lfStrikeOut = 0;
  101. logfont.lfItalic = 0;
  102. logfont.lfWeight = FW_NORMAL;
  103. if (fIsDbcs)
  104. {
  105. logfont.lfHeight = -(9*GetDeviceCaps(hdc,LOGPIXELSY)/72);
  106. logfont.lfCharSet = DEFAULT_CHARSET;
  107. }
  108. else
  109. {
  110. logfont.lfHeight = -(8*GetDeviceCaps(hdc,LOGPIXELSY)/72);
  111. logfont.lfCharSet = ANSI_CHARSET;
  112. }
  113. lstrcpy( logfont.lfFaceName,TEXT("MS Shell Dlg"));
  114. ReleaseDC(NULL, hdc);
  115. }
  116. /*
  117. IpAddrInit() - IPAddress custom control initialization
  118. call
  119. hInstance = library or application instance
  120. dwErrorTitle = String ID of error popup title
  121. dwBadIpAddrRange = String ID of bad range popup text, e.g.
  122. "You must choose a value between %1 and %2 for this field."
  123. return
  124. TRUE on success, FALSE on failure.
  125. This function does all the one time initialization of IPAddress custom
  126. controls. Specifically it creates the IPAddress window class.
  127. */
  128. int FAR PASCAL
  129. IpAddrInit(
  130. IN HANDLE hInstance,
  131. IN DWORD dwErrorTitle,
  132. IN DWORD dwBadIpAddrRange )
  133. {
  134. HGLOBAL hClassStruct;
  135. LPWNDCLASS lpClassStruct;
  136. /* register IPAddress window if necessary */
  137. if ( g_hLibInstance == NULL ) {
  138. /* allocate memory for class structure */
  139. hClassStruct = GlobalAlloc( GHND, (DWORD)sizeof(WNDCLASS) );
  140. if ( hClassStruct ) {
  141. /* lock it down */
  142. lpClassStruct = (LPWNDCLASS)GlobalLock( hClassStruct );
  143. if ( lpClassStruct ) {
  144. /* define class attributes */
  145. lpClassStruct->lpszClassName = IPADDRESS_CLASS;
  146. lpClassStruct->hCursor = LoadCursor(NULL,IDC_IBEAM);
  147. lpClassStruct->lpszMenuName = (LPCTSTR)NULL;
  148. lpClassStruct->style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS|CS_GLOBALCLASS;
  149. lpClassStruct->lpfnWndProc = IPAddressWndFn;
  150. lpClassStruct->hInstance = hInstance;
  151. lpClassStruct->hIcon = NULL;
  152. lpClassStruct->cbWndExtra = IPADDRESS_EXTRA;
  153. lpClassStruct->hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
  154. /* register IPAddress window class */
  155. g_hLibInstance = ( RegisterClass(lpClassStruct) ) ? hInstance : NULL;
  156. GlobalUnlock( hClassStruct );
  157. }
  158. GlobalFree( hClassStruct );
  159. }
  160. }
  161. SetDefaultFont();
  162. g_dwErrorTitle = dwErrorTitle;
  163. g_dwBadIpAddrRange = dwBadIpAddrRange;
  164. return( g_hLibInstance ? 1:0 );
  165. }
  166. // Use this function to force the ip address entered to
  167. // be contiguous (series of 1's followed by a series of 0's).
  168. // This is useful for entering valid submasks
  169. //
  170. // Returns NO_ERROR if successful, error code otherwise
  171. //
  172. DWORD APIENTRY IpAddr_ForceContiguous(HWND hwndIpAddr) {
  173. DWORD dwOldStyle;
  174. // Set the last error information so that we can
  175. // return an error correctly
  176. SetLastError(NO_ERROR);
  177. // Set the extended style of the given window so
  178. // that it descriminates the address entered.
  179. dwOldStyle = IPADDR_GET_SUBSTYLE(hwndIpAddr);
  180. IPADDR_SET_SUBSTYLE(hwndIpAddr, dwOldStyle | IPADDR_EX_STYLE_CONTIGUOUS);
  181. return GetLastError();
  182. }
  183. void FormatIPAddress(LPTSTR pszString, DWORD* dwValue)
  184. {
  185. static TCHAR szBuf[CHARS_PER_FIELD+1];
  186. int nField, nPos;
  187. BOOL fFinish = FALSE;
  188. dwValue[0] = 0; dwValue[1] = 0; dwValue[2] = 0; dwValue[3] = 0;
  189. if (pszString[0] == 0)
  190. return;
  191. for( nField = 0, nPos = 0; !fFinish; nPos++)
  192. {
  193. if (( pszString[nPos]<TEXT('0')) || (pszString[nPos]>TEXT('9')))
  194. {
  195. // not a number
  196. nField++;
  197. fFinish = (nField == 4);
  198. }
  199. else
  200. {
  201. dwValue[nField] *= 10;
  202. dwValue[nField] += (pszString[nPos]-TEXT('0'));
  203. }
  204. }
  205. }
  206. // This function causes the ip address entered into hwndIpAddr to be
  207. // corrected so that it is contiguous.
  208. DWORD IpAddrMakeContiguous(HWND hwndIpAddr) {
  209. DWORD i, dwNewMask, dwMask;
  210. // Read in the current address
  211. SendMessage(hwndIpAddr, IP_GETADDRESS, 0, (LPARAM)&dwMask);
  212. // Find out where the first '1' is in binary going right to left
  213. dwNewMask = 0;
  214. for (i = 0; i < sizeof(dwMask)*8; i++) {
  215. dwNewMask |= 1 << i;
  216. if (dwNewMask & dwMask) {
  217. break;
  218. }
  219. }
  220. // At this point, dwNewMask is 000...0111... If we inverse it,
  221. // we get a mask that can be or'd with dwMask to fill in all of
  222. // the holes.
  223. dwNewMask = dwMask | ~dwNewMask;
  224. // If the new mask is different, correct it here
  225. if (dwMask != dwNewMask) {
  226. WCHAR pszAddr[32];
  227. wsprintfW(pszAddr, L"%d.%d.%d.%d", FIRST_IPADDRESS (dwNewMask),
  228. SECOND_IPADDRESS(dwNewMask),
  229. THIRD_IPADDRESS (dwNewMask),
  230. FOURTH_IPADDRESS(dwNewMask));
  231. SendMessage(hwndIpAddr, IP_SETADDRESS, 0, (LPARAM)pszAddr);
  232. }
  233. return NO_ERROR;
  234. }
  235. LRESULT FAR PASCAL IPAddressWndFn( hWnd, wMsg, wParam, lParam )
  236. HWND hWnd;
  237. UINT wMsg;
  238. WPARAM wParam;
  239. LPARAM lParam;
  240. {
  241. LONG lResult;
  242. HGLOBAL hControl;
  243. CONTROL *pControl;
  244. int i;
  245. lResult = TRUE;
  246. switch( wMsg )
  247. {
  248. case WM_HELP:
  249. {
  250. HWND hwndParent = GetParent(hWnd);
  251. HELPINFO* p = (HELPINFO*)lParam;
  252. p->hItemHandle = hWnd;
  253. p->iCtrlId = (INT) GetWindowLongPtr(hWnd, GWLP_ID);
  254. TRACE4( "IPAddressWndFn(HLP,t=%d,id=%d,h=$%08x,p=$%08x)",
  255. p->iContextType,p->iCtrlId,p->hItemHandle,hwndParent);
  256. SendMessage(hwndParent, WM_HELP, wParam, lParam);
  257. return 0;
  258. }
  259. break;
  260. case WM_CONTEXTMENU:
  261. {
  262. SendMessage(GetParent(hWnd), WM_CONTEXTMENU, (WPARAM)GetParent(hWnd), 0);
  263. return 0;
  264. }
  265. break;
  266. // use empty string (not NULL) to set to blank
  267. case WM_SETTEXT:
  268. {
  269. static TCHAR szBuf[CHARS_PER_FIELD+1];
  270. DWORD dwValue[4];
  271. LPTSTR pszString = (LPTSTR)lParam;
  272. if (!pszString)
  273. pszString = TEXT("0.0.0.0");
  274. FormatIPAddress(pszString, &dwValue[0]);
  275. hControl = GET_CONTROL_HANDLE(hWnd);
  276. pControl = (CONTROL *)GlobalLock(hControl);
  277. pControl->bCancelParentNotify = TRUE;
  278. for (i = 0; i < NUM_FIELDS; ++i)
  279. {
  280. if (pszString[0] == 0)
  281. {
  282. szBuf[0] = 0;
  283. }
  284. else
  285. {
  286. wsprintf(szBuf, TEXT("%d"), dwValue[i]);
  287. }
  288. SendMessage(pControl->Children[i].hWnd, WM_SETTEXT,
  289. 0, (LPARAM) (LPSTR) szBuf);
  290. }
  291. pControl->bCancelParentNotify = FALSE;
  292. SendMessage(pControl->hwndParent, WM_COMMAND,
  293. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  294. GlobalUnlock(hControl);
  295. }
  296. break;
  297. case WM_GETTEXTLENGTH:
  298. case WM_GETTEXT:
  299. {
  300. int iFieldValue;
  301. int srcPos, desPos;
  302. DWORD dwValue[4];
  303. TCHAR pszResult[30];
  304. TCHAR *pszDest = (TCHAR *)lParam;
  305. hControl = GET_CONTROL_HANDLE(hWnd);
  306. pControl = (CONTROL *)GlobalLock(hControl);
  307. lResult = 0;
  308. dwValue[0] = 0;
  309. dwValue[1] = 0;
  310. dwValue[2] = 0;
  311. dwValue[3] = 0;
  312. for (i = 0; i < NUM_FIELDS; ++i)
  313. {
  314. iFieldValue = GetFieldValue(&(pControl->Children[i]));
  315. if (iFieldValue == -1)
  316. iFieldValue = 0;
  317. else
  318. ++lResult;
  319. dwValue[i] = iFieldValue;
  320. }
  321. wsprintf( pszResult, TEXT("%d.%d.%d.%d"), dwValue[0], dwValue[1], dwValue[2], dwValue[3] );
  322. if ( wMsg == WM_GETTEXTLENGTH )
  323. {
  324. lResult = lstrlen( pszResult );
  325. }
  326. else
  327. {
  328. for ( srcPos=0, desPos=0; (srcPos+1<(INT)wParam) && (pszResult[srcPos]!=TEXT('\0')); )
  329. {
  330. pszDest[desPos++] = pszResult[srcPos++];
  331. }
  332. pszDest[desPos]=TEXT('\0');
  333. lResult = desPos;
  334. }
  335. GlobalUnlock(hControl);
  336. }
  337. break;
  338. case WM_GETDLGCODE :
  339. lResult = DLGC_WANTCHARS;
  340. break;
  341. case WM_NCCREATE:
  342. SetWindowLong(hWnd, GWL_EXSTYLE, (GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_CLIENTEDGE));
  343. lResult = TRUE;
  344. break;
  345. case WM_CREATE : /* create pallette window */
  346. {
  347. HDC hdc;
  348. UINT uiFieldStart;
  349. FARPROC lpfnFieldProc;
  350. hControl = GlobalAlloc(GMEM_MOVEABLE, sizeof(CONTROL));
  351. if (hControl)
  352. {
  353. HFONT OldFont;
  354. RECT rect;
  355. #define LPCS ((CREATESTRUCT *)lParam)
  356. pControl = (CONTROL *)GlobalLock(hControl);
  357. pControl->fEnabled = TRUE;
  358. pControl->fPainted = FALSE;
  359. pControl->fInMessageBox = FALSE;
  360. pControl->hwndParent = LPCS->hwndParent;
  361. pControl->uiFillerWidth = 1;
  362. pControl->bControlInFocus = FALSE;
  363. pControl->bCancelParentNotify = FALSE;
  364. hdc = GetDC(hWnd);
  365. GetClientRect(hWnd, &rect);
  366. OldFont = SelectObject( hdc, CreateFontIndirect(&logfont) );
  367. if( NULL != OldFont )
  368. {
  369. HFONT NewFont;
  370. GetCharWidth(hdc, FILLER, FILLER,
  371. (int *)(&pControl->uiFillerWidth));
  372. NewFont = SelectObject(hdc, OldFont );
  373. if( NULL != NewFont )
  374. {
  375. DeleteObject( NewFont );
  376. }
  377. }
  378. ReleaseDC(hWnd, hdc);
  379. pControl->uiFieldWidth = (LPCS->cx
  380. - LEAD_ROOM
  381. - pControl->uiFillerWidth
  382. *(NUM_FIELDS-1))
  383. / NUM_FIELDS;
  384. uiFieldStart = LEAD_ROOM;
  385. lpfnFieldProc = MakeProcInstance((FARPROC)IPAddressFieldProc,
  386. LPCS->hInstance);
  387. for (i = 0; i < NUM_FIELDS; ++i)
  388. {
  389. pControl->Children[i].byLow = MIN_FIELD_VALUE;
  390. pControl->Children[i].byHigh = MAX_FIELD_VALUE;
  391. pControl->Children[i].hWnd = CreateWindowEx(0,
  392. TEXT("Edit"),
  393. NULL,
  394. WS_CHILD | WS_VISIBLE |
  395. ES_CENTER,
  396. uiFieldStart,
  397. HEAD_ROOM,
  398. pControl->uiFieldWidth,
  399. (rect.bottom-rect.top),
  400. hWnd,
  401. (HMENU)UlongToPtr(i),
  402. LPCS->hInstance,
  403. (LPVOID)NULL);
  404. SendMessage(pControl->Children[i].hWnd, EM_LIMITTEXT,
  405. CHARS_PER_FIELD, 0L);
  406. SendMessage(pControl->Children[i].hWnd, WM_SETFONT,
  407. (WPARAM)CreateFontIndirect(&logfont), TRUE);
  408. pControl->Children[i].lpfnWndProc =
  409. (WNDPROC)GetWindowLongPtr(pControl->Children[i].hWnd,
  410. GWLP_WNDPROC);
  411. SetWindowLongPtr(pControl->Children[i].hWnd,
  412. GWLP_WNDPROC, (ULONG_PTR)lpfnFieldProc);
  413. uiFieldStart += pControl->uiFieldWidth
  414. + pControl->uiFillerWidth;
  415. }
  416. GlobalUnlock(hControl);
  417. SAVE_CONTROL_HANDLE(hWnd, hControl);
  418. #undef LPCS
  419. }
  420. else
  421. DestroyWindow(hWnd);
  422. }
  423. lResult = 0;
  424. break;
  425. case WM_PAINT: /* paint control window */
  426. {
  427. PAINTSTRUCT Ps;
  428. RECT rect;
  429. UINT uiFieldStart;
  430. COLORREF TextColor;
  431. COLORREF cRef;
  432. HFONT OldFont, NewFont, TmpFont;
  433. HBRUSH hbr;
  434. //Add return value check for bug 199026
  435. if ( BeginPaint(hWnd, (LPPAINTSTRUCT)&Ps) )
  436. {
  437. NewFont = CreateFontIndirect(&logfont);
  438. if (NewFont)
  439. {
  440. OldFont = SelectObject( Ps.hdc, NewFont );
  441. if (OldFont)
  442. {
  443. GetClientRect(hWnd, &rect);
  444. hControl = GET_CONTROL_HANDLE(hWnd);
  445. if (hControl)
  446. {
  447. pControl = (CONTROL *)GlobalLock(hControl);
  448. if (pControl)
  449. {
  450. if (pControl->fEnabled)
  451. {
  452. TextColor = GetSysColor(COLOR_WINDOWTEXT);
  453. cRef = GetSysColor(COLOR_WINDOW);
  454. }
  455. else
  456. {
  457. TextColor = GetSysColor(COLOR_GRAYTEXT);
  458. cRef = GetSysColor(COLOR_3DFACE);
  459. }
  460. if (cRef)
  461. SetBkColor(Ps.hdc, cRef);
  462. if (TextColor)
  463. SetTextColor(Ps.hdc, TextColor);
  464. hbr = CreateSolidBrush(cRef);
  465. if ( NULL != hbr )
  466. {
  467. FillRect(Ps.hdc, &rect, hbr);
  468. DeleteObject(hbr);
  469. }
  470. SetRect(&rect,
  471. 0,
  472. HEAD_ROOM,
  473. pControl->uiFillerWidth,
  474. (rect.bottom-rect.top));
  475. ExtTextOut(Ps.hdc,
  476. rect.left,
  477. HEAD_ROOM,
  478. ETO_OPAQUE,
  479. &rect,
  480. L" ",
  481. 1,
  482. NULL);
  483. for (i = 0; i < NUM_FIELDS-1; ++i)
  484. {
  485. rect.left += pControl->uiFieldWidth +
  486. pControl->uiFillerWidth;
  487. rect.right += rect.left +
  488. pControl->uiFillerWidth;
  489. ExtTextOut(Ps.hdc,
  490. rect.left,
  491. HEAD_ROOM,
  492. ETO_OPAQUE,
  493. &rect,
  494. SZFILLER,
  495. 1,
  496. NULL);
  497. }
  498. pControl->fPainted = TRUE;
  499. GlobalUnlock(hControl);
  500. }
  501. }
  502. TmpFont = SelectObject(Ps.hdc, OldFont);
  503. if (TmpFont)
  504. {
  505. NewFont = TmpFont;
  506. }
  507. else
  508. {
  509. NewFont = OldFont;
  510. }
  511. }
  512. DeleteObject(NewFont);
  513. }
  514. EndPaint(hWnd, &Ps);
  515. }
  516. }
  517. break;
  518. case WM_SETFOCUS : /* get focus - display caret */
  519. hControl = GET_CONTROL_HANDLE(hWnd);
  520. pControl = (CONTROL *)GlobalLock(hControl);
  521. EnterField(&(pControl->Children[0]), 0, CHARS_PER_FIELD);
  522. GlobalUnlock(hControl);
  523. break;
  524. case WM_LBUTTONDOWN : /* left button depressed - fall through */
  525. SetFocus(hWnd);
  526. break;
  527. case WM_ENABLE:
  528. {
  529. hControl = GET_CONTROL_HANDLE(hWnd);
  530. pControl = (CONTROL *)GlobalLock(hControl);
  531. pControl->fEnabled = (BOOL)wParam;
  532. for (i = 0; i < NUM_FIELDS; ++i)
  533. {
  534. EnableWindow(pControl->Children[i].hWnd, (BOOL)wParam);
  535. }
  536. if (pControl->fPainted) InvalidateRect(hWnd, NULL, FALSE);
  537. GlobalUnlock(hControl);
  538. }
  539. break;
  540. case WM_DESTROY :
  541. hControl = GET_CONTROL_HANDLE(hWnd);
  542. pControl = (CONTROL *)GlobalLock(hControl);
  543. // Restore all the child window procedures before we delete our memory block.
  544. for (i = 0; i < NUM_FIELDS; ++i)
  545. {
  546. SetWindowLongPtr(pControl->Children[i].hWnd, GWLP_WNDPROC,
  547. (ULONG_PTR)pControl->Children[i].lpfnWndProc);
  548. }
  549. GlobalUnlock(hControl);
  550. GlobalFree(hControl);
  551. break;
  552. case WM_COMMAND:
  553. switch (HIWORD(wParam))
  554. {
  555. // One of the fields lost the focus, see if it lost the focus to another field
  556. // of if we've lost the focus altogether. If its lost altogether, we must send
  557. // an EN_KILLFOCUS notification on up the ladder.
  558. case EN_KILLFOCUS:
  559. {
  560. HWND hFocus;
  561. hControl = GET_CONTROL_HANDLE(hWnd);
  562. pControl = (CONTROL *)GlobalLock(hControl);
  563. if (!pControl->fInMessageBox)
  564. {
  565. hFocus = GetFocus();
  566. for (i = 0; i < NUM_FIELDS; ++i)
  567. if (pControl->Children[i].hWnd == hFocus)
  568. break;
  569. if (i >= NUM_FIELDS)
  570. {
  571. // Before sending the message up the ladder, make sure that
  572. // the ip address is contiguous if needed
  573. if (IPADDR_GET_SUBSTYLE(hWnd) & IPADDR_EX_STYLE_CONTIGUOUS)
  574. IpAddrMakeContiguous(hWnd);
  575. SendMessage(pControl->hwndParent, WM_COMMAND,
  576. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID),
  577. EN_KILLFOCUS), (LPARAM)hWnd);
  578. pControl->bControlInFocus = FALSE;
  579. }
  580. }
  581. GlobalUnlock(hControl);
  582. }
  583. break;
  584. case EN_SETFOCUS:
  585. {
  586. HWND hFocus;
  587. hControl = GET_CONTROL_HANDLE(hWnd);
  588. pControl = (CONTROL *)GlobalLock(hControl);
  589. if (!pControl->fInMessageBox)
  590. {
  591. hFocus = (HWND)lParam;
  592. for (i = 0; i < NUM_FIELDS; ++i)
  593. if (pControl->Children[i].hWnd == hFocus)
  594. break;
  595. // send a focus message when the
  596. if (i < NUM_FIELDS && pControl->bControlInFocus == FALSE)
  597. {
  598. SendMessage(pControl->hwndParent, WM_COMMAND,
  599. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID),
  600. EN_SETFOCUS), (LPARAM)hWnd);
  601. pControl->bControlInFocus = TRUE; // only set the focus once
  602. }
  603. }
  604. GlobalUnlock(hControl);
  605. }
  606. break;
  607. case EN_CHANGE:
  608. hControl = GET_CONTROL_HANDLE(hWnd);
  609. pControl = (CONTROL *)GlobalLock(hControl);
  610. if (pControl->bCancelParentNotify == FALSE)
  611. {
  612. SendMessage(pControl->hwndParent, WM_COMMAND,
  613. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  614. }
  615. GlobalUnlock(hControl);
  616. break;
  617. }
  618. break;
  619. // Get the value of the IP Address. The address is placed in the DWORD pointed
  620. // to by lParam and the number of non-blank fields is returned.
  621. case IP_GETADDRESS:
  622. {
  623. int iFieldValue;
  624. DWORD dwValue;
  625. hControl = GET_CONTROL_HANDLE(hWnd);
  626. pControl = (CONTROL *)GlobalLock(hControl);
  627. lResult = 0;
  628. dwValue = 0;
  629. for (i = 0; i < NUM_FIELDS; ++i)
  630. {
  631. iFieldValue = GetFieldValue(&(pControl->Children[i]));
  632. if (iFieldValue == -1)
  633. iFieldValue = 0;
  634. else
  635. ++lResult;
  636. dwValue = (dwValue << 8) + iFieldValue;
  637. }
  638. *((DWORD *)lParam) = dwValue;
  639. GlobalUnlock(hControl);
  640. }
  641. break;
  642. // Clear all fields to blanks.
  643. case IP_CLEARADDRESS:
  644. {
  645. hControl = GET_CONTROL_HANDLE(hWnd);
  646. pControl = (CONTROL *)GlobalLock(hControl);
  647. pControl->bCancelParentNotify = TRUE;
  648. for (i = 0; i < NUM_FIELDS; ++i)
  649. {
  650. SendMessage(pControl->Children[i].hWnd, WM_SETTEXT,
  651. 0, (LPARAM) (LPSTR) TEXT(""));
  652. }
  653. pControl->bCancelParentNotify = FALSE;
  654. SendMessage(pControl->hwndParent, WM_COMMAND,
  655. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  656. GlobalUnlock(hControl);
  657. }
  658. break;
  659. // Set the value of the IP Address. The address is in the lParam with the
  660. // first address byte being the high byte, the second being the second byte,
  661. // and so on. A lParam value of -1 removes the address.
  662. case IP_SETADDRESS:
  663. {
  664. static TCHAR szBuf[CHARS_PER_FIELD+1];
  665. DWORD dwValue[4];
  666. LPTSTR pszString = (LPTSTR)lParam;
  667. FormatIPAddress(pszString, &dwValue[0]);
  668. hControl = GET_CONTROL_HANDLE(hWnd);
  669. pControl = (CONTROL *)GlobalLock(hControl);
  670. pControl->bCancelParentNotify = TRUE;
  671. for (i = 0; i < NUM_FIELDS; ++i)
  672. {
  673. if (pszString[0] == 0)
  674. {
  675. szBuf[0] =0;
  676. }
  677. else
  678. {
  679. wsprintf(szBuf, TEXT("%d"), dwValue[i]);
  680. }
  681. SendMessage(pControl->Children[i].hWnd, WM_SETTEXT,
  682. 0, (LPARAM) (LPSTR) szBuf);
  683. }
  684. pControl->bCancelParentNotify = FALSE;
  685. SendMessage(pControl->hwndParent, WM_COMMAND,
  686. MAKEWPARAM(GetWindowLong(hWnd, GWL_ID), EN_CHANGE), (LPARAM)hWnd);
  687. GlobalUnlock(hControl);
  688. }
  689. break;
  690. case IP_SETRANGE:
  691. if (wParam < NUM_FIELDS)
  692. {
  693. hControl = GET_CONTROL_HANDLE(hWnd);
  694. pControl = (CONTROL *)GlobalLock(hControl);
  695. pControl->Children[wParam].byLow = LOBYTE(LOWORD(lParam));
  696. pControl->Children[wParam].byHigh = HIBYTE(LOWORD(lParam));
  697. GlobalUnlock(hControl);
  698. }
  699. break;
  700. // Set the focus to this control.
  701. // wParam = the field number to set focus to, or -1 to set the focus to the
  702. // first non-blank field.
  703. case IP_SETFOCUS:
  704. hControl = GET_CONTROL_HANDLE(hWnd);
  705. pControl = (CONTROL *)GlobalLock(hControl);
  706. if (wParam >= NUM_FIELDS)
  707. {
  708. for (wParam = 0; wParam < NUM_FIELDS; ++wParam)
  709. if (GetFieldValue(&(pControl->Children[wParam])) == -1) break;
  710. if (wParam >= NUM_FIELDS) wParam = 0;
  711. }
  712. EnterField(&(pControl->Children[wParam]), 0, CHARS_PER_FIELD);
  713. GlobalUnlock(hControl);
  714. break;
  715. // Determine whether all four subfields are blank
  716. case IP_ISBLANK:
  717. hControl = GET_CONTROL_HANDLE(hWnd);
  718. pControl = (CONTROL *)GlobalLock(hControl);
  719. lResult = TRUE;
  720. for (i = 0; i < NUM_FIELDS; ++i)
  721. {
  722. if (GetFieldValue(&(pControl->Children[i])) != -1)
  723. {
  724. lResult = FALSE;
  725. break;
  726. }
  727. }
  728. GlobalUnlock(hControl);
  729. break;
  730. default:
  731. lResult = (LONG) DefWindowProc( hWnd, wMsg, wParam, lParam );
  732. break;
  733. }
  734. return( lResult );
  735. }
  736. /*
  737. IPAddressFieldProc() - Edit field window procedure
  738. This function sub-classes each edit field.
  739. */
  740. LRESULT FAR PASCAL IPAddressFieldProc(HWND hWnd,
  741. UINT wMsg,
  742. WPARAM wParam,
  743. LPARAM lParam)
  744. {
  745. HANDLE hControl;
  746. CONTROL *pControl;
  747. FIELD *pField;
  748. HWND hControlWindow;
  749. WORD wChildID;
  750. LRESULT lresult;
  751. if (!(hControlWindow = GetParent(hWnd)))
  752. return 0;
  753. hControl = GET_CONTROL_HANDLE(hControlWindow);
  754. pControl = (CONTROL *)GlobalLock(hControl);
  755. wChildID = (WORD)GetWindowLong(hWnd, GWL_ID);
  756. pField = &(pControl->Children[wChildID]);
  757. if (pField->hWnd != hWnd) return 0;
  758. switch (wMsg)
  759. {
  760. case WM_CONTEXTMENU:
  761. {
  762. SendMessage(GetParent(hWnd), WM_CONTEXTMENU, (WPARAM)GetParent(hWnd), 0);
  763. return 0;
  764. }
  765. break;
  766. case WM_HELP:
  767. {
  768. HWND hwndParent = GetParent(hWnd);
  769. HELPINFO* p = (HELPINFO*)lParam;
  770. p->hItemHandle = hWnd;
  771. p->iCtrlId = (INT) GetWindowLongPtr(hWnd, GWLP_ID);
  772. TRACE4( "IPAddressFieldProc(HLP,t=%d,id=%d,h=$%08x,p=$%08x)",
  773. p->iContextType,p->iCtrlId,p->hItemHandle,hwndParent);
  774. SendMessage(hwndParent, WM_HELP, wParam, lParam);
  775. return 0;
  776. }
  777. break;
  778. case WM_DESTROY:
  779. DeleteObject( (HGDIOBJ)SendMessage( hWnd, WM_GETFONT, 0, 0 ));
  780. return 0;
  781. case WM_CHAR:
  782. // Typing in the last digit in a field, skips to the next field.
  783. if (wParam >= TEXT('0') && wParam <= TEXT('9'))
  784. {
  785. DWORD dwResult;
  786. dwResult = (DWORD)CallWindowProc(pControl->Children[wChildID].lpfnWndProc,
  787. hWnd, wMsg, wParam, lParam);
  788. dwResult = (DWORD) SendMessage(hWnd, EM_GETSEL, 0, 0L);
  789. if (dwResult == MAKELPARAM(CHARS_PER_FIELD, CHARS_PER_FIELD)
  790. && ExitField(pControl, wChildID)
  791. && wChildID < NUM_FIELDS-1)
  792. {
  793. EnterField(&(pControl->Children[wChildID+1]),
  794. 0, CHARS_PER_FIELD);
  795. }
  796. GlobalUnlock( hControl );
  797. return dwResult;
  798. }
  799. // spaces and periods fills out the current field and then if possible,
  800. // goes to the next field.
  801. else if (wParam == FILLER || wParam == SPACE )
  802. {
  803. DWORD dwResult;
  804. dwResult = (DWORD) SendMessage(hWnd, EM_GETSEL, 0, 0L);
  805. if (dwResult != 0L && HIWORD(dwResult) == LOWORD(dwResult)
  806. && ExitField(pControl, wChildID))
  807. {
  808. if (wChildID >= NUM_FIELDS-1)
  809. MessageBeep((UINT)-1);
  810. else
  811. {
  812. EnterField(&(pControl->Children[wChildID+1]),
  813. 0, CHARS_PER_FIELD);
  814. }
  815. }
  816. GlobalUnlock( hControl );
  817. return 0;
  818. }
  819. // Backspaces go to the previous field if at the beginning of the current field.
  820. // Also, if the focus shifts to the previous field, the backspace must be
  821. // processed by that field.
  822. else if (wParam == BACK_SPACE)
  823. {
  824. if (wChildID > 0 && SendMessage(hWnd, EM_GETSEL, 0, 0L) == 0L)
  825. {
  826. if (SwitchFields(pControl, wChildID, wChildID-1,
  827. CHARS_PER_FIELD, CHARS_PER_FIELD)
  828. && SendMessage(pControl->Children[wChildID-1].hWnd,
  829. EM_LINELENGTH, 0, 0L) != 0L)
  830. {
  831. SendMessage(pControl->Children[wChildID-1].hWnd,
  832. wMsg, wParam, lParam);
  833. }
  834. GlobalUnlock( hControl );
  835. return 0;
  836. }
  837. }
  838. // Any other printable characters are not allowed.
  839. else if (wParam > SPACE)
  840. {
  841. MessageBeep((UINT)-1);
  842. GlobalUnlock( hControl );
  843. return 0;
  844. }
  845. break;
  846. case WM_KEYDOWN:
  847. switch (wParam)
  848. {
  849. // Arrow keys move between fields when the end of a field is reached.
  850. case VK_LEFT:
  851. case VK_RIGHT:
  852. case VK_UP:
  853. case VK_DOWN:
  854. if (GetKeyState(VK_CONTROL) < 0)
  855. {
  856. if ((wParam == VK_LEFT || wParam == VK_UP) && wChildID > 0)
  857. {
  858. SwitchFields(pControl, wChildID, wChildID-1,
  859. 0, CHARS_PER_FIELD);
  860. GlobalUnlock( hControl );
  861. return 0;
  862. }
  863. else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
  864. && wChildID < NUM_FIELDS-1)
  865. {
  866. SwitchFields(pControl, wChildID, wChildID+1,
  867. 0, CHARS_PER_FIELD);
  868. GlobalUnlock( hControl );
  869. return 0;
  870. }
  871. }
  872. else
  873. {
  874. DWORD dwResult;
  875. WORD wStart, wEnd;
  876. dwResult = (DWORD) SendMessage(hWnd, EM_GETSEL, 0, 0L);
  877. wStart = LOWORD(dwResult);
  878. wEnd = HIWORD(dwResult);
  879. if (wStart == wEnd)
  880. {
  881. if ((wParam == VK_LEFT || wParam == VK_UP)
  882. && wStart == 0
  883. && wChildID > 0)
  884. {
  885. SwitchFields(pControl, wChildID, wChildID-1,
  886. CHARS_PER_FIELD, CHARS_PER_FIELD);
  887. GlobalUnlock( hControl );
  888. return 0;
  889. }
  890. else if ((wParam == VK_RIGHT || wParam == VK_DOWN)
  891. && wChildID < NUM_FIELDS-1)
  892. {
  893. dwResult = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0L);
  894. if (wStart >= dwResult)
  895. {
  896. SwitchFields(pControl, wChildID, wChildID+1, 0, 0);
  897. GlobalUnlock( hControl );
  898. return 0;
  899. }
  900. }
  901. }
  902. }
  903. break;
  904. // Home jumps back to the beginning of the first field.
  905. case VK_HOME:
  906. if (wChildID > 0)
  907. {
  908. SwitchFields(pControl, wChildID, 0, 0, 0);
  909. GlobalUnlock( hControl );
  910. return 0;
  911. }
  912. break;
  913. // End scoots to the end of the last field.
  914. case VK_END:
  915. if (wChildID < NUM_FIELDS-1)
  916. {
  917. SwitchFields(pControl, wChildID, NUM_FIELDS-1,
  918. CHARS_PER_FIELD, CHARS_PER_FIELD);
  919. GlobalUnlock( hControl );
  920. return 0;
  921. }
  922. break;
  923. } // switch (wParam)
  924. break;
  925. case WM_KILLFOCUS:
  926. if ( !ExitField( pControl, wChildID ))
  927. {
  928. GlobalUnlock( hControl );
  929. return 0;
  930. }
  931. } // switch (wMsg)
  932. lresult = CallWindowProc(pControl->Children[wChildID].lpfnWndProc,
  933. hWnd, wMsg, wParam, lParam);
  934. GlobalUnlock( hControl );
  935. return lresult;
  936. }
  937. /*
  938. Switch the focus from one field to another.
  939. call
  940. pControl = Pointer to the CONTROL structure.
  941. iOld = Field we're leaving.
  942. iNew = Field we're entering.
  943. hNew = Window of field to goto
  944. wStart = First character selected
  945. wEnd = Last character selected + 1
  946. returns
  947. TRUE on success, FALSE on failure.
  948. Only switches fields if the current field can be validated.
  949. */
  950. BOOL SwitchFields(CONTROL *pControl, int iOld, int iNew, WORD wStart, WORD wEnd)
  951. {
  952. if (!ExitField(pControl, iOld)) return FALSE;
  953. EnterField(&(pControl->Children[iNew]), wStart, wEnd);
  954. return TRUE;
  955. }
  956. /*
  957. Set the focus to a specific field's window.
  958. call
  959. pField = pointer to field structure for the field.
  960. wStart = First character selected
  961. wEnd = Last character selected + 1
  962. */
  963. void EnterField(FIELD *pField, WORD wStart, WORD wEnd)
  964. {
  965. SetFocus(pField->hWnd);
  966. SendMessage(pField->hWnd, EM_SETSEL, wStart, wEnd);
  967. }
  968. /*
  969. Exit a field.
  970. call
  971. pControl = pointer to CONTROL structure.
  972. iField = field number being exited.
  973. returns
  974. TRUE if the user may exit the field.
  975. FALSE if he may not.
  976. */
  977. BOOL ExitField(CONTROL *pControl, int iField)
  978. {
  979. HWND hControlWnd;
  980. HWND hDialog;
  981. WORD wLength;
  982. FIELD *pField;
  983. static TCHAR szBuf[CHARS_PER_FIELD+1];
  984. int i,j;
  985. pField = &(pControl->Children[iField]);
  986. *(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
  987. wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)szBuf);
  988. if (wLength != 0)
  989. {
  990. szBuf[wLength] = TEXT('\0');
  991. for (j=0,i=0;j<(INT)wLength;j++)
  992. {
  993. i=i*10+szBuf[j]-TEXT('0');
  994. }
  995. if (i < (int)(UINT)pField->byLow || i > (int)(UINT)pField->byHigh)
  996. {
  997. if ( i < (int)(UINT) pField->byLow )
  998. {
  999. /* too small */
  1000. wsprintf(szBuf, TEXT("%d"), (int)(UINT)pField->byLow );
  1001. }
  1002. else
  1003. {
  1004. /* must be bigger */
  1005. wsprintf(szBuf, TEXT("%d"), (int)(UINT)pField->byHigh );
  1006. }
  1007. SendMessage(pField->hWnd, WM_SETTEXT, 0, (LPARAM) (LPSTR) szBuf);
  1008. if ((hControlWnd = GetParent(pField->hWnd)) != NULL
  1009. && (hDialog = GetParent(hControlWnd)) != NULL)
  1010. {
  1011. MSGARGS msgargs;
  1012. TCHAR szLow[ 50 ];
  1013. TCHAR szHigh[ 50 ];
  1014. pControl->fInMessageBox = TRUE;
  1015. ZeroMemory( &msgargs, sizeof(msgargs) );
  1016. msgargs.dwFlags = MB_ICONEXCLAMATION + MB_OK;
  1017. wsprintf( szLow, TEXT("%d"), (int )pField->byLow );
  1018. msgargs.apszArgs[ 0 ] = szLow;
  1019. wsprintf( szHigh, TEXT("%d"), (int )pField->byHigh );
  1020. msgargs.apszArgs[ 1 ] = szHigh;
  1021. MsgDlgUtil( hDialog, g_dwBadIpAddrRange,
  1022. &msgargs, g_hLibInstance, g_dwErrorTitle );
  1023. pControl->fInMessageBox = FALSE;
  1024. SendMessage(pField->hWnd, EM_SETSEL, 0, CHARS_PER_FIELD);
  1025. return FALSE;
  1026. }
  1027. }
  1028. }
  1029. return TRUE;
  1030. }
  1031. /*
  1032. Get the value stored in a field.
  1033. call
  1034. pField = pointer to the FIELD structure for the field.
  1035. returns
  1036. The value (0..255) or -1 if the field has not value.
  1037. */
  1038. int GetFieldValue(FIELD *pField)
  1039. {
  1040. WORD wLength;
  1041. static TCHAR szBuf[CHARS_PER_FIELD+1];
  1042. INT i,j;
  1043. *(WORD *)szBuf = (sizeof(szBuf)/sizeof(TCHAR)) - 1;
  1044. wLength = (WORD)SendMessage(pField->hWnd,EM_GETLINE,0,(LPARAM)szBuf);
  1045. if (wLength != 0)
  1046. {
  1047. szBuf[wLength] = TEXT('\0');
  1048. for (j=0,i=0;j<(INT)wLength;j++)
  1049. {
  1050. i=i*10+szBuf[j]-TEXT('0');
  1051. }
  1052. return i;
  1053. }
  1054. else
  1055. return -1;
  1056. }