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