Release 960506
[wine] / windows / class.c
1 /*
2  * Window classes functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include "class.h"
11 #include "heap.h"
12 #include "user.h"
13 #include "win.h"
14 #include "dce.h"
15 #include "atom.h"
16 #include "ldt.h"
17 #include "toolhelp.h"
18 #include "stddebug.h"
19 #include "debug.h"
20
21
22 static CLASS *firstClass = NULL;
23
24
25 /***********************************************************************
26  *           CLASS_DumpClass
27  *
28  * Dump the content of a class structure to stderr.
29  */
30 void CLASS_DumpClass( CLASS *ptr )
31 {
32     char className[80];
33     int i;
34
35     if (ptr->magic != CLASS_MAGIC)
36     {
37         fprintf( stderr, "%p is not a class\n", ptr );
38         return;
39     }
40
41     GlobalGetAtomName( ptr->atomName, className, sizeof(className) );
42
43     fprintf( stderr, "Class %p:\n", ptr );
44     fprintf( stderr,
45              "next=%p  name=%04x '%s'  style=%08x  wndProc=%08lx\n"
46              "inst=%04x  hdce=%04x  icon=%04x  cursor=%04x  bkgnd=%04x\n"
47              "clsExtra=%d  winExtra=%d  #windows=%d\n",
48              ptr->next, ptr->atomName, className, ptr->style,
49              (DWORD)ptr->lpfnWndProc, ptr->hInstance, ptr->hdce,
50              ptr->hIcon, ptr->hCursor, ptr->hbrBackground,
51              ptr->cbClsExtra, ptr->cbWndExtra, ptr->cWindows );
52     if (ptr->cbClsExtra)
53     {
54         fprintf( stderr, "extra bytes:" );
55         for (i = 0; i < ptr->cbClsExtra; i++)
56             fprintf( stderr, " %02x", *((BYTE *)ptr->wExtra+i) );
57         fprintf( stderr, "\n" );
58     }
59     fprintf( stderr, "\n" );
60 }
61
62
63 /***********************************************************************
64  *           CLASS_WalkClasses
65  *
66  * Walk the class list and print each class on stderr.
67  */
68 void CLASS_WalkClasses(void)
69 {
70     CLASS *ptr;
71     char className[80];
72
73     fprintf( stderr, " Class   Name                 Style   WndProc\n" );
74     for (ptr = firstClass; ptr; ptr = ptr->next)
75     {
76         GlobalGetAtomName( ptr->atomName, className, sizeof(className) );
77         fprintf( stderr, "%08lx %-20.20s %08x %08lx\n", (DWORD)ptr, className,
78                  ptr->style, (DWORD)ptr->lpfnWndProc );
79     }
80     fprintf( stderr, "\n" );
81 }
82
83
84 /***********************************************************************
85  *           CLASS_FreeClass
86  *
87  * Free a class structure.
88  */
89 static void CLASS_FreeClass( CLASS *classPtr )
90 {
91     CLASS **ppClass;
92
93     /* Remove the class from the linked list */
94
95     for (ppClass = &firstClass; *ppClass; ppClass = &(*ppClass)->next)
96         if (*ppClass == classPtr) break;
97     if (!*ppClass)
98     {
99         fprintf(stderr, "ERROR: Class list corrupted\n" );
100         return;
101     }
102     *ppClass = classPtr->next;
103
104     /* Delete the class */
105
106     if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce );
107     if (classPtr->hbrBackground) DeleteObject( classPtr->hbrBackground );
108     GlobalDeleteAtom( classPtr->atomName );
109     if (HIWORD(classPtr->lpszMenuName))
110         USER_HEAP_FREE( (HANDLE)classPtr->lpszMenuName );
111     HeapFree( SystemHeap, 0, classPtr );
112 }
113
114
115 /***********************************************************************
116  *           CLASS_FreeModuleClasses
117  */
118 void CLASS_FreeModuleClasses( HMODULE hModule )
119 {
120     CLASS *ptr, *next;
121   
122     for (ptr = firstClass; ptr; ptr = next)
123     {
124         next = ptr->next;
125         if (ptr->hInstance == hModule) CLASS_FreeClass( ptr );
126     }
127 }
128
129
130 /***********************************************************************
131  *           CLASS_FindClassByAtom
132  *
133  * Return a pointer to the class.
134  */
135 CLASS *CLASS_FindClassByAtom( ATOM atom, HINSTANCE16 hinstance )
136 {
137     CLASS * class;
138
139       /* First search task-specific classes */
140
141     for (class = firstClass; (class); class = class->next)
142     {
143         if (class->style & CS_GLOBALCLASS) continue;
144         if ((class->atomName == atom) && 
145             ((hinstance==(HINSTANCE16)0xffff) ||
146              (hinstance == class->hInstance))) return class;
147     }
148     
149       /* Then search global classes */
150
151     for (class = firstClass; (class); class = class->next)
152     {
153         if (!(class->style & CS_GLOBALCLASS)) continue;
154         if (class->atomName == atom) return class;
155     }
156
157     return 0;
158 }
159
160
161 /***********************************************************************
162  *           CLASS_FindClassByName
163  *
164  * Return a pointer to the class.
165  */
166 CLASS *CLASS_FindClassByName( SEGPTR name, HINSTANCE hinstance )
167 {
168     ATOM atom;
169
170     if (!(atom = GlobalFindAtom( name ))) return 0;
171     return CLASS_FindClassByAtom( atom, hinstance );
172 }
173
174
175 /***********************************************************************
176  *           RegisterClass16    (USER.57)
177  */
178 ATOM RegisterClass16( const WNDCLASS16 *wc )
179 {
180     CLASS * newClass, * prevClass;
181     HANDLE16 hInstance;
182     int classExtra;
183
184     dprintf_class( stddeb, "RegisterClass: wndproc=%08lx hinst=%04x name='%s' background %04x\n",
185                  (DWORD)wc->lpfnWndProc, wc->hInstance,
186                  HIWORD(wc->lpszClassName) ?
187                   (char *)PTR_SEG_TO_LIN(wc->lpszClassName) : "(int)",
188                  wc->hbrBackground );
189     dprintf_class(stddeb,"               style=%04x clsExtra=%d winExtra=%d\n",
190                   wc->style, wc->cbClsExtra, wc->cbWndExtra );
191     
192       /* Window classes are owned by modules, not instances */
193     hInstance = GetExePtr( wc->hInstance );
194     
195       /* Check if a class with this name already exists */
196     prevClass = CLASS_FindClassByName( wc->lpszClassName, hInstance );
197     if (prevClass)
198     {
199           /* Class can be created only if it is local and */
200           /* if the class with the same name is global.   */
201
202         if (wc->style & CS_GLOBALCLASS) return 0;
203         if (!(prevClass->style & CS_GLOBALCLASS)) return 0;
204     }
205
206       /* Create class */
207
208     classExtra = (wc->cbClsExtra < 0) ? 0 : wc->cbClsExtra;
209     newClass = (CLASS *)HeapAlloc( SystemHeap, 0, sizeof(CLASS) + classExtra );
210     if (!newClass) return 0;
211     newClass->next          = firstClass;
212     newClass->magic         = CLASS_MAGIC;
213     newClass->cWindows      = 0;  
214     newClass->style         = wc->style;
215     newClass->lpfnWndProc   = wc->lpfnWndProc;
216     newClass->cbWndExtra    = (wc->cbWndExtra < 0) ? 0 : wc->cbWndExtra;
217     newClass->cbClsExtra    = classExtra;
218     newClass->lpszMenuName  = wc->lpszMenuName;
219     newClass->hInstance     = hInstance;
220     newClass->hIcon         = wc->hIcon;
221     newClass->hCursor       = wc->hCursor;
222     newClass->hbrBackground = wc->hbrBackground;
223
224     newClass->atomName = GlobalAddAtom( wc->lpszClassName );
225
226     if (newClass->style & CS_CLASSDC)
227         newClass->hdce = DCE_AllocDCE( DCE_CLASS_DC );
228     else newClass->hdce = 0;
229
230       /* Make a copy of the menu name (only if it is a string) */
231
232     if (HIWORD(wc->lpszMenuName))
233     {
234         char *menuname = PTR_SEG_TO_LIN( wc->lpszMenuName );
235         HANDLE hname = USER_HEAP_ALLOC( strlen(menuname)+1 );
236         if (hname)
237         {
238             newClass->lpszMenuName = (SEGPTR)USER_HEAP_SEG_ADDR( hname );
239             strcpy( USER_HEAP_LIN_ADDR( hname ), menuname );
240         }
241     }
242
243     if (classExtra) memset( newClass->wExtra, 0, classExtra );
244     firstClass = newClass;
245     return newClass->atomName;
246 }
247
248
249 /***********************************************************************
250  *           RegisterClass32A      (USER32.426)
251  */
252 ATOM RegisterClass32A( const WNDCLASS32A* wc )
253 {
254     WNDCLASS16 copy;
255     HANDLE classh = 0, menuh = 0;
256     SEGPTR classsegp, menusegp;
257     char *classbuf, *menubuf;
258
259     ATOM retval;
260     copy.style=wc->style;
261     ALIAS_RegisterAlias(0,0,(DWORD)wc->lpfnWndProc);
262     copy.lpfnWndProc=wc->lpfnWndProc;
263     copy.cbClsExtra=wc->cbClsExtra;
264     copy.cbWndExtra=wc->cbWndExtra;
265     copy.hInstance=(HINSTANCE)wc->hInstance;
266     copy.hIcon=(HICON)wc->hIcon;
267     copy.hCursor=(HCURSOR)wc->hCursor;
268     copy.hbrBackground=(HBRUSH)wc->hbrBackground;
269     
270     /* FIXME: There has to be a better way of doing this - but neither
271        malloc nor alloca will work */
272
273     if(wc->lpszMenuName)
274     {
275         menuh = GlobalAlloc16(0, strlen(wc->lpszMenuName)+1);
276         menusegp = WIN16_GlobalLock16(menuh);
277         menubuf = PTR_SEG_TO_LIN(menusegp);
278         strcpy( menubuf, wc->lpszMenuName);
279         copy.lpszMenuName=menusegp;
280     }else
281         copy.lpszMenuName=0;
282     if(wc->lpszClassName)
283     {
284         classh = GlobalAlloc16(0, strlen(wc->lpszClassName)+1);
285         classsegp = WIN16_GlobalLock16(classh);
286         classbuf = PTR_SEG_TO_LIN(classsegp);
287         strcpy( classbuf, wc->lpszClassName);
288         copy.lpszClassName=classsegp;
289     }
290     retval = RegisterClass16(&copy);
291     GlobalFree16(menuh);
292     GlobalFree16(classh);
293     return retval;
294 }
295
296
297 /***********************************************************************
298  *           UnregisterClass16    (USER.403)
299  */
300 BOOL UnregisterClass16( SEGPTR className, HINSTANCE16 hinstance )
301 {
302     CLASS *classPtr;
303
304     hinstance = GetExePtr( hinstance );
305
306       /* Check if we can remove this class */
307     if (!(classPtr = CLASS_FindClassByName( className, hinstance )))
308         return FALSE;
309     if ((classPtr->hInstance != hinstance) || (classPtr->cWindows > 0))
310         return FALSE;
311     CLASS_FreeClass( classPtr );
312     return TRUE;
313 }
314
315
316 /***********************************************************************
317  *           GetClassWord    (USER.129)
318  */
319 WORD GetClassWord( HWND hwnd, short offset )
320 {
321     WND * wndPtr;
322     
323     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
324     if (offset >= 0)
325         return *(WORD *)(((char *)wndPtr->class->wExtra) + offset);
326     switch(offset)
327     {
328         case GCW_HBRBACKGROUND: return wndPtr->class->hbrBackground;
329         case GCW_HCURSOR:       return wndPtr->class->hCursor;
330         case GCW_HICON:         return wndPtr->class->hIcon;
331         case GCW_HMODULE:       return wndPtr->class->hInstance;
332         case GCW_ATOM:          return wndPtr->class->atomName;
333         case GCW_STYLE:
334         case GCW_CBWNDEXTRA:
335         case GCW_CBCLSEXTRA:
336             return (WORD)GetClassLong( hwnd, offset );
337     }
338     fprintf(stderr, "Warning: invalid offset %d for GetClassWord()\n", offset);
339     return 0;
340 }
341
342
343 /***********************************************************************
344  *           SetClassWord    (USER.130)
345  */
346 WORD SetClassWord( HWND hwnd, short offset, WORD newval )
347 {
348     WND * wndPtr;
349     WORD *ptr, retval = 0;
350     
351     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
352     if (offset >= 0) ptr = (WORD *)(((char *)wndPtr->class->wExtra) + offset);
353     else switch(offset)
354     {
355         case GCW_HBRBACKGROUND: ptr = &wndPtr->class->hbrBackground; break;
356         case GCW_HCURSOR:       ptr = &wndPtr->class->hCursor; break;
357         case GCW_HICON:         ptr = &wndPtr->class->hIcon; break;
358         case GCW_HMODULE:       ptr = &wndPtr->class->hInstance; break;
359         case GCW_ATOM:          ptr = &wndPtr->class->atomName; break;
360         case GCW_STYLE:
361         case GCW_CBWNDEXTRA:
362         case GCW_CBCLSEXTRA:
363             return (WORD)SetClassLong( hwnd, offset, (LONG)newval );
364         default:
365             fprintf( stderr, "Warning: invalid offset %d for SetClassWord()\n",
366                      offset);
367             return 0;
368     }
369     retval = *ptr;
370     *ptr = newval;
371     return retval;
372 }
373
374
375 /***********************************************************************
376  *           GetClassLong    (USER.131)
377  */
378 LONG GetClassLong( HWND hwnd, short offset )
379 {
380     WND * wndPtr;
381     
382     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
383     if (offset >= 0)
384         return *(WORD *)(((char *)wndPtr->class->wExtra) + offset);
385     switch(offset)
386     {
387         case GCL_STYLE:      return (LONG)wndPtr->class->style;
388         case GCL_CBWNDEXTRA: return (LONG)wndPtr->class->cbWndExtra;
389         case GCL_CBCLSEXTRA: return (LONG)wndPtr->class->cbClsExtra;
390         case GCL_MENUNAME:   return (LONG)wndPtr->class->lpszMenuName;
391         case GCL_WNDPROC:    return (LONG)wndPtr->class->lpfnWndProc;
392     }
393     fprintf(stderr, "Warning: invalid offset %d for GetClassLong()\n", offset);
394     return 0;
395 }
396
397
398 /***********************************************************************
399  *           SetClassLong    (USER.132)
400  */
401 LONG SetClassLong( HWND hwnd, short offset, LONG newval )
402 {
403     WND * wndPtr;
404     LONG *ptr, retval = 0;
405     
406     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
407     if (offset >= 0) ptr = (LONG *)(((char *)wndPtr->class->wExtra) + offset);
408     else switch(offset)
409     {
410         case GCL_STYLE:      ptr = (LONG*)&wndPtr->class->style; break;
411         case GCL_CBWNDEXTRA: ptr = (LONG*)&wndPtr->class->cbWndExtra; break;
412         case GCL_CBCLSEXTRA: ptr = (LONG*)&wndPtr->class->cbClsExtra; break;
413         case GCL_MENUNAME:   ptr = (LONG*)&wndPtr->class->lpszMenuName; break;
414         case GCL_WNDPROC:    ptr = (LONG*)&wndPtr->class->lpfnWndProc; break;
415         default:
416             fprintf( stderr, "Warning: invalid offset %d for SetClassLong()\n",
417                      offset);
418             return 0;
419     }
420     retval = *ptr;
421     *ptr = newval;
422     return retval;
423 }
424
425
426 /***********************************************************************
427  *           GetClassName      (USER.58)
428  */
429 int GetClassName(HWND hwnd, LPSTR lpClassName, short maxCount)
430 {
431     WND *wndPtr;
432
433     /* FIXME: We have the find the correct hInstance */
434     dprintf_class(stddeb,"GetClassName(%04x,%p,%d)\n",hwnd,lpClassName,maxCount);
435     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
436     
437     return GlobalGetAtomName( wndPtr->class->atomName, lpClassName, maxCount );
438 }
439
440
441 /***********************************************************************
442  *           GetClassInfo      (USER.404)
443  */
444 BOOL GetClassInfo( HANDLE hInstance, SEGPTR name, WNDCLASS16 *lpWndClass )
445 {
446     CLASS *classPtr;
447
448     dprintf_class( stddeb, "GetClassInfo: hInstance=%04x className=%s\n",
449                    hInstance,
450                    HIWORD(name) ? (char *)PTR_SEG_TO_LIN(name) : "(int)" );
451
452     hInstance = GetExePtr( hInstance );
453     
454     if (!(classPtr = CLASS_FindClassByName( name, hInstance ))) return FALSE;
455     if (hInstance && (hInstance != classPtr->hInstance)) return FALSE;
456
457     lpWndClass->style         = (UINT16)classPtr->style;
458     lpWndClass->lpfnWndProc   = classPtr->lpfnWndProc;
459     lpWndClass->cbClsExtra    = (INT16)classPtr->cbClsExtra;
460     lpWndClass->cbWndExtra    = (INT16)classPtr->cbWndExtra;
461     lpWndClass->hInstance     = classPtr->hInstance;
462     lpWndClass->hIcon         = classPtr->hIcon;
463     lpWndClass->hCursor       = classPtr->hCursor;
464     lpWndClass->hbrBackground = classPtr->hbrBackground;
465     lpWndClass->lpszMenuName  = classPtr->lpszMenuName;
466     lpWndClass->lpszClassName = 0;
467
468     return TRUE;
469 }
470
471
472 /***********************************************************************
473  *           ClassFirst      (TOOLHELP.69)
474  */
475 BOOL ClassFirst( CLASSENTRY *pClassEntry )
476 {
477     pClassEntry->wNext = 1;
478     return ClassNext( pClassEntry );
479 }
480
481
482 /***********************************************************************
483  *           ClassNext      (TOOLHELP.70)
484  */
485 BOOL ClassNext( CLASSENTRY *pClassEntry )
486 {
487     int i;
488     CLASS *class = firstClass;
489
490     if (!pClassEntry->wNext) return FALSE;
491     for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
492     if (!class)
493     {
494         pClassEntry->wNext = 0;
495         return FALSE;
496     }
497     pClassEntry->hInst = class->hInstance;
498     pClassEntry->wNext++;
499     GlobalGetAtomName( class->atomName, pClassEntry->szClassName,
500                        sizeof(pClassEntry->szClassName) );
501     return TRUE;
502 }