Release 941107
[wine] / windows / class.c
1 /*
2  * Window classes functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "class.h"
13 #include "user.h"
14 #include "win.h"
15 #include "dce.h"
16 #include "stddebug.h"
17 /* #define DEBUG_CLASS */
18 /* #undef  DEBUG_CLASS */
19 #include "debug.h"
20
21
22 static HCLASS firstClass = 0;
23
24
25 /***********************************************************************
26  *           CLASS_FindClassByName
27  *
28  * Return a handle and a pointer to the class.
29  * 'ptr' can be NULL if the pointer is not needed.
30  */
31 HCLASS CLASS_FindClassByName( char * name, WORD hinstance, CLASS **ptr )
32 {
33     ATOM atom;
34     HCLASS class;
35     CLASS * classPtr;
36
37       /* First search task-specific classes */
38
39     if ((atom = /*FindAtom*/GlobalFindAtom( name )) != 0)
40     {
41         for (class = firstClass; (class); class = classPtr->hNext)
42         {
43             classPtr = (CLASS *) USER_HEAP_ADDR(class);
44             if (classPtr->wc.style & CS_GLOBALCLASS) continue;
45             if ((classPtr->atomName == atom) && 
46                 (( hinstance==0xffff )|| (hinstance == classPtr->wc.hInstance)))
47             {
48                 if (ptr) *ptr = classPtr;
49                 return class;
50             }
51         }
52     }
53     
54       /* Then search global classes */
55
56     if ((atom = GlobalFindAtom( name )) != 0)
57     {
58         for (class = firstClass; (class); class = classPtr->hNext)
59         {
60             classPtr = (CLASS *) USER_HEAP_ADDR(class);
61             if (!(classPtr->wc.style & CS_GLOBALCLASS)) continue;
62             if (classPtr->atomName == atom)
63             {
64                 if (ptr) *ptr = classPtr;
65                 return class;
66             }
67         }
68     }
69
70     return 0;
71 }
72
73
74 /***********************************************************************
75  *           CLASS_FindClassPtr
76  *
77  * Return a pointer to the CLASS structure corresponding to a HCLASS.
78  */
79 CLASS * CLASS_FindClassPtr( HCLASS hclass )
80 {
81     CLASS * ptr;
82     
83     if (!hclass) return NULL;
84     ptr = (CLASS *) USER_HEAP_ADDR( hclass );
85     if (ptr->wMagic != CLASS_MAGIC) return NULL;
86     return ptr;
87 }
88
89
90 /***********************************************************************
91  *           RegisterClass    (USER.57)
92  */
93 ATOM RegisterClass( LPWNDCLASS class )
94 {
95     CLASS * newClass, * prevClassPtr;
96     HCLASS handle, prevClass;
97     int classExtra;
98
99     dprintf_class(stddeb, "RegisterClass: wndproc=%p hinst=%d name='%s' background %x\n", 
100             class->lpfnWndProc, class->hInstance, class->lpszClassName,
101             class->hbrBackground );
102
103       /* Check if a class with this name already exists */
104
105     prevClass = CLASS_FindClassByName( class->lpszClassName, class->hInstance,
106         &prevClassPtr );
107     if (prevClass)
108     {
109           /* Class can be created only if it is local and */
110           /* if the class with the same name is global.   */
111
112         if (class->style & CS_GLOBALCLASS) return 0;
113         if (!(prevClassPtr->wc.style & CS_GLOBALCLASS)) return 0;
114     }
115
116       /* Create class */
117
118     classExtra = (class->cbClsExtra < 0) ? 0 : class->cbClsExtra;
119     handle = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(CLASS) + classExtra );
120     if (!handle) return 0;
121     newClass = (CLASS *) USER_HEAP_ADDR( handle );
122     newClass->hNext         = firstClass;
123     newClass->wMagic        = CLASS_MAGIC;
124     newClass->cWindows      = 0;  
125     newClass->wc            = *class;
126     newClass->wc.cbWndExtra = (class->cbWndExtra < 0) ? 0 : class->cbWndExtra;
127     newClass->wc.cbClsExtra = classExtra;
128
129     /*if (newClass->wc.style & CS_GLOBALCLASS)*/
130         newClass->atomName = GlobalAddAtom( class->lpszClassName );
131     /*else newClass->atomName = AddAtom( class->lpszClassName );*/
132     newClass->wc.lpszClassName = NULL; 
133
134     if (newClass->wc.style & CS_CLASSDC)
135         newClass->hdce = DCE_AllocDCE( DCE_CLASS_DC );
136     else newClass->hdce = 0;
137
138       /* Make a copy of the menu name (only if it is a string) */
139
140     if ((int)class->lpszMenuName & 0xffff0000)
141     {
142         HANDLE hname;
143         hname = USER_HEAP_ALLOC( GMEM_MOVEABLE, strlen(class->lpszMenuName)+1);
144         if (hname)
145         {
146             newClass->wc.lpszMenuName = (char *)USER_HEAP_ADDR( hname );
147             strcpy( newClass->wc.lpszMenuName, class->lpszMenuName );
148         }
149     }
150
151     if (classExtra) memset( newClass->wExtra, 0, classExtra );
152     firstClass = handle;
153     return newClass->atomName;
154 }
155
156
157 /***********************************************************************
158  *           UnregisterClass    (USER.403)
159  */
160 BOOL UnregisterClass( LPSTR className, HANDLE instance )
161 {
162     HANDLE class, prevClass;
163     CLASS * classPtr, * prevClassPtr;
164     
165       /* Check if we can remove this class */
166     class = CLASS_FindClassByName( className, instance, &classPtr );
167     if (!class) return FALSE;
168     if ((classPtr->wc.hInstance != instance) || (classPtr->cWindows > 0))
169         return FALSE;
170     
171       /* Remove the class from the linked list */
172     if (firstClass == class) firstClass = classPtr->hNext;
173     else
174     {
175         for (prevClass = firstClass; prevClass; prevClass=prevClassPtr->hNext)
176         {
177             prevClassPtr = (CLASS *) USER_HEAP_ADDR(prevClass);
178             if (prevClassPtr->hNext == class) break;
179         }
180         if (!prevClass)
181         {
182             fprintf(stderr, "ERROR: Class list corrupted\n" );
183             return FALSE;
184         }
185         prevClassPtr->hNext = classPtr->hNext;
186     }
187
188       /* Delete the class */
189     if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce );
190     if (classPtr->wc.hbrBackground) DeleteObject( classPtr->wc.hbrBackground );
191     /*if (classPtr->wc.style & CS_GLOBALCLASS)*/ GlobalDeleteAtom( classPtr->atomName );
192     /*else DeleteAtom( classPtr->atomName );*/
193     if ((int)classPtr->wc.lpszMenuName & 0xffff0000)
194         USER_HEAP_FREE( (int)classPtr->wc.lpszMenuName & 0xffff );
195     USER_HEAP_FREE( class );
196     return TRUE;
197 }
198
199
200 /***********************************************************************
201  *           GetClassWord    (USER.129)
202  */
203 WORD GetClassWord( HWND hwnd, short offset )
204 {
205     return (WORD)GetClassLong( hwnd, offset );
206 }
207
208
209 /***********************************************************************
210  *           SetClassWord    (USER.130)
211  */
212 WORD SetClassWord( HWND hwnd, short offset, WORD newval )
213 {
214     CLASS * classPtr;
215     WND * wndPtr;
216     WORD *ptr, retval = 0;
217     
218     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
219     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
220     ptr = (WORD *)(((char *)classPtr->wExtra) + offset);
221     retval = *ptr;
222     *ptr = newval;
223     return retval;
224 }
225
226
227 /***********************************************************************
228  *           GetClassLong    (USER.131)
229  */
230 LONG GetClassLong( HWND hwnd, short offset )
231 {
232     CLASS * classPtr;
233     WND * wndPtr;
234     
235     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
236     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
237     return *(LONG *)(((char *)classPtr->wExtra) + offset);
238 }
239
240
241 /***********************************************************************
242  *           SetClassLong    (USER.132)
243  */
244 LONG SetClassLong( HWND hwnd, short offset, LONG newval )
245 {
246     CLASS * classPtr;
247     WND * wndPtr;
248     LONG *ptr, retval = 0;
249     
250     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
251     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
252     ptr = (LONG *)(((char *)classPtr->wExtra) + offset);
253     retval = *ptr;
254     *ptr = newval;
255     return retval;
256 }
257
258
259 /***********************************************************************
260  *           GetClassName      (USER.58)
261  */
262 int GetClassName(HWND hwnd, LPSTR lpClassName, short maxCount)
263 {
264     WND *wndPtr;
265     CLASS *classPtr;
266
267     /* FIXME: We have the find the correct hInstance */
268     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
269     if (!(classPtr = CLASS_FindClassPtr(wndPtr->hClass))) return 0;
270
271     return (GetAtomName(classPtr->atomName, lpClassName, maxCount));
272 }
273
274
275 /***********************************************************************
276  *           GetClassInfo      (USER.404)
277  */
278 BOOL GetClassInfo(HANDLE hInstance, LPSTR lpClassName, 
279                                     LPWNDCLASS lpWndClass)
280 {
281     CLASS *classPtr;
282
283     if (HIWORD(lpClassName))
284     {
285         dprintf_class(stddeb, "GetClassInfo   hInstance=%04x  lpClassName=%s\n",
286             hInstance, lpClassName);
287     }
288     else
289        dprintf_class(stddeb, "GetClassInfo   hInstance=%04x  lpClassName=#%d\n",
290             hInstance, (int)lpClassName);    
291
292
293     /* if (!(CLASS_FindClassByName(lpClassName, &classPtr))) return FALSE; */
294     if (!(CLASS_FindClassByName(lpClassName, hInstance, &classPtr)))
295     {
296         if (!HIWORD(lpClassName))
297         {
298             char temp[10];
299             sprintf(temp, "#%d", (int)lpClassName);
300             if (!(CLASS_FindClassByName(temp, hInstance, &classPtr))) return FALSE;        
301     
302         }
303         else return FALSE;
304     }
305
306     if (hInstance && (hInstance != classPtr->wc.hInstance)) return FALSE;
307
308     memcpy(lpWndClass, &(classPtr->wc), sizeof(WNDCLASS));
309     return TRUE;
310 }