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