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