wintrust: Use a helper function to get a signer's cert info from a message.
[wine] / dlls / user32 / 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 "wine/server.h"
40 #include "wine/list.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(class);
44
45 typedef struct tagCLASS
46 {
47     struct list      entry;         /* Entry in class list */
48     UINT             style;         /* Class style */
49     BOOL             local;         /* Local class? */
50     WNDPROC          winproc;       /* Window procedure */
51     INT              cbClsExtra;    /* Class extra bytes */
52     INT              cbWndExtra;    /* Window extra bytes */
53     LPWSTR           menuName;      /* Default menu name (Unicode followed by ASCII) */
54     HINSTANCE        hInstance;     /* Module that created the task */
55     HICON            hIcon;         /* Default icon */
56     HICON            hIconSm;       /* Default small icon */
57     HCURSOR          hCursor;       /* Default cursor */
58     HBRUSH           hbrBackground; /* Default background */
59     ATOM             atomName;      /* Name of the class */
60 } CLASS;
61
62 static struct list class_list = LIST_INIT( class_list );
63
64 #define CLASS_OTHER_PROCESS ((CLASS *)1)
65 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
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 static inline 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 static inline 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 static inline 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     /* the DefWindowProc winprocs are magic too */
420     WINPROC_AllocProc( DefWindowProcA, DefWindowProcW );
421 }
422
423
424 /***********************************************************************
425  *           CLASS_AddWindow
426  *
427  * Add a new window using this class, and set the necessary
428  * information inside the window structure.
429  */
430 void CLASS_AddWindow( CLASS *class, WND *win, BOOL unicode )
431 {
432     win->class    = class;
433     win->clsStyle = class->style;
434     win->winproc  = class->winproc;
435     if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
436 }
437
438
439 /***********************************************************************
440  *              RegisterClassA (USER32.@)
441  *
442  * Register a window class.
443  *
444  * RETURNS
445  *      >0: Unique identifier
446  *      0: Failure
447  */
448 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
449 {
450     WNDCLASSEXA wcex;
451
452     wcex.cbSize        = sizeof(wcex);
453     wcex.style         = wc->style;
454     wcex.lpfnWndProc   = wc->lpfnWndProc;
455     wcex.cbClsExtra    = wc->cbClsExtra;
456     wcex.cbWndExtra    = wc->cbWndExtra;
457     wcex.hInstance     = wc->hInstance;
458     wcex.hIcon         = wc->hIcon;
459     wcex.hCursor       = wc->hCursor;
460     wcex.hbrBackground = wc->hbrBackground;
461     wcex.lpszMenuName  = wc->lpszMenuName;
462     wcex.lpszClassName = wc->lpszClassName;
463     wcex.hIconSm       = 0;
464     return RegisterClassExA( &wcex );
465 }
466
467
468 /***********************************************************************
469  *              RegisterClassW (USER32.@)
470  *
471  * See RegisterClassA.
472  */
473 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
474 {
475     WNDCLASSEXW wcex;
476
477     wcex.cbSize        = sizeof(wcex);
478     wcex.style         = wc->style;
479     wcex.lpfnWndProc   = wc->lpfnWndProc;
480     wcex.cbClsExtra    = wc->cbClsExtra;
481     wcex.cbWndExtra    = wc->cbWndExtra;
482     wcex.hInstance     = wc->hInstance;
483     wcex.hIcon         = wc->hIcon;
484     wcex.hCursor       = wc->hCursor;
485     wcex.hbrBackground = wc->hbrBackground;
486     wcex.lpszMenuName  = wc->lpszMenuName;
487     wcex.lpszClassName = wc->lpszClassName;
488     wcex.hIconSm       = 0;
489     return RegisterClassExW( &wcex );
490 }
491
492
493 /***********************************************************************
494  *              RegisterClassExA (USER32.@)
495  */
496 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
497 {
498     ATOM atom;
499     CLASS *classPtr;
500     HINSTANCE instance;
501
502     if (wc->hInstance == user32_module)
503     {
504         /* we can't register a class for user32 */
505         SetLastError( ERROR_INVALID_PARAMETER );
506         return 0;
507     }
508     if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
509
510     if (!(atom = GlobalAddAtomA( wc->lpszClassName ))) return 0;
511
512     if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
513                                           wc->style, wc->cbClsExtra, wc->cbWndExtra )))
514         return 0;
515
516     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
517           atom, wc->lpfnWndProc, instance, wc->hbrBackground,
518           wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
519
520     classPtr->hIcon         = wc->hIcon;
521     classPtr->hIconSm       = wc->hIconSm;
522     classPtr->hCursor       = wc->hCursor;
523     classPtr->hbrBackground = wc->hbrBackground;
524     classPtr->winproc       = WINPROC_AllocProc( wc->lpfnWndProc, NULL );
525     CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
526     release_class_ptr( classPtr );
527     return atom;
528 }
529
530
531 /***********************************************************************
532  *              RegisterClassExW (USER32.@)
533  */
534 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
535 {
536     ATOM atom;
537     CLASS *classPtr;
538     HINSTANCE instance;
539
540     if (wc->hInstance == user32_module)
541     {
542         /* we can't register a class for user32 */
543         SetLastError( ERROR_INVALID_PARAMETER );
544         return 0;
545     }
546     if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
547
548     if (!(atom = GlobalAddAtomW( wc->lpszClassName ))) return 0;
549
550     if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
551                                           wc->style, wc->cbClsExtra, wc->cbWndExtra )))
552         return 0;
553
554     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
555           atom, wc->lpfnWndProc, instance, wc->hbrBackground,
556           wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
557
558     classPtr->hIcon         = wc->hIcon;
559     classPtr->hIconSm       = wc->hIconSm;
560     classPtr->hCursor       = wc->hCursor;
561     classPtr->hbrBackground = wc->hbrBackground;
562     classPtr->winproc       = WINPROC_AllocProc( NULL, wc->lpfnWndProc );
563     CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
564     release_class_ptr( classPtr );
565     return atom;
566 }
567
568
569 /***********************************************************************
570  *              UnregisterClassA (USER32.@)
571  */
572 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
573 {
574     ATOM atom = HIWORD(className) ? GlobalFindAtomA( className ) : LOWORD(className);
575     return UnregisterClassW( (LPCWSTR)MAKEINTATOM(atom), hInstance );
576 }
577
578 /***********************************************************************
579  *              UnregisterClassW (USER32.@)
580  */
581 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
582 {
583     CLASS *classPtr = NULL;
584     ATOM atom = HIWORD(className) ? GlobalFindAtomW( className ) : LOWORD(className);
585
586     TRACE("%s %p %x\n",debugstr_w(className), hInstance, atom);
587
588     if (!atom)
589     {
590         SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
591         return FALSE;
592     }
593
594     SERVER_START_REQ( destroy_class )
595     {
596         req->atom = atom;
597         req->instance = hInstance;
598         if (!wine_server_call_err( req )) classPtr = reply->client_ptr;
599     }
600     SERVER_END_REQ;
601
602     if (classPtr) CLASS_FreeClass( classPtr );
603     return (classPtr != NULL);
604 }
605
606
607 /***********************************************************************
608  *              GetClassWord (USER32.@)
609  */
610 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
611 {
612     CLASS *class;
613     WORD retvalue = 0;
614
615     if (offset < 0) return GetClassLongA( hwnd, offset );
616
617     TRACE("%p %x\n",hwnd, offset);
618
619     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
620
621     if (class == CLASS_OTHER_PROCESS)
622     {
623         SERVER_START_REQ( set_class_info )
624         {
625             req->window = hwnd;
626             req->flags = 0;
627             req->extra_offset = offset;
628             req->extra_size = sizeof(retvalue);
629             if (!wine_server_call_err( req ))
630                 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
631         }
632         SERVER_END_REQ;
633         return retvalue;
634     }
635
636     if (offset <= class->cbClsExtra - sizeof(WORD))
637         memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
638     else
639         SetLastError( ERROR_INVALID_INDEX );
640     release_class_ptr( class );
641     return retvalue;
642 }
643
644
645 /***********************************************************************
646  *             CLASS_GetClassLong
647  *
648  * Implementation of GetClassLong(Ptr)A/W
649  */
650 static ULONG_PTR CLASS_GetClassLong( HWND hwnd, INT offset, UINT size,
651                                      BOOL unicode )
652 {
653     CLASS *class;
654     ULONG_PTR retvalue = 0;
655
656     TRACE("%p %d\n", hwnd, offset);
657
658     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
659
660     if (class == CLASS_OTHER_PROCESS)
661     {
662         SERVER_START_REQ( set_class_info )
663         {
664             req->window = hwnd;
665             req->flags = 0;
666             req->extra_offset = (offset >= 0) ? offset : -1;
667             req->extra_size = (offset >= 0) ? size : 0;
668             if (!wine_server_call_err( req ))
669             {
670                 switch(offset)
671                 {
672                 case GCLP_HBRBACKGROUND:
673                 case GCLP_HCURSOR:
674                 case GCLP_HICON:
675                 case GCLP_HICONSM:
676                 case GCLP_WNDPROC:
677                 case GCLP_MENUNAME:
678                     FIXME( "offset %d (%s) not supported on other process window %p\n",
679                            offset, SPY_GetClassLongOffsetName(offset), hwnd );
680                     SetLastError( ERROR_INVALID_HANDLE );
681                     break;
682                 case GCL_STYLE:
683                     retvalue = reply->old_style;
684                     break;
685                 case GCL_CBWNDEXTRA:
686                     retvalue = reply->old_win_extra;
687                     break;
688                 case GCL_CBCLSEXTRA:
689                     retvalue = reply->old_extra;
690                     break;
691                 case GCLP_HMODULE:
692                     retvalue = (ULONG_PTR)reply->old_instance;
693                     break;
694                 case GCW_ATOM:
695                     retvalue = reply->old_atom;
696                     break;
697                 default:
698                     if (offset >= 0)
699                     {
700                         if (size == sizeof(DWORD))
701                         {
702                             DWORD retdword;
703                             memcpy( &retdword, &reply->old_extra_value, sizeof(DWORD) );
704                             retvalue = retdword;
705                         }
706                         else
707                             memcpy( &retvalue, &reply->old_extra_value,
708                                     sizeof(ULONG_PTR) );
709                     }
710                     else SetLastError( ERROR_INVALID_INDEX );
711                     break;
712                 }
713             }
714         }
715         SERVER_END_REQ;
716         return retvalue;
717     }
718
719     if (offset >= 0)
720     {
721         if (offset <= class->cbClsExtra - size)
722         {
723             if (size == sizeof(DWORD))
724             {
725                 DWORD retdword;
726                 memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) );
727                 retvalue = retdword;
728             }
729             else
730                 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) );
731         }
732         else
733             SetLastError( ERROR_INVALID_INDEX );
734         release_class_ptr( class );
735         return retvalue;
736     }
737
738     switch(offset)
739     {
740     case GCLP_HBRBACKGROUND:
741         retvalue = (ULONG_PTR)class->hbrBackground;
742         break;
743     case GCLP_HCURSOR:
744         retvalue = (ULONG_PTR)class->hCursor;
745         break;
746     case GCLP_HICON:
747         retvalue = (ULONG_PTR)class->hIcon;
748         break;
749     case GCLP_HICONSM:
750         retvalue = (ULONG_PTR)class->hIconSm;
751         break;
752     case GCL_STYLE:
753         retvalue = class->style;
754         break;
755     case GCL_CBWNDEXTRA:
756         retvalue = class->cbWndExtra;
757         break;
758     case GCL_CBCLSEXTRA:
759         retvalue = class->cbClsExtra;
760         break;
761     case GCLP_HMODULE:
762         retvalue = (ULONG_PTR)class->hInstance;
763         break;
764     case GCLP_WNDPROC:
765         retvalue = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
766         break;
767     case GCLP_MENUNAME:
768         retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
769         if (unicode)
770             retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
771         else
772             retvalue = (ULONG_PTR)CLASS_GetMenuNameA( class );
773         break;
774     case GCW_ATOM:
775         retvalue = class->atomName;
776         break;
777     default:
778         SetLastError( ERROR_INVALID_INDEX );
779         break;
780     }
781     release_class_ptr( class );
782     return retvalue;
783 }
784
785
786 /***********************************************************************
787  *              GetClassLongW (USER32.@)
788  */
789 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
790 {
791     return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), TRUE );
792 }
793
794
795
796 /***********************************************************************
797  *              GetClassLongA (USER32.@)
798  */
799 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
800 {
801     return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), FALSE );
802 }
803
804
805 /***********************************************************************
806  *              SetClassWord (USER32.@)
807  */
808 WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
809 {
810     CLASS *class;
811     WORD retval = 0;
812
813     if (offset < 0) return SetClassLongA( hwnd, offset, (DWORD)newval );
814
815     TRACE("%p %d %x\n", hwnd, offset, newval);
816
817     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
818
819     SERVER_START_REQ( set_class_info )
820     {
821         req->window = hwnd;
822         req->flags = SET_CLASS_EXTRA;
823         req->extra_offset = offset;
824         req->extra_size = sizeof(newval);
825         memcpy( &req->extra_value, &newval, sizeof(newval) );
826         if (!wine_server_call_err( req ))
827         {
828             void *ptr = (char *)(class + 1) + offset;
829             memcpy( &retval, ptr, sizeof(retval) );
830             memcpy( ptr, &newval, sizeof(newval) );
831         }
832     }
833     SERVER_END_REQ;
834     release_class_ptr( class );
835     return retval;
836 }
837
838
839 /***********************************************************************
840  *             CLASS_SetClassLong
841  *
842  * Implementation of SetClassLong(Ptr)A/W
843  */
844 static ULONG_PTR CLASS_SetClassLong( HWND hwnd, INT offset, LONG_PTR newval,
845                                      UINT size, BOOL unicode )
846 {
847     CLASS *class;
848     ULONG_PTR retval = 0;
849
850     TRACE("%p %d %lx\n", hwnd, offset, newval);
851
852     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
853
854     if (offset >= 0)
855     {
856         if (set_server_info( hwnd, offset, newval, size ))
857         {
858             void *ptr = (char *)(class + 1) + offset;
859             if ( size == sizeof(LONG) )
860             {
861                 DWORD retdword;
862                 LONG newlong = newval;
863                 memcpy( &retdword, ptr, sizeof(DWORD) );
864                 memcpy( ptr, &newlong, sizeof(LONG) );
865                 retval = retdword;
866             }
867             else
868             {
869                 memcpy( &retval, ptr, sizeof(ULONG_PTR) );
870                 memcpy( ptr, &newval, sizeof(LONG_PTR) );
871             }
872         }
873     }
874     else switch(offset)
875     {
876     case GCLP_MENUNAME:
877         if ( unicode )
878             CLASS_SetMenuNameW( class, (LPCWSTR)newval );
879         else
880             CLASS_SetMenuNameA( class, (LPCSTR)newval );
881         retval = 0;  /* Old value is now meaningless anyway */
882         break;
883     case GCLP_WNDPROC:
884         retval = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
885         class->winproc = WINPROC_AllocProc( unicode ? NULL : (WNDPROC)newval,
886                                             unicode ? (WNDPROC)newval : NULL );
887         break;
888     case GCLP_HBRBACKGROUND:
889         retval = (ULONG_PTR)class->hbrBackground;
890         class->hbrBackground = (HBRUSH)newval;
891         break;
892     case GCLP_HCURSOR:
893         retval = (ULONG_PTR)class->hCursor;
894         class->hCursor = (HCURSOR)newval;
895         break;
896     case GCLP_HICON:
897         retval = (ULONG_PTR)class->hIcon;
898         class->hIcon = (HICON)newval;
899         break;
900     case GCLP_HICONSM:
901         retval = (ULONG_PTR)class->hIconSm;
902         class->hIconSm = (HICON)newval;
903         break;
904     case GCL_STYLE:
905         if (!set_server_info( hwnd, offset, newval, size )) break;
906         retval = class->style;
907         class->style = newval;
908         break;
909     case GCL_CBWNDEXTRA:
910         if (!set_server_info( hwnd, offset, newval, size )) break;
911         retval = class->cbWndExtra;
912         class->cbWndExtra = newval;
913         break;
914     case GCLP_HMODULE:
915         if (!set_server_info( hwnd, offset, newval, size )) break;
916         retval = (ULONG_PTR)class->hInstance;
917         class->hInstance = (HINSTANCE)newval;
918         break;
919     case GCW_ATOM:
920         if (!set_server_info( hwnd, offset, newval, size )) break;
921         retval = class->atomName;
922         class->atomName = newval;
923         break;
924     case GCL_CBCLSEXTRA:  /* cannot change this one */
925         SetLastError( ERROR_INVALID_PARAMETER );
926         break;
927     default:
928         SetLastError( ERROR_INVALID_INDEX );
929         break;
930     }
931     release_class_ptr( class );
932     return retval;
933 }
934
935
936 /***********************************************************************
937  *              SetClassLongW (USER32.@)
938  */
939 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
940 {
941     TRACE("%p %d %x\n", hwnd, offset, newval);
942
943     return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), TRUE );
944 }
945
946
947 /***********************************************************************
948  *              SetClassLongA (USER32.@)
949  */
950 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
951 {
952     TRACE("%p %d %x\n", hwnd, offset, newval);
953
954     return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), FALSE );
955 }
956
957
958 /***********************************************************************
959  *              GetClassNameA (USER32.@)
960  */
961 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
962 {
963     char tmpbuf[MAX_ATOM_LEN + 1];
964     INT ret;
965
966     TRACE("%p %p %d\n", hwnd, buffer, count);
967
968     if (count <= 0) return 0;
969
970     ret = GlobalGetAtomNameA( GetClassLongW( hwnd, GCW_ATOM ), tmpbuf, MAX_ATOM_LEN + 1 );
971     if (ret)
972     {
973         ret = min(count - 1, ret);
974         memcpy(buffer, tmpbuf, ret);
975         buffer[ret] = 0;
976     }
977     return ret;
978 }
979
980
981 /***********************************************************************
982  *              GetClassNameW (USER32.@)
983  */
984 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
985 {
986     WCHAR tmpbuf[MAX_ATOM_LEN + 1];
987     INT ret;
988
989     TRACE("%p %p %d\n", hwnd, buffer, count);
990
991     if (count <= 0) return 0;
992
993     ret = GlobalGetAtomNameW( GetClassLongW( hwnd, GCW_ATOM ), tmpbuf, MAX_ATOM_LEN + 1 );
994     if (ret)
995     {
996         ret = min(count - 1, ret);
997         memcpy(buffer, tmpbuf, ret * sizeof(WCHAR));
998         buffer[ret] = 0;
999     }
1000     return ret;
1001 }
1002
1003
1004 /***********************************************************************
1005  *              RealGetWindowClassA (USER32.@)
1006  */
1007 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
1008 {
1009     return GetClassNameA( hwnd, buffer, count );
1010 }
1011
1012
1013 /***********************************************************************
1014  *              RealGetWindowClassW (USER32.@)
1015  */
1016 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
1017 {
1018     return GetClassNameW( hwnd, buffer, count );
1019 }
1020
1021
1022 /***********************************************************************
1023  *              GetClassInfoA (USER32.@)
1024  */
1025 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
1026 {
1027     WNDCLASSEXA wcex;
1028     UINT ret = GetClassInfoExA( hInstance, name, &wcex );
1029
1030     if (ret)
1031     {
1032         wc->style         = wcex.style;
1033         wc->lpfnWndProc   = wcex.lpfnWndProc;
1034         wc->cbClsExtra    = wcex.cbClsExtra;
1035         wc->cbWndExtra    = wcex.cbWndExtra;
1036         wc->hInstance     = wcex.hInstance;
1037         wc->hIcon         = wcex.hIcon;
1038         wc->hCursor       = wcex.hCursor;
1039         wc->hbrBackground = wcex.hbrBackground;
1040         wc->lpszMenuName  = wcex.lpszMenuName;
1041         wc->lpszClassName = wcex.lpszClassName;
1042     }
1043     return ret;
1044 }
1045
1046
1047 /***********************************************************************
1048  *              GetClassInfoW (USER32.@)
1049  */
1050 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
1051 {
1052     WNDCLASSEXW wcex;
1053     UINT ret = GetClassInfoExW( hInstance, name, &wcex );
1054
1055     if (ret)
1056     {
1057         wc->style         = wcex.style;
1058         wc->lpfnWndProc   = wcex.lpfnWndProc;
1059         wc->cbClsExtra    = wcex.cbClsExtra;
1060         wc->cbWndExtra    = wcex.cbWndExtra;
1061         wc->hInstance     = wcex.hInstance;
1062         wc->hIcon         = wcex.hIcon;
1063         wc->hCursor       = wcex.hCursor;
1064         wc->hbrBackground = wcex.hbrBackground;
1065         wc->lpszMenuName  = wcex.lpszMenuName;
1066         wc->lpszClassName = wcex.lpszClassName;
1067     }
1068     return ret;
1069 }
1070
1071
1072 /***********************************************************************
1073  *              GetClassInfoExA (USER32.@)
1074  */
1075 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
1076 {
1077     ATOM atom = HIWORD(name) ? GlobalFindAtomA( name ) : LOWORD(name);
1078     CLASS *classPtr;
1079
1080     TRACE("%p %s %x %p\n", hInstance, debugstr_a(name), atom, wc);
1081
1082     if (!hInstance) hInstance = user32_module;
1083
1084     if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
1085     {
1086         SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1087         return FALSE;
1088     }
1089     wc->style         = classPtr->style;
1090     wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, FALSE );
1091     wc->cbClsExtra    = classPtr->cbClsExtra;
1092     wc->cbWndExtra    = classPtr->cbWndExtra;
1093     wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1094     wc->hIcon         = (HICON)classPtr->hIcon;
1095     wc->hIconSm       = (HICON)classPtr->hIconSm;
1096     wc->hCursor       = (HCURSOR)classPtr->hCursor;
1097     wc->hbrBackground = (HBRUSH)classPtr->hbrBackground;
1098     wc->lpszMenuName  = CLASS_GetMenuNameA( classPtr );
1099     wc->lpszClassName = name;
1100     release_class_ptr( classPtr );
1101
1102     /* We must return the atom of the class here instead of just TRUE. */
1103     return atom;
1104 }
1105
1106
1107 /***********************************************************************
1108  *              GetClassInfoExW (USER32.@)
1109  */
1110 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
1111 {
1112     ATOM atom = HIWORD(name) ? GlobalFindAtomW( name ) : LOWORD(name);
1113     CLASS *classPtr;
1114
1115     TRACE("%p %s %x %p\n", hInstance, debugstr_w(name), atom, wc);
1116
1117     if (!hInstance) hInstance = user32_module;
1118
1119     if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
1120     {
1121         SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1122         return FALSE;
1123     }
1124     wc->style         = classPtr->style;
1125     wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, TRUE );
1126     wc->cbClsExtra    = classPtr->cbClsExtra;
1127     wc->cbWndExtra    = classPtr->cbWndExtra;
1128     wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1129     wc->hIcon         = (HICON)classPtr->hIcon;
1130     wc->hIconSm       = (HICON)classPtr->hIconSm;
1131     wc->hCursor       = (HCURSOR)classPtr->hCursor;
1132     wc->hbrBackground = (HBRUSH)classPtr->hbrBackground;
1133     wc->lpszMenuName  = CLASS_GetMenuNameW( classPtr );
1134     wc->lpszClassName = name;
1135     release_class_ptr( classPtr );
1136
1137     /* We must return the atom of the class here instead of just TRUE. */
1138     return atom;
1139 }
1140
1141
1142 #if 0  /* toolhelp is in kernel, so this cannot work */
1143
1144 /***********************************************************************
1145  *              ClassFirst (TOOLHELP.69)
1146  */
1147 BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
1148 {
1149     TRACE("%p\n",pClassEntry);
1150     pClassEntry->wNext = 1;
1151     return ClassNext16( pClassEntry );
1152 }
1153
1154
1155 /***********************************************************************
1156  *              ClassNext (TOOLHELP.70)
1157  */
1158 BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
1159 {
1160     int i;
1161     CLASS *class = firstClass;
1162
1163     TRACE("%p\n",pClassEntry);
1164
1165     if (!pClassEntry->wNext) return FALSE;
1166     for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
1167     if (!class)
1168     {
1169         pClassEntry->wNext = 0;
1170         return FALSE;
1171     }
1172     pClassEntry->hInst = class->hInstance;
1173     pClassEntry->wNext++;
1174     GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
1175                           sizeof(pClassEntry->szClassName) );
1176     return TRUE;
1177 }
1178 #endif
1179
1180 /* 64bit versions */
1181
1182 #ifdef GetClassLongPtrA
1183 #undef GetClassLongPtrA
1184 #endif
1185
1186 #ifdef GetClassLongPtrW
1187 #undef GetClassLongPtrW
1188 #endif
1189
1190 #ifdef SetClassLongPtrA
1191 #undef SetClassLongPtrA
1192 #endif
1193
1194 #ifdef SetClassLongPtrW
1195 #undef SetClassLongPtrW
1196 #endif
1197
1198 /***********************************************************************
1199  *              GetClassLongPtrA (USER32.@)
1200  */
1201 ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
1202 {
1203     return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1204 }
1205
1206 /***********************************************************************
1207  *              GetClassLongPtrW (USER32.@)
1208  */
1209 ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
1210 {
1211     return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1212 }
1213
1214 /***********************************************************************
1215  *              SetClassLongPtrW (USER32.@)
1216  */
1217 ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
1218 {
1219     return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), TRUE );
1220 }
1221
1222 /***********************************************************************
1223  *              SetClassLongPtrA (USER32.@)
1224  */
1225 ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
1226 {
1227     return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), FALSE );
1228 }