Release 960314
[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="NPFMT" name='%s' background "NPFMT"\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 #ifdef WINELIB32
262         USER_HEAP_FREE( (HANDLE)classPtr->wc.lpszMenuName );
263 #else
264         USER_HEAP_FREE( LOWORD(classPtr->wc.lpszMenuName) );
265 #endif
266     USER_HEAP_FREE( class );
267     return TRUE;
268 }
269
270
271 /***********************************************************************
272  *           GetClassWord    (USER.129)
273  */
274 WORD GetClassWord( HWND hwnd, short offset )
275 {
276     return (WORD)GetClassLong( hwnd, offset );
277 }
278
279
280 /***********************************************************************
281  *           SetClassWord    (USER.130)
282  */
283 WORD SetClassWord( HWND hwnd, short offset, WORD newval )
284 {
285     CLASS * classPtr;
286     WND * wndPtr;
287     WORD *ptr, retval = 0;
288     
289     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
290     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
291     ptr = (WORD *)(((char *)classPtr->wExtra) + offset);
292     retval = *ptr;
293     *ptr = newval;
294     return retval;
295 }
296
297
298 /***********************************************************************
299  *           GetClassLong    (USER.131)
300  */
301 LONG GetClassLong( HWND hwnd, short offset )
302 {
303     CLASS * classPtr;
304     WND * wndPtr;
305     
306     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
307     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
308     return *(LONG *)(((char *)classPtr->wExtra) + offset);
309 }
310
311
312 /***********************************************************************
313  *           SetClassLong    (USER.132)
314  */
315 LONG SetClassLong( HWND hwnd, short offset, LONG newval )
316 {
317     CLASS * classPtr;
318     WND * wndPtr;
319     LONG *ptr, retval = 0;
320     
321     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
322     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
323     ptr = (LONG *)(((char *)classPtr->wExtra) + offset);
324     retval = *ptr;
325     *ptr = newval;
326     return retval;
327 }
328
329
330 /***********************************************************************
331  *           GetClassName      (USER.58)
332  */
333 int GetClassName(HWND hwnd, LPSTR lpClassName, short maxCount)
334 {
335     WND *wndPtr;
336     CLASS *classPtr;
337
338     /* FIXME: We have the find the correct hInstance */
339     dprintf_class(stddeb,"GetClassName("NPFMT",%p,%d)\n",hwnd,lpClassName,maxCount);
340     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
341     if (!(classPtr = CLASS_FindClassPtr(wndPtr->hClass))) return 0;
342     
343     return GlobalGetAtomName(classPtr->atomName, lpClassName, maxCount);
344 }
345
346
347 /***********************************************************************
348  *           GetClassInfo      (USER.404)
349  */
350 BOOL GetClassInfo( HANDLE hInstance, SEGPTR name, LPWNDCLASS lpWndClass )
351 {
352     CLASS *classPtr;
353
354     dprintf_class( stddeb, "GetClassInfo: hInstance="NPFMT" className=%s\n",
355                    hInstance,
356                    HIWORD(name) ? (char *)PTR_SEG_TO_LIN(name) : "(int)" );
357
358     hInstance = GetExePtr( hInstance );
359     
360     if (!(CLASS_FindClassByName( name, hInstance, &classPtr))) return FALSE;
361     if (hInstance && (hInstance != classPtr->wc.hInstance)) return FALSE;
362
363     memcpy(lpWndClass, &(classPtr->wc), sizeof(WNDCLASS));
364     return TRUE;
365 }
366
367
368 /***********************************************************************
369  *           ClassFirst      (TOOLHELP.69)
370  */
371 BOOL ClassFirst( CLASSENTRY *pClassEntry )
372 {
373     pClassEntry->wNext = firstClass;
374     return ClassNext( pClassEntry );
375 }
376
377
378 /***********************************************************************
379  *           ClassNext      (TOOLHELP.70)
380  */
381 BOOL ClassNext( CLASSENTRY *pClassEntry )
382 {
383     CLASS *classPtr = (CLASS *) USER_HEAP_LIN_ADDR( pClassEntry->wNext );
384     if (!classPtr) return FALSE;
385
386     pClassEntry->hInst = classPtr->wc.hInstance;
387     pClassEntry->wNext = classPtr->hNext;
388     GlobalGetAtomName( classPtr->atomName, pClassEntry->szClassName,
389                        sizeof(pClassEntry->szClassName) );
390     return TRUE;
391 }