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