Release 960324
[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 "user.h"
12 #include "win.h"
13 #include "dce.h"
14 #include "atom.h"
15 #include "ldt.h"
16 #include "toolhelp.h"
17 #include "stddebug.h"
18 /* #define DEBUG_CLASS */
19 #include "debug.h"
20
21
22 static HCLASS firstClass = 0;
23
24
25 /***********************************************************************
26  *           CLASS_DumpClass
27  *
28  * Dump the content of a class structure to stderr.
29  */
30 void CLASS_DumpClass( HCLASS hClass )
31 {
32     CLASS *ptr;
33     char className[80];
34     int i;
35
36     if (!(ptr = CLASS_FindClassPtr( hClass )))
37     {
38         fprintf( stderr, "%04x is not a class handle\n", hClass );
39         return;
40     }
41     GlobalGetAtomName( ptr->atomName, className, sizeof(className) );
42
43     fprintf( stderr, "Class %04x:\n", hClass );
44     fprintf( stderr,
45              "next=%04x  name=%04x '%s'  style=%04x  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->hNext, ptr->atomName, className, ptr->wc.style,
49              (DWORD)ptr->wc.lpfnWndProc, ptr->wc.hInstance, ptr->hdce,
50              ptr->wc.hIcon, ptr->wc.hCursor, ptr->wc.hbrBackground,
51              ptr->wc.cbClsExtra, ptr->wc.cbWndExtra, ptr->cWindows );
52     if (ptr->wc.cbClsExtra)
53     {
54         fprintf( stderr, "extra bytes:" );
55         for (i = 0; i < ptr->wc.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     HCLASS hClass = firstClass;
71     CLASS *ptr;
72     char className[80];
73
74     fprintf( stderr, "Class  Name                Style WndProc\n" );
75     while (hClass)
76     {
77         if (!(ptr = CLASS_FindClassPtr( hClass )))
78         {
79             fprintf( stderr, "*** Bad class %04x in list\n", hClass );
80             return;
81         }
82         GlobalGetAtomName( ptr->atomName, className, sizeof(className) );
83         fprintf( stderr, "%04x  %-20.20s %04x %08lx\n",
84                  hClass, className, ptr->wc.style, (DWORD)ptr->wc.lpfnWndProc);
85         hClass = ptr->hNext;
86     }
87     fprintf( stderr, "\n" );
88 }
89
90
91 /***********************************************************************
92  *           CLASS_FindClassByName
93  *
94  * Return a handle and a pointer to the class.
95  * 'ptr' can be NULL if the pointer is not needed.
96  */
97 HCLASS CLASS_FindClassByName( SEGPTR name, HINSTANCE hinstance, CLASS **ptr )
98 {
99     ATOM atom;
100     HCLASS class;
101     CLASS * classPtr;
102
103     if (!(atom = GlobalFindAtom( name ))) return 0;
104
105       /* First search task-specific classes */
106
107     for (class = firstClass; (class); class = classPtr->hNext)
108     {
109         classPtr = (CLASS *) USER_HEAP_LIN_ADDR(class);
110         if (classPtr->wc.style & CS_GLOBALCLASS) continue;
111         if ((classPtr->atomName == atom) && 
112             ( (hinstance==(HINSTANCE)0xffff) ||
113               (hinstance == classPtr->wc.hInstance) ) )
114         {
115             if (ptr) *ptr = classPtr;
116             return class;
117         }
118     }
119     
120       /* Then search global classes */
121
122     for (class = firstClass; (class); class = classPtr->hNext)
123     {
124         classPtr = (CLASS *) USER_HEAP_LIN_ADDR(class);
125         if (!(classPtr->wc.style & CS_GLOBALCLASS)) continue;
126         if (classPtr->atomName == atom)
127         {
128             if (ptr) *ptr = classPtr;
129             return class;
130         }
131     }
132
133     return 0;
134 }
135
136
137 /***********************************************************************
138  *           CLASS_FindClassPtr
139  *
140  * Return a pointer to the CLASS structure corresponding to a HCLASS.
141  */
142 CLASS * CLASS_FindClassPtr( HCLASS hclass )
143 {
144     CLASS * ptr;
145     
146     if (!hclass) return NULL;
147     ptr = (CLASS *) USER_HEAP_LIN_ADDR( hclass );
148     if (ptr->wMagic != CLASS_MAGIC) return NULL;
149     return ptr;
150 }
151
152
153 /***********************************************************************
154  *           RegisterClass    (USER.57)
155  */
156 ATOM RegisterClass( LPWNDCLASS class )
157 {
158     CLASS * newClass, * prevClassPtr;
159     HCLASS handle, prevClass;
160     int classExtra;
161
162     dprintf_class( stddeb, "RegisterClass: wndproc=%08lx hinst=%04x name='%s' background %04x\n",
163                  (DWORD)class->lpfnWndProc, class->hInstance,
164                  HIWORD(class->lpszClassName) ?
165                   (char *)PTR_SEG_TO_LIN(class->lpszClassName) : "(int)",
166                  class->hbrBackground );
167     dprintf_class(stddeb,"               style=%04x clsExtra=%d winExtra=%d\n",
168                   class->style, class->cbClsExtra, class->cbWndExtra );
169     
170       /* Window classes are owned by modules, not instances */
171     class->hInstance = GetExePtr( class->hInstance );
172     
173       /* Check if a class with this name already exists */
174     prevClass = CLASS_FindClassByName( class->lpszClassName,
175                                        class->hInstance, &prevClassPtr );
176     if (prevClass)
177     {
178           /* Class can be created only if it is local and */
179           /* if the class with the same name is global.   */
180
181         if (class->style & CS_GLOBALCLASS) return 0;
182         if (!(prevClassPtr->wc.style & CS_GLOBALCLASS)) return 0;
183     }
184
185       /* Create class */
186
187     classExtra = (class->cbClsExtra < 0) ? 0 : class->cbClsExtra;
188     handle = USER_HEAP_ALLOC( sizeof(CLASS) + classExtra );
189     if (!handle) return 0;
190     newClass = (CLASS *) USER_HEAP_LIN_ADDR( handle );
191     newClass->hNext         = firstClass;
192     newClass->wMagic        = CLASS_MAGIC;
193     newClass->cWindows      = 0;  
194     newClass->wc            = *class;
195     newClass->wc.cbWndExtra = (class->cbWndExtra < 0) ? 0 : class->cbWndExtra;
196     newClass->wc.cbClsExtra = classExtra;
197
198     newClass->atomName = GlobalAddAtom( class->lpszClassName );
199     newClass->wc.lpszClassName = 0;
200
201     if (newClass->wc.style & CS_CLASSDC)
202         newClass->hdce = DCE_AllocDCE( DCE_CLASS_DC );
203     else newClass->hdce = 0;
204
205       /* Make a copy of the menu name (only if it is a string) */
206
207     if (HIWORD(class->lpszMenuName))
208     {
209         char *menuname = PTR_SEG_TO_LIN( class->lpszMenuName );
210         HANDLE hname = USER_HEAP_ALLOC( strlen(menuname)+1 );
211         if (hname)
212         {
213             newClass->wc.lpszMenuName = (SEGPTR)USER_HEAP_SEG_ADDR( hname );
214             strcpy( USER_HEAP_LIN_ADDR( hname ), menuname );
215         }
216     }
217
218     if (classExtra) memset( newClass->wExtra, 0, classExtra );
219     firstClass = handle;
220     return newClass->atomName;
221 }
222
223
224 /***********************************************************************
225  *           UnregisterClass    (USER.403)
226  */
227 BOOL UnregisterClass( SEGPTR className, HANDLE hinstance )
228 {
229     HANDLE class, prevClass;
230     CLASS * classPtr, * prevClassPtr;
231     
232     hinstance = GetExePtr( hinstance );
233       /* Check if we can remove this class */
234     class = CLASS_FindClassByName( className, hinstance, &classPtr );
235     if (!class) return FALSE;
236     if ((classPtr->wc.hInstance != hinstance) || (classPtr->cWindows > 0))
237         return FALSE;
238     
239       /* Remove the class from the linked list */
240     if (firstClass == class) firstClass = classPtr->hNext;
241     else
242     {
243         for (prevClass = firstClass; prevClass; prevClass=prevClassPtr->hNext)
244         {
245             prevClassPtr = (CLASS *) USER_HEAP_LIN_ADDR(prevClass);
246             if (prevClassPtr->hNext == class) break;
247         }
248         if (!prevClass)
249         {
250             fprintf(stderr, "ERROR: Class list corrupted\n" );
251             return FALSE;
252         }
253         prevClassPtr->hNext = classPtr->hNext;
254     }
255
256       /* Delete the class */
257     if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce );
258     if (classPtr->wc.hbrBackground) DeleteObject( classPtr->wc.hbrBackground );
259     GlobalDeleteAtom( classPtr->atomName );
260     if (HIWORD(classPtr->wc.lpszMenuName))
261         USER_HEAP_FREE( (HANDLE)classPtr->wc.lpszMenuName );
262     USER_HEAP_FREE( class );
263     return TRUE;
264 }
265
266
267 /***********************************************************************
268  *           GetClassWord    (USER.129)
269  */
270 WORD GetClassWord( HWND hwnd, short offset )
271 {
272     return (WORD)GetClassLong( hwnd, offset );
273 }
274
275
276 /***********************************************************************
277  *           SetClassWord    (USER.130)
278  */
279 WORD SetClassWord( HWND hwnd, short offset, WORD newval )
280 {
281     CLASS * classPtr;
282     WND * wndPtr;
283     WORD *ptr, retval = 0;
284     
285     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
286     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
287     ptr = (WORD *)(((char *)classPtr->wExtra) + offset);
288     retval = *ptr;
289     *ptr = newval;
290     return retval;
291 }
292
293
294 /***********************************************************************
295  *           GetClassLong    (USER.131)
296  */
297 LONG GetClassLong( HWND hwnd, short offset )
298 {
299     CLASS * classPtr;
300     WND * wndPtr;
301     
302     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
303     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
304     return *(LONG *)(((char *)classPtr->wExtra) + offset);
305 }
306
307
308 /***********************************************************************
309  *           SetClassLong    (USER.132)
310  */
311 LONG SetClassLong( HWND hwnd, short offset, LONG newval )
312 {
313     CLASS * classPtr;
314     WND * wndPtr;
315     LONG *ptr, retval = 0;
316     
317     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
318     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
319     ptr = (LONG *)(((char *)classPtr->wExtra) + offset);
320     retval = *ptr;
321     *ptr = newval;
322     return retval;
323 }
324
325
326 /***********************************************************************
327  *           GetClassName      (USER.58)
328  */
329 int GetClassName(HWND hwnd, LPSTR lpClassName, short maxCount)
330 {
331     WND *wndPtr;
332     CLASS *classPtr;
333
334     /* FIXME: We have the find the correct hInstance */
335     dprintf_class(stddeb,"GetClassName(%04x,%p,%d)\n",hwnd,lpClassName,maxCount);
336     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
337     if (!(classPtr = CLASS_FindClassPtr(wndPtr->hClass))) return 0;
338     
339     return GlobalGetAtomName(classPtr->atomName, lpClassName, maxCount);
340 }
341
342
343 /***********************************************************************
344  *           GetClassInfo      (USER.404)
345  */
346 BOOL GetClassInfo( HANDLE hInstance, SEGPTR name, LPWNDCLASS lpWndClass )
347 {
348     CLASS *classPtr;
349
350     dprintf_class( stddeb, "GetClassInfo: hInstance=%04x className=%s\n",
351                    hInstance,
352                    HIWORD(name) ? (char *)PTR_SEG_TO_LIN(name) : "(int)" );
353
354     hInstance = GetExePtr( hInstance );
355     
356     if (!(CLASS_FindClassByName( name, hInstance, &classPtr))) return FALSE;
357     if (hInstance && (hInstance != classPtr->wc.hInstance)) return FALSE;
358
359     memcpy(lpWndClass, &(classPtr->wc), sizeof(WNDCLASS));
360     return TRUE;
361 }
362
363
364 /***********************************************************************
365  *           ClassFirst      (TOOLHELP.69)
366  */
367 BOOL ClassFirst( CLASSENTRY *pClassEntry )
368 {
369     pClassEntry->wNext = firstClass;
370     return ClassNext( pClassEntry );
371 }
372
373
374 /***********************************************************************
375  *           ClassNext      (TOOLHELP.70)
376  */
377 BOOL ClassNext( CLASSENTRY *pClassEntry )
378 {
379     CLASS *classPtr = (CLASS *) USER_HEAP_LIN_ADDR( pClassEntry->wNext );
380     if (!classPtr) return FALSE;
381
382     pClassEntry->hInst = classPtr->wc.hInstance;
383     pClassEntry->wNext = classPtr->hNext;
384     GlobalGetAtomName( classPtr->atomName, pClassEntry->szClassName,
385                        sizeof(pClassEntry->szClassName) );
386     return TRUE;
387 }