Change the callback declarations to a safer format.
[wine] / dlls / comctl32 / ipaddress.c
1 /*
2  * IP Address control
3  *
4  * Copyright 1999 Chris Morgan<cmorgan@wpi.edu> and
5  *                James Abbatiello<abbeyj@wpi.edu>
6  * Copyright 1998, 1999 Eric Kohl
7  * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
8  *
9  * NOTES
10  *
11  * TODO:
12  *    -Edit control doesn't support the ES_CENTER style which prevents
13  *     this ipaddress control from having centered text look like the
14  *     windows ipaddress control
15  *    -Check all notifications/behavior.
16  *    -Optimization: 
17  *        -include lpipsi in IPADDRESS_INFO.
18  *        -CurrentFocus: field that has focus at moment of processing.
19  *        -connect Rect32 rcClient.
20  *        -check ipaddress.cpp for missing features.
21  *    -refresh: draw '.' instead of setpixel.
22  */
23
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "winbase.h"
30 #include "commctrl.h"
31 #include "heap.h"
32 #include "debugtools.h"
33
34 DEFAULT_DEBUG_CHANNEL(ipaddress);
35
36 typedef struct
37 {
38         BYTE LowerLimit[4];
39         BYTE UpperLimit[4];
40
41         RECT    rcClient;
42         INT     uFocus;
43 } IPADDRESS_INFO;
44
45 typedef struct
46 {
47     WNDPROC wpOrigProc[4];
48     HWND    hwndIP[4];
49     IPADDRESS_INFO *infoPtr;
50     HWND    hwnd;
51     UINT    uRefCount;
52 } IP_SUBCLASS_INFO, *LPIP_SUBCLASS_INFO;
53
54 #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0))
55
56 static BOOL 
57 IPADDRESS_SendNotify (HWND hwnd, UINT command);
58 static BOOL 
59 IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue);
60
61 /* property name of tooltip window handle */
62 #define IP_SUBCLASS_PROP "CCIP32SubclassInfo"
63
64
65 static LRESULT CALLBACK
66 IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
67
68
69 static VOID
70 IPADDRESS_Refresh (HWND hwnd, HDC hdc)
71 {
72   RECT rcClient;
73   HBRUSH hbr;
74   COLORREF clr=GetSysColor (COLOR_3DDKSHADOW);
75   int i,x,fieldsize;
76
77   GetClientRect (hwnd, &rcClient);
78   hbr = CreateSolidBrush (RGB(255,255,255));
79   DrawEdge (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
80   FillRect (hdc, &rcClient, hbr);
81   DeleteObject (hbr);
82
83   x=rcClient.left;
84   fieldsize=(rcClient.right-rcClient.left) / 4;
85
86   for (i=0; i<3; i++) {         /* Should draw text "." here */
87     x+=fieldsize;
88     SetPixel (hdc, x,   13, clr);
89     SetPixel (hdc, x,   14, clr);
90     SetPixel (hdc, x+1, 13, clr);
91     SetPixel (hdc, x+1, 14, clr);
92   }
93 }
94
95
96 static LRESULT
97 IPADDRESS_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
98 {
99   IPADDRESS_INFO *infoPtr;
100   RECT rcClient, edit;
101   int i,fieldsize;
102   LPIP_SUBCLASS_INFO lpipsi;
103         
104
105   infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO));
106   SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
107
108   GetClientRect (hwnd, &rcClient);
109
110   fieldsize=(rcClient.right-rcClient.left) /4;
111
112   edit.top   =rcClient.top+2;
113   edit.bottom=rcClient.bottom-2;
114
115   lpipsi=(LPIP_SUBCLASS_INFO) GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
116   if (lpipsi == NULL)  {
117     lpipsi = (LPIP_SUBCLASS_INFO) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO));
118     lpipsi->hwnd = hwnd;
119     lpipsi->uRefCount++;
120     SetPropA ((HWND)hwnd, IP_SUBCLASS_PROP, (HANDLE)lpipsi);
121 /*              infoPtr->lpipsi= lpipsi; */
122   } else 
123     WARN("IP-create called twice\n");
124         
125   for (i=0; i<=3; i++)
126   {
127     infoPtr->LowerLimit[i]=0;
128     infoPtr->UpperLimit[i]=255;
129     edit.left=rcClient.left+i*fieldsize+6;
130     edit.right=rcClient.left+(i+1)*fieldsize-2;
131     lpipsi->hwndIP[i]= CreateWindowA ("edit", NULL, 
132         WS_CHILD | WS_VISIBLE | ES_CENTER,
133         edit.left, edit.top, edit.right-edit.left, edit.bottom-edit.top,
134         hwnd, (HMENU) 1, GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
135     lpipsi->wpOrigProc[i]= (WNDPROC)
136         SetWindowLongA (lpipsi->hwndIP[i],GWL_WNDPROC, (LONG)
137         IPADDRESS_SubclassProc);
138     SetPropA ((HWND)lpipsi->hwndIP[i], IP_SUBCLASS_PROP, (HANDLE)lpipsi);
139   }
140
141   lpipsi->infoPtr= infoPtr;
142
143   return 0;
144 }
145
146
147 static LRESULT
148 IPADDRESS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
149 {
150   int i;
151   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
152   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
153             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
154
155   for (i=0; i<=3; i++) {
156     SetWindowLongA ((HWND)lpipsi->hwndIP[i], GWL_WNDPROC,
157                   (LONG)lpipsi->wpOrigProc[i]);
158   }
159
160   COMCTL32_Free (infoPtr);
161   SetWindowLongA (hwnd, 0, 0);
162   return 0;
163 }
164
165
166 static LRESULT
167 IPADDRESS_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
168 {
169   HDC hdc;
170
171   TRACE("\n");
172   hdc = GetDC (hwnd);
173   IPADDRESS_Refresh (hwnd, hdc);
174   ReleaseDC (hwnd, hdc);
175
176   IPADDRESS_SendIPAddressNotify (hwnd, 0, 0);  /* FIXME: should use -1 */
177   IPADDRESS_SendNotify (hwnd, EN_KILLFOCUS);       
178   InvalidateRect (hwnd, NULL, TRUE);
179
180   return 0;
181 }
182
183
184 static LRESULT
185 IPADDRESS_Paint (HWND hwnd, WPARAM wParam)
186 {
187   HDC hdc;
188   PAINTSTRUCT ps;
189
190   hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
191   IPADDRESS_Refresh (hwnd, hdc);
192   if(!wParam)
193     EndPaint (hwnd, &ps);
194   return 0;
195 }
196
197
198 static LRESULT
199 IPADDRESS_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
200 {
201   HDC hdc;
202
203   TRACE("\n");
204
205   hdc = GetDC (hwnd);
206   IPADDRESS_Refresh (hwnd, hdc);
207   ReleaseDC (hwnd, hdc);
208
209   return 0;
210 }
211
212
213 static LRESULT
214 IPADDRESS_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
215 {
216   /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
217   TRACE("\n");
218   return 0;
219 }
220
221
222 static BOOL
223 IPADDRESS_SendNotify (HWND hwnd, UINT command)
224 {
225   TRACE("%x\n",command);
226   return (BOOL)SendMessageA (GetParent (hwnd), WM_COMMAND,
227               MAKEWPARAM (GetWindowLongA (hwnd, GWL_ID),command), (LPARAM)hwnd);
228 }
229
230
231 static BOOL
232 IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue)
233 {
234   NMIPADDRESS nmip;
235
236   TRACE("%x %x\n",field,newValue);
237   nmip.hdr.hwndFrom = hwnd;
238   nmip.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
239   nmip.hdr.code     = IPN_FIELDCHANGED;
240
241   nmip.iField=field;
242   nmip.iValue=newValue;
243
244   return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
245                              (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip);
246 }
247
248
249 static LRESULT
250 IPADDRESS_ClearAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
251 {
252   int i;
253   HDC hdc;
254   char buf[1];
255   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
256             GetPropA ((HWND)hwnd,IP_SUBCLASS_PROP);
257
258   TRACE("\n");
259
260   buf[0]=0;
261   for (i=0; i<=3; i++) 
262     SetWindowTextA (lpipsi->hwndIP[i],buf);
263         
264   hdc = GetDC (hwnd);
265   IPADDRESS_Refresh (hwnd, hdc);
266   ReleaseDC (hwnd, hdc);
267         
268   return 0;
269 }
270
271
272 static LRESULT
273 IPADDRESS_IsBlank (HWND hwnd, WPARAM wParam, LPARAM lParam)
274 {
275   int i;
276   char buf[20];
277   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
278             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
279
280   TRACE("\n");
281
282   for (i=0; i<=3; i++) {
283     GetWindowTextA (lpipsi->hwndIP[i],buf,5);
284     if (buf[0])
285       return 0;
286   }
287
288   return 1;
289 }
290
291
292 static LRESULT
293 IPADDRESS_GetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
294 {
295   char field[20];
296   int i,valid,fieldvalue;
297   DWORD ip_addr;
298   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
299   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
300             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
301
302   TRACE("\n");
303
304   valid=0;
305   ip_addr=0;
306   for (i=0; i<=3; i++) {
307     GetWindowTextA (lpipsi->hwndIP[i],field,4);
308     ip_addr*=256;
309     if (field[0]) {
310       field[3]=0;
311       fieldvalue=atoi(field);
312       if (fieldvalue<infoPtr->LowerLimit[i]) 
313         fieldvalue=infoPtr->LowerLimit[i];
314       if (fieldvalue>infoPtr->UpperLimit[i]) 
315         fieldvalue=infoPtr->UpperLimit[i];
316       ip_addr+=fieldvalue;
317       valid++;
318     }
319   }
320
321   *(LPDWORD) lParam=ip_addr;
322
323   return valid;
324 }
325
326
327 static LRESULT
328 IPADDRESS_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
329 {
330   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
331   INT index;
332         
333   TRACE("\n");
334
335   index=(INT) wParam;
336   if ((index<0) || (index>3)) return 0;
337
338   infoPtr->LowerLimit[index]=lParam & 0xff;
339   infoPtr->UpperLimit[index]=(lParam >>8)  & 0xff;
340   return 1;
341 }
342
343
344 static LRESULT
345 IPADDRESS_SetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
346 {
347   IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
348   HDC hdc;
349   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
350             GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
351   int i,ip_address,value;
352   char buf[20];
353
354   TRACE("\n");
355   ip_address=(DWORD) lParam;
356
357   for (i=3; i>=0; i--) {
358     value=ip_address & 0xff;
359     if ((value>=infoPtr->LowerLimit[i]) && (value<=infoPtr->UpperLimit[i])) 
360     {
361       sprintf (buf,"%d",value);
362       SetWindowTextA (lpipsi->hwndIP[i],buf);
363       IPADDRESS_SendNotify (hwnd, EN_CHANGE);
364     }
365     ip_address/=256;
366   }
367
368   hdc = GetDC (hwnd);           /* & send notifications */
369   IPADDRESS_Refresh (hwnd, hdc);
370   ReleaseDC (hwnd, hdc);
371
372   return TRUE;
373 }
374
375
376 static LRESULT
377 IPADDRESS_SetFocusToField (HWND hwnd, WPARAM wParam, LPARAM lParam)
378 {
379   /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
380   LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetPropA ((HWND)hwnd,
381                                                    IP_SUBCLASS_PROP);
382   INT index;
383
384   index=(INT) wParam;
385   TRACE(" %d\n", index);
386   if ((index<0) || (index>3)) return 0;
387         
388   SetFocus (lpipsi->hwndIP[index]);
389         
390   return 1;
391 }
392
393
394 static LRESULT
395 IPADDRESS_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
396 {
397   TRACE("\n");
398
399   SetFocus (hwnd);
400   IPADDRESS_SendNotify (hwnd, EN_SETFOCUS);
401   IPADDRESS_SetFocusToField (hwnd, 0, 0);
402
403   return TRUE;
404 }
405
406
407 static INT
408 IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi, int currentfield)
409 {
410   int newField,fieldvalue;
411   char field[20];
412   IPADDRESS_INFO *infoPtr=lpipsi->infoPtr;
413
414   if(currentfield >= 0 && currentfield < 4)
415   {
416     TRACE("\n");
417     GetWindowTextA (lpipsi->hwndIP[currentfield],field,4);
418     if (field[0])
419     {
420       field[3]=0;       
421       newField=-1;
422       fieldvalue=atoi(field);
423     
424       if (fieldvalue < infoPtr->LowerLimit[currentfield]) 
425         newField=infoPtr->LowerLimit[currentfield];
426     
427       if (fieldvalue > infoPtr->UpperLimit[currentfield])
428         newField=infoPtr->UpperLimit[currentfield];
429     
430       if (newField >= 0)
431       {
432         sprintf (field,"%d",newField);
433         SetWindowTextA (lpipsi->hwndIP[currentfield], field);
434         return TRUE;
435       }
436     }
437   }
438   return FALSE;
439 }
440
441
442 static INT
443 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi, int currentfield)
444 {
445   if(currentfield >= -1 && currentfield < 4)
446   {
447     IPADDRESS_CheckField(lpipsi, currentfield); /* check the fields value */  
448
449     if(currentfield < 3)
450     { 
451       SetFocus (lpipsi->hwndIP[currentfield+1]);
452       return TRUE; 
453     }
454   }
455   return FALSE;
456 }
457
458
459 /* period: move and select the text in the next field to the right if */
460 /*         the current field is not empty(l!=0), we are not in the */
461 /*         left most position, and nothing is selected(startsel==endsel) */
462
463 /* spacebar: same behavior as period */
464
465 /* alpha characters: completely ignored */
466
467 /* digits: accepted when field text length < 2 ignored otherwise. */
468 /*         when 3 numbers have been entered into the field the value */
469 /*         of the field is checked, if the field value exceeds the */
470 /*         maximum value and is changed the field remains the current */
471 /*         field, otherwise focus moves to the field to the right */
472
473 /* tab: change focus from the current ipaddress control to the next */
474 /*      control in the tab order */
475
476 /* right arrow: move to the field on the right to the left most */
477 /*              position in that field if no text is selected, */
478 /*              we are in the right most position in the field, */
479 /*              we are not in the right most field */
480
481 /* left arrow: move to the field on the left to the right most */
482 /*             position in that field if no text is selected, */
483 /*             we are in the left most position in the current field */
484 /*             and we are not in the left most field */
485
486 /* backspace: delete the character to the left of the cursor position, */
487 /*            if none are present move to the field on the left if */
488 /*            we are not in the left most field and delete the right */
489 /*            most digit in that field while keeping the cursor */
490 /*            on the right side of the field */
491
492
493 LRESULT CALLBACK
494 IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
495 {
496   IPADDRESS_INFO *infoPtr;
497   LPIP_SUBCLASS_INFO lpipsi = (LPIP_SUBCLASS_INFO) GetPropA
498         ((HWND)hwnd,IP_SUBCLASS_PROP); 
499   CHAR c = (CHAR)wParam;
500   INT i, l, index, startsel, endsel;
501
502   infoPtr = lpipsi->infoPtr;
503   index=0;             /* FIXME */
504   for (i=0; i<=3; i++) 
505     if (lpipsi->hwndIP[i]==hwnd) index=i;
506
507   switch (uMsg) {
508   case WM_CHAR: 
509     if(isdigit(c)) /* process all digits */
510     {
511       int return_val;
512       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); 
513       l = GetWindowTextLengthA (lpipsi->hwndIP[index]);
514       if(l==2 && startsel==endsel) /* field is full after this key is processed */
515       { 
516         /* process the digit press before we check the field */
517         return_val = CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam);
518           
519         /* if the field value was changed stay at the current field */
520         if(!IPADDRESS_CheckField(lpipsi, index))
521           IPADDRESS_GotoNextField (lpipsi,index);
522
523         return return_val;
524       }
525       
526       if(l > 2) /* field is full, stop key messages */
527       {
528         lParam = 0;
529         wParam = 0;
530       }
531       break;
532     }   
533     
534     if(c == '.') /* VK_PERIOD */
535     { 
536       l = GetWindowTextLengthA(lpipsi->hwndIP[index]);
537       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
538       if(l != 0 && startsel==endsel && startsel != 0)
539       {
540         IPADDRESS_GotoNextField(lpipsi, index); 
541         SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0, (LPARAM)3);
542       }
543     }
544         
545     /* stop all other characters */
546     wParam = 0;
547     lParam = 0;
548     break;
549
550   case WM_KEYDOWN:
551     if(c == VK_SPACE)
552     { 
553       l = GetWindowTextLengthA(lpipsi->hwndIP[index]);
554       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
555       if(l != 0 && startsel==endsel && startsel != 0)
556       {
557         IPADDRESS_GotoNextField(lpipsi, index); 
558         SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0, (LPARAM)3);
559       }
560     }
561
562     if(c == VK_RIGHT)
563     {
564       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
565       l = GetWindowTextLengthA (lpipsi->hwndIP[index]);
566     
567       if(startsel==endsel && startsel==l)
568       {
569         IPADDRESS_GotoNextField(lpipsi, index);
570         SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0,(LPARAM)0);
571       }
572     }
573
574     if(c == VK_LEFT)
575     { 
576       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel);
577       if(startsel==0 && startsel==endsel && index > 0)
578       {        
579         IPADDRESS_GotoNextField(lpipsi, index - 2);
580         l = GetWindowTextLengthA(lpipsi->hwndIP[index-1]);
581         SendMessageA(lpipsi->hwndIP[index-1], EM_SETSEL, (WPARAM)l,(LPARAM)l);
582       }     
583     }
584    
585     if(c == VK_BACK) /* VK_BACKSPACE */
586     {
587       CHAR buf[4];
588
589       SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); 
590       l = GetWindowTextLengthA (lpipsi->hwndIP[index]);
591       if(startsel==endsel && startsel==0 && index > 0)
592       {
593         l = GetWindowTextLengthA(lpipsi->hwndIP[index-1]);
594         if(l!=0)
595         {
596           GetWindowTextA (lpipsi->hwndIP[index-1],buf,4);
597           buf[l-1] = '\0'; 
598           SetWindowTextA(lpipsi->hwndIP[index-1], buf);
599           SendMessageA(lpipsi->hwndIP[index-1], EM_SETSEL, (WPARAM)l,(LPARAM)l);
600         } 
601         IPADDRESS_GotoNextField(lpipsi, index - 2);
602       }
603     }
604     break;
605
606   default:
607     break;
608   }
609   return CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam);
610 }
611
612
613 static LRESULT WINAPI
614 IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
615 {
616   TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
617   if (!IPADDRESS_GetInfoPtr (hwnd) && (uMsg != WM_CREATE))
618       return DefWindowProcA (hwnd, uMsg, wParam, lParam);
619   switch (uMsg)
620   {
621     case IPM_CLEARADDRESS:
622       return IPADDRESS_ClearAddress (hwnd, wParam, lParam);
623
624     case IPM_SETADDRESS:
625       return IPADDRESS_SetAddress (hwnd, wParam, lParam);
626
627     case IPM_GETADDRESS:
628       return IPADDRESS_GetAddress (hwnd, wParam, lParam);
629
630     case IPM_SETRANGE:
631       return IPADDRESS_SetRange (hwnd, wParam, lParam);
632
633     case IPM_SETFOCUS:
634       return IPADDRESS_SetFocusToField (hwnd, wParam, lParam);
635
636     case IPM_ISBLANK:
637       return IPADDRESS_IsBlank (hwnd, wParam, lParam);
638
639     case WM_CREATE:
640       return IPADDRESS_Create (hwnd, wParam, lParam);
641
642     case WM_DESTROY:
643       return IPADDRESS_Destroy (hwnd, wParam, lParam);
644
645     case WM_GETDLGCODE:
646       return DLGC_WANTARROWS | DLGC_WANTCHARS;
647
648     case WM_KILLFOCUS:
649       return IPADDRESS_KillFocus (hwnd, wParam, lParam);
650
651     case WM_LBUTTONDOWN:
652       return IPADDRESS_LButtonDown (hwnd, wParam, lParam);
653
654     case WM_PAINT:
655       return IPADDRESS_Paint (hwnd, wParam);
656
657     case WM_SETFOCUS:
658       return IPADDRESS_SetFocus (hwnd, wParam, lParam);
659
660     case WM_SIZE:
661       return IPADDRESS_Size (hwnd, wParam, lParam);
662
663     default:
664       if (uMsg >= WM_USER)
665         ERR("unknown msg %04x wp=%08x lp=%08lx\n",
666                      uMsg, wParam, lParam);
667       return DefWindowProcA (hwnd, uMsg, wParam, lParam);
668     }
669     return 0;
670 }
671
672
673 void IPADDRESS_Register (void)
674 {
675   WNDCLASSA wndClass;
676
677   ZeroMemory (&wndClass, sizeof(WNDCLASSA));
678   wndClass.style         = CS_GLOBALCLASS;
679   wndClass.lpfnWndProc   = (WNDPROC)IPADDRESS_WindowProc;
680   wndClass.cbClsExtra    = 0;
681   wndClass.cbWndExtra    = sizeof(IPADDRESS_INFO *);
682   wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
683   wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
684   wndClass.lpszClassName = WC_IPADDRESSA;
685  
686   RegisterClassA (&wndClass);
687 }
688
689
690 VOID IPADDRESS_Unregister (void)
691 {
692   UnregisterClassA (WC_IPADDRESSA, (HINSTANCE)NULL);
693 }