The TEB doesn't need execute permissions.
[wine] / dlls / user / class.c
1 /*
2  * Window classes functions
3  *
4  * Copyright 1993, 1996, 2003 Alexandre Julliard
5  * Copyright 1998 Juergen Schmied (jsch)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "wine/winuser16.h"
35 #include "wine/unicode.h"
36 #include "win.h"
37 #include "user_private.h"
38 #include "controls.h"
39 #include "winproc.h"
40 #include "wine/server.h"
41 #include "wine/list.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(class);
45
46 typedef struct tagCLASS
47 {
48     struct list      entry;         /* Entry in class list */
49     UINT             style;         /* Class style */
50     BOOL             local;         /* Local class? */
51     WNDPROC          winprocA;      /* Window procedure (ASCII) */
52     WNDPROC          winprocW;      /* Window procedure (Unicode) */
53     INT              cbClsExtra;    /* Class extra bytes */
54     INT              cbWndExtra;    /* Window extra bytes */
55     LPWSTR           menuName;      /* Default menu name (Unicode followed by ASCII) */
56     SEGPTR           segMenuName;   /* Default menu name as SEGPTR */
57     HINSTANCE        hInstance;     /* Module that created the task */
58     HICON            hIcon;         /* Default icon */
59     HICON            hIconSm;       /* Default small icon */
60     HCURSOR          hCursor;       /* Default cursor */
61     HBRUSH           hbrBackground; /* Default background */
62     ATOM             atomName;      /* Name of the class */
63 } CLASS;
64
65 static struct list class_list = LIST_INIT( class_list );
66
67 #define CLASS_OTHER_PROCESS ((CLASS *)1)
68
69 /***********************************************************************
70  *           get_class_ptr
71  */
72 static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
73 {
74     WND *ptr = WIN_GetPtr( hwnd );
75
76     if (ptr)
77     {
78         if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class;
79
80         if (write_access && (ptr == WND_DESKTOP || IsWindow( hwnd ))) /* check other processes */
81         {
82             /* modifying classes in other processes is not allowed */
83             SetLastError( ERROR_ACCESS_DENIED );
84             return NULL;
85         }
86         return CLASS_OTHER_PROCESS;
87     }
88     SetLastError( ERROR_INVALID_WINDOW_HANDLE );
89     return NULL;
90 }
91
92
93 /***********************************************************************
94  *           release_class_ptr
95  */
96 inline static void release_class_ptr( CLASS *ptr )
97 {
98     USER_Unlock();
99 }
100
101
102 /***********************************************************************
103  *           set_server_info
104  *
105  * Set class info with the wine server.
106  */
107 static BOOL set_server_info( HWND hwnd, INT offset, LONG newval )
108 {
109     BOOL ret;
110
111     SERVER_START_REQ( set_class_info )
112     {
113         req->window = hwnd;
114         req->extra_offset = -1;
115         switch(offset)
116         {
117         case GCW_ATOM:
118             req->flags = SET_CLASS_ATOM;
119             req->atom = newval;
120         case GCL_STYLE:
121             req->flags = SET_CLASS_STYLE;
122             req->style = newval;
123             break;
124         case GCL_CBWNDEXTRA:
125             req->flags = SET_CLASS_WINEXTRA;
126             req->win_extra = newval;
127             break;
128         case GCLP_HMODULE:
129             req->flags = SET_CLASS_INSTANCE;
130             req->instance = (void *)newval;
131             break;
132         default:
133             assert( offset >= 0 );
134             req->flags = SET_CLASS_EXTRA;
135             req->extra_offset = offset;
136             req->extra_size = sizeof(newval);
137             memcpy( &req->extra_value, &newval, sizeof(newval) );
138             break;
139         }
140         ret = !wine_server_call_err( req );
141     }
142     SERVER_END_REQ;
143     return ret;
144 }
145
146
147 /***********************************************************************
148  *           CLASS_GetProc
149  *
150  * Get the class winproc for a given proc type
151  */
152 static WNDPROC16 CLASS_GetProc( CLASS *classPtr, WINDOWPROCTYPE type )
153 {
154     WNDPROC proc = classPtr->winprocA;
155
156     if (classPtr->winprocW)
157     {
158         /* if we have a Unicode proc, use it if we have no ASCII proc
159          * or if we have both and Unicode was requested
160          */
161         if (!proc || type == WIN_PROC_32W) proc = classPtr->winprocW;
162     }
163     return WINPROC_GetProc( proc, type );
164 }
165
166
167 /***********************************************************************
168  *           CLASS_SetProc
169  *
170  * Set the class winproc for a given proc type.
171  * Returns the previous window proc.
172  */
173 static WNDPROC16 CLASS_SetProc( CLASS *classPtr, WNDPROC newproc, WINDOWPROCTYPE type )
174 {
175     WNDPROC *proc = &classPtr->winprocA;
176     WNDPROC16 ret;
177
178     if (classPtr->winprocW)
179     {
180         /* if we have a Unicode proc, use it if we have no ASCII proc
181          * or if we have both and Unicode was requested
182          */
183         if (!*proc || type == WIN_PROC_32W) proc = &classPtr->winprocW;
184     }
185     ret = WINPROC_GetProc( *proc, type );
186     *proc = WINPROC_AllocProc( newproc, type );
187     /* now clear the one that we didn't set */
188     if (classPtr->winprocA && classPtr->winprocW)
189     {
190         if (proc == &classPtr->winprocA)
191             classPtr->winprocW = 0;
192         else
193             classPtr->winprocA = 0;
194     }
195     return ret;
196 }
197
198
199 /***********************************************************************
200  *           CLASS_GetMenuNameA
201  *
202  * Get the menu name as a ASCII string.
203  */
204 inline static LPSTR CLASS_GetMenuNameA( CLASS *classPtr )
205 {
206     if (!HIWORD(classPtr->menuName)) return (LPSTR)classPtr->menuName;
207     return (LPSTR)(classPtr->menuName + strlenW(classPtr->menuName) + 1);
208 }
209
210
211 /***********************************************************************
212  *           CLASS_GetMenuName16
213  *
214  * Get the menu name as a SEGPTR.
215  */
216 inline static SEGPTR CLASS_GetMenuName16( CLASS *classPtr )
217 {
218     if (!HIWORD(classPtr->menuName)) return (SEGPTR)classPtr->menuName;
219     if (!classPtr->segMenuName)
220         classPtr->segMenuName = MapLS( CLASS_GetMenuNameA(classPtr) );
221     return classPtr->segMenuName;
222 }
223
224
225 /***********************************************************************
226  *           CLASS_GetMenuNameW
227  *
228  * Get the menu name as a Unicode string.
229  */
230 inline static LPWSTR CLASS_GetMenuNameW( CLASS *classPtr )
231 {
232     return classPtr->menuName;
233 }
234
235
236 /***********************************************************************
237  *           CLASS_SetMenuNameA
238  *
239  * Set the menu name in a class structure by copying the string.
240  */
241 static void CLASS_SetMenuNameA( CLASS *classPtr, LPCSTR name )
242 {
243     UnMapLS( classPtr->segMenuName );
244     classPtr->segMenuName = 0;
245     if (HIWORD(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
246     if (HIWORD(name))
247     {
248         DWORD lenA = strlen(name) + 1;
249         DWORD lenW = MultiByteToWideChar( CP_ACP, 0, name, lenA, NULL, 0 );
250         classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
251         MultiByteToWideChar( CP_ACP, 0, name, lenA, classPtr->menuName, lenW );
252         memcpy( classPtr->menuName + lenW, name, lenA );
253     }
254     else classPtr->menuName = (LPWSTR)name;
255 }
256
257
258 /***********************************************************************
259  *           CLASS_SetMenuNameW
260  *
261  * Set the menu name in a class structure by copying the string.
262  */
263 static void CLASS_SetMenuNameW( CLASS *classPtr, LPCWSTR name )
264 {
265     UnMapLS( classPtr->segMenuName );
266     classPtr->segMenuName = 0;
267     if (HIWORD(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
268     if (HIWORD(name))
269     {
270         DWORD lenW = strlenW(name) + 1;
271         DWORD lenA = WideCharToMultiByte( CP_ACP, 0, name, lenW, NULL, 0, NULL, NULL );
272         classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
273         memcpy( classPtr->menuName, name, lenW*sizeof(WCHAR) );
274         WideCharToMultiByte( CP_ACP, 0, name, lenW,
275                              (char *)(classPtr->menuName + lenW), lenA, NULL, NULL );
276     }
277     else classPtr->menuName = (LPWSTR)name;
278 }
279
280
281 /***********************************************************************
282  *           CLASS_FreeClass
283  *
284  * Free a class structure.
285  */
286 static void CLASS_FreeClass( CLASS *classPtr )
287 {
288     TRACE("%p\n", classPtr);
289
290     USER_Lock();
291
292     list_remove( &classPtr->entry );
293     if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
294         DeleteObject( classPtr->hbrBackground );
295     UnMapLS( classPtr->segMenuName );
296     HeapFree( GetProcessHeap(), 0, classPtr->menuName );
297     HeapFree( GetProcessHeap(), 0, classPtr );
298     USER_Unlock();
299 }
300
301
302 /***********************************************************************
303  *           CLASS_FreeModuleClasses
304  */
305 void CLASS_FreeModuleClasses( HMODULE16 hModule )
306 {
307     struct list *ptr, *next;
308
309     TRACE("0x%08x\n", hModule);
310
311     USER_Lock();
312     for (ptr = list_head( &class_list ); ptr; ptr = next)
313     {
314         CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
315         next = list_next( &class_list, ptr );
316         if (class->hInstance == HINSTANCE_32(hModule))
317         {
318             BOOL ret;
319
320             SERVER_START_REQ( destroy_class )
321             {
322                 req->atom = class->atomName;
323                 req->instance = class->hInstance;
324                 ret = !wine_server_call_err( req );
325             }
326             SERVER_END_REQ;
327             if (ret) CLASS_FreeClass( class );
328         }
329     }
330     USER_Unlock();
331 }
332
333
334 /***********************************************************************
335  *           CLASS_FindClassByAtom
336  *
337  * Return a pointer to the class.
338  * hinstance has been normalized by the caller.
339  */
340 static CLASS *CLASS_FindClassByAtom( ATOM atom, HINSTANCE hinstance )
341 {
342     struct list *ptr;
343
344     USER_Lock();
345
346     LIST_FOR_EACH( ptr, &class_list )
347     {
348         CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
349         if (class->atomName != atom) continue;
350         if (!hinstance || !class->local || class->hInstance == hinstance)
351         {
352             TRACE("0x%04x %p -> %p\n", atom, hinstance, class);
353             return class;
354         }
355     }
356     USER_Unlock();
357     TRACE("0x%04x %p -> not found\n", atom, hinstance);
358     return NULL;
359 }
360
361
362 /***********************************************************************
363  *           CLASS_RegisterClass
364  *
365  * The real RegisterClass() functionality.
366  * The atom is deleted no matter what.
367  */
368 static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance, BOOL local,
369                                    DWORD style, INT classExtra, INT winExtra )
370 {
371     CLASS *classPtr;
372     BOOL ret;
373
374     TRACE("atom=0x%x hinst=%p style=0x%lx clExtr=0x%x winExtr=0x%x\n",
375           atom, hInstance, style, classExtra, winExtra );
376
377     /* Fix the extra bytes value */
378
379     if (classExtra < 0 || winExtra < 0)
380     {
381          SetLastError( ERROR_INVALID_PARAMETER );
382          return NULL;
383     }
384     if (classExtra > 40)  /* Extra bytes are limited to 40 in Win32 */
385         WARN("Class extra bytes %d is > 40\n", classExtra);
386     if (winExtra > 40)    /* Extra bytes are limited to 40 in Win32 */
387         WARN("Win extra bytes %d is > 40\n", winExtra );
388
389     classPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS) + classExtra );
390     if (!classPtr)
391     {
392         GlobalDeleteAtom( atom );
393         return NULL;
394     }
395
396     SERVER_START_REQ( create_class )
397     {
398         req->local      = local;
399         req->atom       = atom;
400         req->style      = style;
401         req->instance   = hInstance;
402         req->extra      = classExtra;
403         req->win_extra  = winExtra;
404         req->client_ptr = classPtr;
405         ret = !wine_server_call_err( req );
406     }
407     SERVER_END_REQ;
408     GlobalDeleteAtom( atom );  /* the server increased the atom ref count */
409     if (!ret)
410     {
411         HeapFree( GetProcessHeap(), 0, classPtr );
412         return NULL;
413     }
414
415     classPtr->style       = style;
416     classPtr->local       = local;
417     classPtr->cbWndExtra  = winExtra;
418     classPtr->cbClsExtra  = classExtra;
419     classPtr->hInstance   = hInstance;
420     classPtr->atomName    = atom;
421
422     /* Other non-null values must be set by caller */
423
424     USER_Lock();
425     if (local) list_add_head( &class_list, &classPtr->entry );
426     else list_add_tail( &class_list, &classPtr->entry );
427     return classPtr;
428 }
429
430
431 /***********************************************************************
432  *           register_builtin
433  *
434  * Register a builtin control class.
435  * This allows having both ASCII and Unicode winprocs for the same class.
436  */
437 static CLASS *register_builtin( const struct builtin_class_descr *descr )
438 {
439     ATOM atom;
440     CLASS *classPtr;
441
442     if (!(atom = GlobalAddAtomA( descr->name ))) return 0;
443
444     if (!(classPtr = CLASS_RegisterClass( atom, user32_module, FALSE,
445                                           descr->style, 0, descr->extra ))) return 0;
446
447     classPtr->hCursor       = LoadCursorA( 0, (LPSTR)descr->cursor );
448     classPtr->hbrBackground = descr->brush;
449
450     if (descr->procA) classPtr->winprocA = WINPROC_AllocProc( descr->procA, WIN_PROC_32A );
451     if (descr->procW) classPtr->winprocW = WINPROC_AllocProc( descr->procW, WIN_PROC_32W );
452     release_class_ptr( classPtr );
453     return classPtr;
454 }
455
456
457 /***********************************************************************
458  *           CLASS_RegisterBuiltinClasses
459  */
460 void CLASS_RegisterBuiltinClasses(void)
461 {
462     extern const struct builtin_class_descr BUTTON_builtin_class;
463     extern const struct builtin_class_descr COMBO_builtin_class;
464     extern const struct builtin_class_descr COMBOLBOX_builtin_class;
465     extern const struct builtin_class_descr DIALOG_builtin_class;
466     extern const struct builtin_class_descr DESKTOP_builtin_class;
467     extern const struct builtin_class_descr EDIT_builtin_class;
468     extern const struct builtin_class_descr ICONTITLE_builtin_class;
469     extern const struct builtin_class_descr LISTBOX_builtin_class;
470     extern const struct builtin_class_descr MDICLIENT_builtin_class;
471     extern const struct builtin_class_descr MENU_builtin_class;
472     extern const struct builtin_class_descr SCROLL_builtin_class;
473     extern const struct builtin_class_descr STATIC_builtin_class;
474
475     register_builtin( &DESKTOP_builtin_class );
476     register_builtin( &BUTTON_builtin_class );
477     register_builtin( &COMBO_builtin_class );
478     register_builtin( &COMBOLBOX_builtin_class );
479     register_builtin( &DIALOG_builtin_class );
480     register_builtin( &EDIT_builtin_class );
481     register_builtin( &ICONTITLE_builtin_class );
482     register_builtin( &LISTBOX_builtin_class );
483     register_builtin( &MDICLIENT_builtin_class );
484     register_builtin( &MENU_builtin_class );
485     register_builtin( &SCROLL_builtin_class );
486     register_builtin( &STATIC_builtin_class );
487 }
488
489
490 /***********************************************************************
491  *           CLASS_AddWindow
492  *
493  * Add a new window using this class, and set the necessary
494  * information inside the window structure.
495  */
496 void CLASS_AddWindow( CLASS *class, WND *win, WINDOWPROCTYPE type )
497 {
498     if (type == WIN_PROC_32W)
499     {
500         if (!(win->winproc = class->winprocW)) win->winproc = class->winprocA;
501     }
502     else
503     {
504         if (!(win->winproc = class->winprocA)) win->winproc = class->winprocW;
505     }
506     win->class    = class;
507     win->clsStyle = class->style;
508 }
509
510
511 /***********************************************************************
512  *              RegisterClassA (USER32.@)
513  * RETURNS
514  *      >0: Unique identifier
515  *      0: Failure
516  */
517 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
518 {
519     WNDCLASSEXA wcex;
520
521     wcex.cbSize        = sizeof(wcex);
522     wcex.style         = wc->style;
523     wcex.lpfnWndProc   = wc->lpfnWndProc;
524     wcex.cbClsExtra    = wc->cbClsExtra;
525     wcex.cbWndExtra    = wc->cbWndExtra;
526     wcex.hInstance     = wc->hInstance;
527     wcex.hIcon         = wc->hIcon;
528     wcex.hCursor       = wc->hCursor;
529     wcex.hbrBackground = wc->hbrBackground;
530     wcex.lpszMenuName  = wc->lpszMenuName;
531     wcex.lpszClassName = wc->lpszClassName;
532     wcex.hIconSm       = 0;
533     return RegisterClassExA( &wcex );
534 }
535
536
537 /***********************************************************************
538  *              RegisterClassW (USER32.@)
539  */
540 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
541 {
542     WNDCLASSEXW wcex;
543
544     wcex.cbSize        = sizeof(wcex);
545     wcex.style         = wc->style;
546     wcex.lpfnWndProc   = wc->lpfnWndProc;
547     wcex.cbClsExtra    = wc->cbClsExtra;
548     wcex.cbWndExtra    = wc->cbWndExtra;
549     wcex.hInstance     = wc->hInstance;
550     wcex.hIcon         = wc->hIcon;
551     wcex.hCursor       = wc->hCursor;
552     wcex.hbrBackground = wc->hbrBackground;
553     wcex.lpszMenuName  = wc->lpszMenuName;
554     wcex.lpszClassName = wc->lpszClassName;
555     wcex.hIconSm       = 0;
556     return RegisterClassExW( &wcex );
557 }
558
559
560 /***********************************************************************
561  *              RegisterClassExA (USER32.@)
562  */
563 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
564 {
565     ATOM atom;
566     CLASS *classPtr;
567     HINSTANCE instance;
568
569     if (wc->hInstance == user32_module)
570     {
571         /* we can't register a class for user32 */
572         SetLastError( ERROR_INVALID_PARAMETER );
573         return 0;
574     }
575     if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
576
577     if (!(atom = GlobalAddAtomA( wc->lpszClassName ))) return 0;
578
579     if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
580                                           wc->style, wc->cbClsExtra, wc->cbWndExtra )))
581         return 0;
582
583     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
584           atom, wc->lpfnWndProc, instance, wc->hbrBackground,
585           wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
586
587     classPtr->hIcon         = wc->hIcon;
588     classPtr->hIconSm       = wc->hIconSm;
589     classPtr->hCursor       = wc->hCursor;
590     classPtr->hbrBackground = wc->hbrBackground;
591     classPtr->winprocA      = WINPROC_AllocProc( wc->lpfnWndProc, WIN_PROC_32A );
592     CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
593     release_class_ptr( classPtr );
594     return atom;
595 }
596
597
598 /***********************************************************************
599  *              RegisterClassExW (USER32.@)
600  */
601 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
602 {
603     ATOM atom;
604     CLASS *classPtr;
605     HINSTANCE instance;
606
607     if (wc->hInstance == user32_module)
608     {
609         /* we can't register a class for user32 */
610         SetLastError( ERROR_INVALID_PARAMETER );
611         return 0;
612     }
613     if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
614
615     if (!(atom = GlobalAddAtomW( wc->lpszClassName ))) return 0;
616
617     if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
618                                           wc->style, wc->cbClsExtra, wc->cbWndExtra )))
619         return 0;
620
621     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
622           atom, wc->lpfnWndProc, instance, wc->hbrBackground,
623           wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
624
625     classPtr->hIcon         = wc->hIcon;
626     classPtr->hIconSm       = wc->hIconSm;
627     classPtr->hCursor       = wc->hCursor;
628     classPtr->hbrBackground = wc->hbrBackground;
629     classPtr->winprocW      = WINPROC_AllocProc( wc->lpfnWndProc, WIN_PROC_32W );
630     CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
631     release_class_ptr( classPtr );
632     return atom;
633 }
634
635
636 /***********************************************************************
637  *              UnregisterClassA (USER32.@)
638  */
639 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
640 {
641     ATOM atom = HIWORD(className) ? GlobalFindAtomA( className ) : LOWORD(className);
642     return UnregisterClassW( MAKEINTATOMW(atom), hInstance );
643 }
644
645 /***********************************************************************
646  *              UnregisterClassW (USER32.@)
647  */
648 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
649 {
650     CLASS *classPtr = NULL;
651     ATOM atom = HIWORD(className) ? GlobalFindAtomW( className ) : LOWORD(className);
652
653     TRACE("%s %p %x\n",debugstr_w(className), hInstance, atom);
654
655     if (!atom)
656     {
657         SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
658         return FALSE;
659     }
660
661     SERVER_START_REQ( destroy_class )
662     {
663         req->atom = atom;
664         req->instance = hInstance;
665         if (!wine_server_call_err( req )) classPtr = reply->client_ptr;
666     }
667     SERVER_END_REQ;
668
669     if (classPtr) CLASS_FreeClass( classPtr );
670     return (classPtr != NULL);
671 }
672
673
674 /***********************************************************************
675  *              GetClassWord (USER32.@)
676  */
677 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
678 {
679     CLASS *class;
680     WORD retvalue = 0;
681
682     if (offset < 0) return GetClassLongA( hwnd, offset );
683
684     TRACE("%p %x\n",hwnd, offset);
685
686     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
687
688     if (class == CLASS_OTHER_PROCESS)
689     {
690         SERVER_START_REQ( set_class_info )
691         {
692             req->window = hwnd;
693             req->flags = 0;
694             req->extra_offset = offset;
695             req->extra_size = sizeof(retvalue);
696             if (!wine_server_call_err( req ))
697                 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
698         }
699         SERVER_END_REQ;
700         return retvalue;
701     }
702
703     if (offset <= class->cbClsExtra - sizeof(WORD))
704         memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
705     else
706         SetLastError( ERROR_INVALID_INDEX );
707     release_class_ptr( class );
708     return retvalue;
709 }
710
711
712 /***********************************************************************
713  *              GetClassLong (USER.131)
714  */
715 LONG WINAPI GetClassLong16( HWND16 hwnd16, INT16 offset )
716 {
717     CLASS *class;
718     LONG ret;
719     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;  /* no need for full handle */
720
721     TRACE("%p %d\n",hwnd, offset);
722
723     switch( offset )
724     {
725     case GCLP_WNDPROC:
726         if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
727         if (class == CLASS_OTHER_PROCESS) break;
728         ret = (LONG)CLASS_GetProc( class, WIN_PROC_16 );
729         release_class_ptr( class );
730         return ret;
731     case GCLP_MENUNAME:
732         if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
733         if (class == CLASS_OTHER_PROCESS) break;
734         ret = (LONG)CLASS_GetMenuName16( class );
735         release_class_ptr( class );
736         return ret;
737     default:
738         return GetClassLongA( hwnd, offset );
739     }
740     FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
741     SetLastError( ERROR_INVALID_HANDLE );
742     return 0;
743 }
744
745
746 /***********************************************************************
747  *              GetClassLongW (USER32.@)
748  */
749 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
750 {
751     CLASS *class;
752     DWORD retvalue = 0;
753
754     TRACE("%p %d\n", hwnd, offset);
755
756     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
757
758     if (class == CLASS_OTHER_PROCESS)
759     {
760         SERVER_START_REQ( set_class_info )
761         {
762             req->window = hwnd;
763             req->flags = 0;
764             req->extra_offset = (offset >= 0) ? offset : -1;
765             req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
766             if (!wine_server_call_err( req ))
767             {
768                 switch(offset)
769                 {
770                 case GCLP_HBRBACKGROUND:
771                 case GCLP_HCURSOR:
772                 case GCLP_HICON:
773                 case GCLP_HICONSM:
774                 case GCLP_WNDPROC:
775                 case GCLP_MENUNAME:
776                     FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
777                     SetLastError( ERROR_INVALID_HANDLE );
778                     break;
779                 case GCL_STYLE:
780                     retvalue = reply->old_style;
781                     break;
782                 case GCL_CBWNDEXTRA:
783                     retvalue = reply->old_win_extra;
784                     break;
785                 case GCL_CBCLSEXTRA:
786                     retvalue = reply->old_extra;
787                     break;
788                 case GCLP_HMODULE:
789                     retvalue = (DWORD)reply->old_instance;
790                     break;
791                 case GCW_ATOM:
792                     retvalue = reply->old_atom;
793                     break;
794                 default:
795                     if (offset >= 0) memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
796                     else SetLastError( ERROR_INVALID_INDEX );
797                     break;
798                 }
799             }
800         }
801         SERVER_END_REQ;
802         return retvalue;
803     }
804
805     if (offset >= 0)
806     {
807         if (offset <= class->cbClsExtra - sizeof(LONG))
808             memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
809         else
810             SetLastError( ERROR_INVALID_INDEX );
811         release_class_ptr( class );
812         return retvalue;
813     }
814
815     switch(offset)
816     {
817     case GCLP_HBRBACKGROUND:
818         retvalue = (DWORD)class->hbrBackground;
819         break;
820     case GCLP_HCURSOR:
821         retvalue = (DWORD)class->hCursor;
822         break;
823     case GCLP_HICON:
824         retvalue = (DWORD)class->hIcon;
825         break;
826     case GCLP_HICONSM:
827         retvalue = (DWORD)class->hIconSm;
828         break;
829     case GCL_STYLE:
830         retvalue = (DWORD)class->style;
831         break;
832     case GCL_CBWNDEXTRA:
833         retvalue = (DWORD)class->cbWndExtra;
834         break;
835     case GCL_CBCLSEXTRA:
836         retvalue = (DWORD)class->cbClsExtra;
837         break;
838     case GCLP_HMODULE:
839         retvalue = (DWORD)class->hInstance;
840         break;
841     case GCLP_WNDPROC:
842         retvalue = (DWORD)CLASS_GetProc( class, WIN_PROC_32W );
843         break;
844     case GCLP_MENUNAME:
845         retvalue = (DWORD)CLASS_GetMenuNameW( class );
846         break;
847     case GCW_ATOM:
848         retvalue = (DWORD)class->atomName;
849         break;
850     default:
851         SetLastError( ERROR_INVALID_INDEX );
852         break;
853     }
854     release_class_ptr( class );
855     return retvalue;
856 }
857
858
859 /***********************************************************************
860  *              GetClassLongA (USER32.@)
861  */
862 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
863 {
864     CLASS *class;
865     DWORD retvalue;
866
867     if (offset != GCLP_WNDPROC && offset != GCLP_MENUNAME)
868         return GetClassLongW( hwnd, offset );
869
870     TRACE("%p %d\n", hwnd, offset);
871
872     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
873
874     if (class == CLASS_OTHER_PROCESS)
875     {
876         FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
877         SetLastError( ERROR_INVALID_HANDLE );
878         return 0;
879     }
880
881     if (offset == GCLP_WNDPROC)
882         retvalue = (DWORD)CLASS_GetProc( class, WIN_PROC_32A );
883     else  /* GCL_MENUNAME */
884         retvalue = (DWORD)CLASS_GetMenuNameA( class );
885
886     release_class_ptr( class );
887     return retvalue;
888 }
889
890
891 /***********************************************************************
892  *              SetClassWord (USER32.@)
893  */
894 WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
895 {
896     CLASS *class;
897     WORD retval = 0;
898
899     if (offset < 0) return SetClassLongA( hwnd, offset, (DWORD)newval );
900
901     TRACE("%p %d %x\n", hwnd, offset, newval);
902
903     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
904
905     SERVER_START_REQ( set_class_info )
906     {
907         req->window = hwnd;
908         req->flags = SET_CLASS_EXTRA;
909         req->extra_offset = offset;
910         req->extra_size = sizeof(newval);
911         memcpy( &req->extra_value, &newval, sizeof(newval) );
912         if (!wine_server_call_err( req ))
913         {
914             void *ptr = (char *)(class + 1) + offset;
915             memcpy( &retval, ptr, sizeof(retval) );
916             memcpy( ptr, &newval, sizeof(newval) );
917         }
918     }
919     SERVER_END_REQ;
920     release_class_ptr( class );
921     return retval;
922 }
923
924
925 /***********************************************************************
926  *              SetClassLong (USER.132)
927  */
928 LONG WINAPI SetClassLong16( HWND16 hwnd16, INT16 offset, LONG newval )
929 {
930     CLASS *class;
931     LONG retval;
932     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;  /* no need for full handle */
933
934     TRACE("%p %d %lx\n", hwnd, offset, newval);
935
936     switch(offset)
937     {
938     case GCLP_WNDPROC:
939         if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
940         retval = (LONG)CLASS_SetProc( class, (WNDPROC)newval, WIN_PROC_16 );
941         release_class_ptr( class );
942         return retval;
943     case GCLP_MENUNAME:
944         newval = (LONG)MapSL( newval );
945         /* fall through */
946     default:
947         return SetClassLongA( hwnd, offset, newval );
948     }
949 }
950
951
952 /***********************************************************************
953  *              SetClassLongW (USER32.@)
954  */
955 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
956 {
957     CLASS *class;
958     DWORD retval = 0;
959
960     TRACE("%p %d %lx\n", hwnd, offset, newval);
961
962     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
963
964     if (offset >= 0)
965     {
966         if (set_server_info( hwnd, offset, newval ))
967         {
968             void *ptr = (char *)(class + 1) + offset;
969             memcpy( &retval, ptr, sizeof(retval) );
970             memcpy( ptr, &newval, sizeof(newval) );
971         }
972     }
973     else switch(offset)
974     {
975     case GCLP_MENUNAME:
976         CLASS_SetMenuNameW( class, (LPCWSTR)newval );
977         retval = 0;  /* Old value is now meaningless anyway */
978         break;
979     case GCLP_WNDPROC:
980         retval = (DWORD)CLASS_SetProc( class, (WNDPROC)newval, WIN_PROC_32W );
981         break;
982     case GCLP_HBRBACKGROUND:
983         retval = (DWORD)class->hbrBackground;
984         class->hbrBackground = (HBRUSH)newval;
985         break;
986     case GCLP_HCURSOR:
987         retval = (DWORD)class->hCursor;
988         class->hCursor = (HCURSOR)newval;
989         break;
990     case GCLP_HICON:
991         retval = (DWORD)class->hIcon;
992         class->hIcon = (HICON)newval;
993         break;
994     case GCLP_HICONSM:
995         retval = (DWORD)class->hIconSm;
996         class->hIconSm = (HICON)newval;
997         break;
998     case GCL_STYLE:
999         if (!set_server_info( hwnd, offset, newval )) break;
1000         retval = (DWORD)class->style;
1001         class->style = newval;
1002         break;
1003     case GCL_CBWNDEXTRA:
1004         if (!set_server_info( hwnd, offset, newval )) break;
1005         retval = (DWORD)class->cbWndExtra;
1006         class->cbWndExtra = newval;
1007         break;
1008     case GCLP_HMODULE:
1009         if (!set_server_info( hwnd, offset, newval )) break;
1010         retval = (DWORD)class->hInstance;
1011         class->hInstance = (HINSTANCE)newval;
1012         break;
1013     case GCW_ATOM:
1014         if (!set_server_info( hwnd, offset, newval )) break;
1015         retval = (DWORD)class->atomName;
1016         class->atomName = newval;
1017         break;
1018     case GCL_CBCLSEXTRA:  /* cannot change this one */
1019         SetLastError( ERROR_INVALID_PARAMETER );
1020         break;
1021     default:
1022         SetLastError( ERROR_INVALID_INDEX );
1023         break;
1024     }
1025     release_class_ptr( class );
1026     return retval;
1027 }
1028
1029
1030 /***********************************************************************
1031  *              SetClassLongA (USER32.@)
1032  */
1033 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
1034 {
1035     CLASS *class;
1036     DWORD retval;
1037
1038     if (offset != GCLP_WNDPROC && offset != GCLP_MENUNAME)
1039         return SetClassLongW( hwnd, offset, newval );
1040
1041     TRACE("%p %d %lx\n", hwnd, offset, newval);
1042
1043     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
1044
1045     if (offset == GCLP_WNDPROC)
1046         retval = (DWORD)CLASS_SetProc( class, (WNDPROC)newval, WIN_PROC_32A );
1047     else  /* GCL_MENUNAME */
1048     {
1049         CLASS_SetMenuNameA( class, (LPCSTR)newval );
1050         retval = 0;  /* Old value is now meaningless anyway */
1051     }
1052     release_class_ptr( class );
1053     return retval;
1054 }
1055
1056
1057 /***********************************************************************
1058  *              GetClassNameA (USER32.@)
1059  */
1060 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
1061 {
1062     INT ret = GlobalGetAtomNameA( GetClassLongA( hwnd, GCW_ATOM ), buffer, count );
1063
1064     TRACE("%p %s %x\n",hwnd, debugstr_a(buffer), count);
1065     return ret;
1066 }
1067
1068
1069 /***********************************************************************
1070  *              GetClassNameW (USER32.@)
1071  */
1072 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
1073 {
1074     INT ret = GlobalGetAtomNameW( GetClassLongW( hwnd, GCW_ATOM ), buffer, count );
1075
1076     TRACE("%p %s %x\n",hwnd, debugstr_w(buffer), count);
1077     return ret;
1078 }
1079
1080
1081 /***********************************************************************
1082  *              RealGetWindowClassA (USER32.@)
1083  */
1084 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
1085 {
1086     return GetClassNameA( hwnd, buffer, count );
1087 }
1088
1089
1090 /***********************************************************************
1091  *              RealGetWindowClassW (USER32.@)
1092  */
1093 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
1094 {
1095     return GetClassNameW( hwnd, buffer, count );
1096 }
1097
1098
1099 /***********************************************************************
1100  *              GetClassInfoA (USER32.@)
1101  */
1102 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
1103 {
1104     WNDCLASSEXA wcex;
1105     UINT ret = GetClassInfoExA( hInstance, name, &wcex );
1106
1107     if (ret)
1108     {
1109         wc->style         = wcex.style;
1110         wc->lpfnWndProc   = wcex.lpfnWndProc;
1111         wc->cbClsExtra    = wcex.cbClsExtra;
1112         wc->cbWndExtra    = wcex.cbWndExtra;
1113         wc->hInstance     = wcex.hInstance;
1114         wc->hIcon         = wcex.hIcon;
1115         wc->hCursor       = wcex.hCursor;
1116         wc->hbrBackground = wcex.hbrBackground;
1117         wc->lpszMenuName  = wcex.lpszMenuName;
1118         wc->lpszClassName = wcex.lpszClassName;
1119     }
1120     return ret;
1121 }
1122
1123
1124 /***********************************************************************
1125  *              GetClassInfoW (USER32.@)
1126  */
1127 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
1128 {
1129     WNDCLASSEXW wcex;
1130     UINT ret = GetClassInfoExW( hInstance, name, &wcex );
1131
1132     if (ret)
1133     {
1134         wc->style         = wcex.style;
1135         wc->lpfnWndProc   = wcex.lpfnWndProc;
1136         wc->cbClsExtra    = wcex.cbClsExtra;
1137         wc->cbWndExtra    = wcex.cbWndExtra;
1138         wc->hInstance     = wcex.hInstance;
1139         wc->hIcon         = wcex.hIcon;
1140         wc->hCursor       = wcex.hCursor;
1141         wc->hbrBackground = wcex.hbrBackground;
1142         wc->lpszMenuName  = wcex.lpszMenuName;
1143         wc->lpszClassName = wcex.lpszClassName;
1144     }
1145     return ret;
1146 }
1147
1148
1149 /***********************************************************************
1150  *              GetClassInfoExA (USER32.@)
1151  */
1152 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
1153 {
1154     ATOM atom = HIWORD(name) ? GlobalFindAtomA( name ) : LOWORD(name);
1155     CLASS *classPtr;
1156
1157     TRACE("%p %s %x %p\n", hInstance, debugstr_a(name), atom, wc);
1158
1159     if (!hInstance) hInstance = user32_module;
1160
1161     if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
1162     {
1163         SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1164         return FALSE;
1165     }
1166     wc->style         = classPtr->style;
1167     wc->lpfnWndProc   = (WNDPROC)CLASS_GetProc( classPtr, WIN_PROC_32A );
1168     wc->cbClsExtra    = classPtr->cbClsExtra;
1169     wc->cbWndExtra    = classPtr->cbWndExtra;
1170     wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1171     wc->hIcon         = (HICON)classPtr->hIcon;
1172     wc->hIconSm       = (HICON)classPtr->hIconSm;
1173     wc->hCursor       = (HCURSOR)classPtr->hCursor;
1174     wc->hbrBackground = (HBRUSH)classPtr->hbrBackground;
1175     wc->lpszMenuName  = CLASS_GetMenuNameA( classPtr );
1176     wc->lpszClassName = name;
1177     release_class_ptr( classPtr );
1178
1179     /* We must return the atom of the class here instead of just TRUE. */
1180     return atom;
1181 }
1182
1183
1184 /***********************************************************************
1185  *              GetClassInfoExW (USER32.@)
1186  */
1187 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
1188 {
1189     ATOM atom = HIWORD(name) ? GlobalFindAtomW( name ) : LOWORD(name);
1190     CLASS *classPtr;
1191
1192     TRACE("%p %s %x %p\n", hInstance, debugstr_w(name), atom, wc);
1193
1194     if (!hInstance) hInstance = user32_module;
1195
1196     if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
1197     {
1198         SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1199         return FALSE;
1200     }
1201     wc->style         = classPtr->style;
1202     wc->lpfnWndProc   = (WNDPROC)CLASS_GetProc( classPtr, WIN_PROC_32W );
1203     wc->cbClsExtra    = classPtr->cbClsExtra;
1204     wc->cbWndExtra    = classPtr->cbWndExtra;
1205     wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1206     wc->hIcon         = (HICON)classPtr->hIcon;
1207     wc->hIconSm       = (HICON)classPtr->hIconSm;
1208     wc->hCursor       = (HCURSOR)classPtr->hCursor;
1209     wc->hbrBackground = (HBRUSH)classPtr->hbrBackground;
1210     wc->lpszMenuName  = CLASS_GetMenuNameW( classPtr );
1211     wc->lpszClassName = name;
1212     release_class_ptr( classPtr );
1213
1214     /* We must return the atom of the class here instead of just TRUE. */
1215     return atom;
1216 }
1217
1218
1219 #if 0  /* toolhelp is in kernel, so this cannot work */
1220
1221 /***********************************************************************
1222  *              ClassFirst (TOOLHELP.69)
1223  */
1224 BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
1225 {
1226     TRACE("%p\n",pClassEntry);
1227     pClassEntry->wNext = 1;
1228     return ClassNext16( pClassEntry );
1229 }
1230
1231
1232 /***********************************************************************
1233  *              ClassNext (TOOLHELP.70)
1234  */
1235 BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
1236 {
1237     int i;
1238     CLASS *class = firstClass;
1239
1240     TRACE("%p\n",pClassEntry);
1241
1242     if (!pClassEntry->wNext) return FALSE;
1243     for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
1244     if (!class)
1245     {
1246         pClassEntry->wNext = 0;
1247         return FALSE;
1248     }
1249     pClassEntry->hInst = class->hInstance;
1250     pClassEntry->wNext++;
1251     GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
1252                           sizeof(pClassEntry->szClassName) );
1253     return TRUE;
1254 }
1255 #endif