user32: Automatically load comctl32 when one of its classes is requested.
[wine/wine-gecko.git] / dlls / user32 / class.c
blob349aedf6abc18de885193978ec7b538269ac9225
1 /*
2 * Window classes functions
4 * Copyright 1993, 1996, 2003 Alexandre Julliard
5 * Copyright 1998 Juergen Schmied (jsch)
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include "winerror.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "user_private.h"
37 #include "controls.h"
38 #include "wine/server.h"
39 #include "wine/list.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(class);
44 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
46 typedef struct tagCLASS
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 struct dce *dce; /* Opaque pointer to class DCE */
56 HINSTANCE hInstance; /* Module that created the task */
57 HICON hIcon; /* Default icon */
58 HICON hIconSm; /* Default small icon */
59 HICON hIconSmIntern; /* Internal small icon, derived from hIcon */
60 HCURSOR hCursor; /* Default cursor */
61 HBRUSH hbrBackground; /* Default background */
62 ATOM atomName; /* Name of the class */
63 WCHAR name[MAX_ATOM_LEN + 1];
64 } CLASS;
66 static struct list class_list = LIST_INIT( class_list );
67 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
69 #define CLASS_OTHER_PROCESS ((CLASS *)1)
71 /***********************************************************************
72 * get_class_ptr
74 static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
76 WND *ptr = WIN_GetPtr( hwnd );
78 if (ptr)
80 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class;
81 if (!write_access) return CLASS_OTHER_PROCESS;
83 /* modifying classes in other processes is not allowed */
84 if (ptr == WND_DESKTOP || IsWindow( hwnd ))
86 SetLastError( ERROR_ACCESS_DENIED );
87 return NULL;
90 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
91 return NULL;
95 /***********************************************************************
96 * release_class_ptr
98 static inline void release_class_ptr( CLASS *ptr )
100 USER_Unlock();
104 /***********************************************************************
105 * get_int_atom_value
107 ATOM get_int_atom_value( LPCWSTR name )
109 UINT ret = 0;
111 if (IS_INTRESOURCE(name)) return LOWORD(name);
112 if (*name++ != '#') return 0;
113 while (*name)
115 if (*name < '0' || *name > '9') return 0;
116 ret = ret * 10 + *name++ - '0';
117 if (ret > 0xffff) return 0;
119 return ret;
123 /***********************************************************************
124 * is_comctl32_class
126 static BOOL is_comctl32_class( const WCHAR *name )
128 static const WCHAR classesW[][20] =
130 {'C','o','m','b','o','B','o','x','E','x','3','2',0},
131 {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
132 {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
133 {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
134 {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
135 {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
136 {'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
137 {'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
138 {'S','y','s','A','n','i','m','a','t','e','3','2',0},
139 {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
140 {'S','y','s','H','e','a','d','e','r','3','2',0},
141 {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
142 {'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
143 {'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
144 {'S','y','s','P','a','g','e','r',0},
145 {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
146 {'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
147 {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
148 {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
151 int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1;
153 while (min <= max)
155 int res, pos = (min + max) / 2;
156 if (!(res = strcmpiW( name, classesW[pos] ))) return TRUE;
157 if (res < 0) max = pos - 1;
158 else min = pos + 1;
160 return FALSE;
164 /***********************************************************************
165 * set_server_info
167 * Set class info with the wine server.
169 static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size )
171 BOOL ret;
173 SERVER_START_REQ( set_class_info )
175 req->window = wine_server_user_handle( hwnd );
176 req->extra_offset = -1;
177 switch(offset)
179 case GCW_ATOM:
180 req->flags = SET_CLASS_ATOM;
181 req->atom = LOWORD(newval);
182 break;
183 case GCL_STYLE:
184 req->flags = SET_CLASS_STYLE;
185 req->style = newval;
186 break;
187 case GCL_CBWNDEXTRA:
188 req->flags = SET_CLASS_WINEXTRA;
189 req->win_extra = newval;
190 break;
191 case GCLP_HMODULE:
192 req->flags = SET_CLASS_INSTANCE;
193 req->instance = wine_server_client_ptr( (void *)newval );
194 break;
195 default:
196 assert( offset >= 0 );
197 req->flags = SET_CLASS_EXTRA;
198 req->extra_offset = offset;
199 req->extra_size = size;
200 if ( size == sizeof(LONG) )
202 LONG newlong = newval;
203 memcpy( &req->extra_value, &newlong, sizeof(LONG) );
205 else
206 memcpy( &req->extra_value, &newval, sizeof(LONG_PTR) );
207 break;
209 ret = !wine_server_call_err( req );
211 SERVER_END_REQ;
212 return ret;
216 /***********************************************************************
217 * CLASS_GetMenuNameA
219 * Get the menu name as a ASCII string.
221 static inline LPSTR CLASS_GetMenuNameA( CLASS *classPtr )
223 if (IS_INTRESOURCE(classPtr->menuName)) return (LPSTR)classPtr->menuName;
224 return (LPSTR)(classPtr->menuName + strlenW(classPtr->menuName) + 1);
228 /***********************************************************************
229 * CLASS_GetMenuNameW
231 * Get the menu name as a Unicode string.
233 static inline LPWSTR CLASS_GetMenuNameW( CLASS *classPtr )
235 return classPtr->menuName;
239 /***********************************************************************
240 * CLASS_SetMenuNameA
242 * Set the menu name in a class structure by copying the string.
244 static void CLASS_SetMenuNameA( CLASS *classPtr, LPCSTR name )
246 if (!IS_INTRESOURCE(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
247 if (!IS_INTRESOURCE(name))
249 DWORD lenA = strlen(name) + 1;
250 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, name, lenA, NULL, 0 );
251 classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
252 MultiByteToWideChar( CP_ACP, 0, name, lenA, classPtr->menuName, lenW );
253 memcpy( classPtr->menuName + lenW, name, lenA );
255 else classPtr->menuName = (LPWSTR)name;
259 /***********************************************************************
260 * CLASS_SetMenuNameW
262 * Set the menu name in a class structure by copying the string.
264 static void CLASS_SetMenuNameW( CLASS *classPtr, LPCWSTR name )
266 if (!IS_INTRESOURCE(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
267 if (!IS_INTRESOURCE(name))
269 DWORD lenW = strlenW(name) + 1;
270 DWORD lenA = WideCharToMultiByte( CP_ACP, 0, name, lenW, NULL, 0, NULL, NULL );
271 classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
272 memcpy( classPtr->menuName, name, lenW*sizeof(WCHAR) );
273 WideCharToMultiByte( CP_ACP, 0, name, lenW,
274 (char *)(classPtr->menuName + lenW), lenA, NULL, NULL );
276 else classPtr->menuName = (LPWSTR)name;
280 /***********************************************************************
281 * CLASS_FreeClass
283 * Free a class structure.
285 static void CLASS_FreeClass( CLASS *classPtr )
287 TRACE("%p\n", classPtr);
289 USER_Lock();
291 if (classPtr->dce) free_dce( classPtr->dce, 0 );
292 list_remove( &classPtr->entry );
293 if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
294 DeleteObject( classPtr->hbrBackground );
295 HeapFree( GetProcessHeap(), 0, classPtr->menuName );
296 HeapFree( GetProcessHeap(), 0, classPtr );
297 USER_Unlock();
301 /***********************************************************************
302 * CLASS_FindClass
304 * Return a pointer to the class.
306 static CLASS *CLASS_FindClass( LPCWSTR name, HINSTANCE hinstance )
308 static const WCHAR comctl32W[] = {'c','o','m','c','t','l','3','2','.','d','l','l',0};
309 struct list *ptr;
310 ATOM atom = get_int_atom_value( name );
312 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
314 for (;;)
316 USER_Lock();
318 LIST_FOR_EACH( ptr, &class_list )
320 CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
321 if (atom)
323 if (class->atomName != atom) continue;
325 else
327 if (!name || strcmpiW( class->name, name )) continue;
329 if (!class->local || class->hInstance == hinstance)
331 TRACE("%s %p -> %p\n", debugstr_w(name), hinstance, class);
332 return class;
335 USER_Unlock();
337 if (!is_comctl32_class( name )) break;
338 if (GetModuleHandleW( comctl32W )) break;
339 if (!LoadLibraryW( comctl32W )) break;
340 TRACE( "%s retrying after loading comctl32\n", debugstr_w(name) );
343 TRACE("%s %p -> not found\n", debugstr_w(name), hinstance);
344 return NULL;
348 /***********************************************************************
349 * CLASS_RegisterClass
351 * The real RegisterClass() functionality.
353 static CLASS *CLASS_RegisterClass( LPCWSTR name, HINSTANCE hInstance, BOOL local,
354 DWORD style, INT classExtra, INT winExtra )
356 CLASS *classPtr;
357 BOOL ret;
359 TRACE("name=%s hinst=%p style=0x%x clExtr=0x%x winExtr=0x%x\n",
360 debugstr_w(name), hInstance, style, classExtra, winExtra );
362 /* Fix the extra bytes value */
364 if (classExtra > 40) /* Extra bytes are limited to 40 in Win32 */
365 WARN("Class extra bytes %d is > 40\n", classExtra);
366 if (winExtra > 40) /* Extra bytes are limited to 40 in Win32 */
367 WARN("Win extra bytes %d is > 40\n", winExtra );
369 classPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS) + classExtra );
370 if (!classPtr) return NULL;
372 classPtr->atomName = get_int_atom_value( name );
373 if (!classPtr->atomName && name) strcpyW( classPtr->name, name );
374 else GlobalGetAtomNameW( classPtr->atomName, classPtr->name, sizeof(classPtr->name)/sizeof(WCHAR) );
376 SERVER_START_REQ( create_class )
378 req->local = local;
379 req->style = style;
380 req->instance = wine_server_client_ptr( hInstance );
381 req->extra = classExtra;
382 req->win_extra = winExtra;
383 req->client_ptr = wine_server_client_ptr( classPtr );
384 req->atom = classPtr->atomName;
385 if (!req->atom && name) wine_server_add_data( req, name, strlenW(name) * sizeof(WCHAR) );
386 ret = !wine_server_call_err( req );
387 classPtr->atomName = reply->atom;
389 SERVER_END_REQ;
390 if (!ret)
392 HeapFree( GetProcessHeap(), 0, classPtr );
393 return NULL;
396 classPtr->style = style;
397 classPtr->local = local;
398 classPtr->cbWndExtra = winExtra;
399 classPtr->cbClsExtra = classExtra;
400 classPtr->hInstance = hInstance;
402 /* Other non-null values must be set by caller */
404 USER_Lock();
405 if (local) list_add_head( &class_list, &classPtr->entry );
406 else list_add_tail( &class_list, &classPtr->entry );
407 return classPtr;
411 /***********************************************************************
412 * register_builtin
414 * Register a builtin control class.
415 * This allows having both ASCII and Unicode winprocs for the same class.
417 static void register_builtin( const struct builtin_class_descr *descr )
419 CLASS *classPtr;
421 if (!(classPtr = CLASS_RegisterClass( descr->name, user32_module, FALSE,
422 descr->style, 0, descr->extra ))) return;
424 if (descr->cursor) classPtr->hCursor = LoadCursorA( 0, (LPSTR)descr->cursor );
425 classPtr->hbrBackground = descr->brush;
426 classPtr->winproc = BUILTIN_WINPROC( descr->proc );
427 release_class_ptr( classPtr );
431 /***********************************************************************
432 * register_builtins
434 static BOOL WINAPI register_builtins( INIT_ONCE *once, void *param, void **context )
436 register_builtin( &BUTTON_builtin_class );
437 register_builtin( &COMBO_builtin_class );
438 register_builtin( &COMBOLBOX_builtin_class );
439 register_builtin( &DIALOG_builtin_class );
440 register_builtin( &EDIT_builtin_class );
441 register_builtin( &ICONTITLE_builtin_class );
442 register_builtin( &LISTBOX_builtin_class );
443 register_builtin( &MDICLIENT_builtin_class );
444 register_builtin( &MENU_builtin_class );
445 register_builtin( &SCROLL_builtin_class );
446 register_builtin( &STATIC_builtin_class );
447 return TRUE;
451 /***********************************************************************
452 * register_builtin_classes
454 void register_builtin_classes(void)
456 InitOnceExecuteOnce( &init_once, register_builtins, NULL, NULL );
460 /***********************************************************************
461 * register_desktop_class
463 void register_desktop_class(void)
465 register_builtin( &DESKTOP_builtin_class );
466 register_builtin( &MESSAGE_builtin_class );
470 /***********************************************************************
471 * get_class_winproc
473 WNDPROC get_class_winproc( CLASS *class )
475 return class->winproc;
479 /***********************************************************************
480 * get_class_dce
482 struct dce *get_class_dce( CLASS *class )
484 return class->dce;
488 /***********************************************************************
489 * set_class_dce
491 struct dce *set_class_dce( CLASS *class, struct dce *dce )
493 if (class->dce) return class->dce; /* already set, don't change it */
494 class->dce = dce;
495 return dce;
499 /***********************************************************************
500 * RegisterClassA (USER32.@)
502 * Register a window class.
504 * RETURNS
505 * >0: Unique identifier
506 * 0: Failure
508 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
510 WNDCLASSEXA wcex;
512 wcex.cbSize = sizeof(wcex);
513 wcex.style = wc->style;
514 wcex.lpfnWndProc = wc->lpfnWndProc;
515 wcex.cbClsExtra = wc->cbClsExtra;
516 wcex.cbWndExtra = wc->cbWndExtra;
517 wcex.hInstance = wc->hInstance;
518 wcex.hIcon = wc->hIcon;
519 wcex.hCursor = wc->hCursor;
520 wcex.hbrBackground = wc->hbrBackground;
521 wcex.lpszMenuName = wc->lpszMenuName;
522 wcex.lpszClassName = wc->lpszClassName;
523 wcex.hIconSm = 0;
524 return RegisterClassExA( &wcex );
528 /***********************************************************************
529 * RegisterClassW (USER32.@)
531 * See RegisterClassA.
533 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
535 WNDCLASSEXW wcex;
537 wcex.cbSize = sizeof(wcex);
538 wcex.style = wc->style;
539 wcex.lpfnWndProc = wc->lpfnWndProc;
540 wcex.cbClsExtra = wc->cbClsExtra;
541 wcex.cbWndExtra = wc->cbWndExtra;
542 wcex.hInstance = wc->hInstance;
543 wcex.hIcon = wc->hIcon;
544 wcex.hCursor = wc->hCursor;
545 wcex.hbrBackground = wc->hbrBackground;
546 wcex.lpszMenuName = wc->lpszMenuName;
547 wcex.lpszClassName = wc->lpszClassName;
548 wcex.hIconSm = 0;
549 return RegisterClassExW( &wcex );
553 /***********************************************************************
554 * RegisterClassExA (USER32.@)
556 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
558 ATOM atom;
559 CLASS *classPtr;
560 HINSTANCE instance;
562 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
564 if (wc->cbSize != sizeof(*wc) || wc->cbClsExtra < 0 || wc->cbWndExtra < 0 ||
565 wc->hInstance == user32_module) /* we can't register a class for user32 */
567 SetLastError( ERROR_INVALID_PARAMETER );
568 return 0;
570 if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
572 if (!IS_INTRESOURCE(wc->lpszClassName))
574 WCHAR name[MAX_ATOM_LEN + 1];
576 if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, name, MAX_ATOM_LEN + 1 )) return 0;
577 classPtr = CLASS_RegisterClass( name, instance, !(wc->style & CS_GLOBALCLASS),
578 wc->style, wc->cbClsExtra, wc->cbWndExtra );
580 else
582 classPtr = CLASS_RegisterClass( (LPCWSTR)wc->lpszClassName, instance,
583 !(wc->style & CS_GLOBALCLASS), wc->style,
584 wc->cbClsExtra, wc->cbWndExtra );
586 if (!classPtr) return 0;
587 atom = classPtr->atomName;
589 TRACE("name=%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
590 debugstr_a(wc->lpszClassName), atom, wc->lpfnWndProc, instance, wc->hbrBackground,
591 wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
593 classPtr->hIcon = wc->hIcon;
594 classPtr->hIconSm = wc->hIconSm;
595 classPtr->hIconSmIntern = wc->hIcon && !wc->hIconSm ?
596 CopyImage( wc->hIcon, IMAGE_ICON,
597 GetSystemMetrics( SM_CXSMICON ),
598 GetSystemMetrics( SM_CYSMICON ), 0 ) : NULL;
599 classPtr->hCursor = wc->hCursor;
600 classPtr->hbrBackground = wc->hbrBackground;
601 classPtr->winproc = WINPROC_AllocProc( wc->lpfnWndProc, FALSE );
602 CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
603 release_class_ptr( classPtr );
604 return atom;
608 /***********************************************************************
609 * RegisterClassExW (USER32.@)
611 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
613 ATOM atom;
614 CLASS *classPtr;
615 HINSTANCE instance;
617 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
619 if (wc->cbSize != sizeof(*wc) || wc->cbClsExtra < 0 || wc->cbWndExtra < 0 ||
620 wc->hInstance == user32_module) /* we can't register a class for user32 */
622 SetLastError( ERROR_INVALID_PARAMETER );
623 return 0;
625 if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
627 if (!(classPtr = CLASS_RegisterClass( wc->lpszClassName, instance, !(wc->style & CS_GLOBALCLASS),
628 wc->style, wc->cbClsExtra, wc->cbWndExtra )))
629 return 0;
631 atom = classPtr->atomName;
633 TRACE("name=%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
634 debugstr_w(wc->lpszClassName), atom, wc->lpfnWndProc, instance, wc->hbrBackground,
635 wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
637 classPtr->hIcon = wc->hIcon;
638 classPtr->hIconSm = wc->hIconSm;
639 classPtr->hIconSmIntern = wc->hIcon && !wc->hIconSm ?
640 CopyImage( wc->hIcon, IMAGE_ICON,
641 GetSystemMetrics( SM_CXSMICON ),
642 GetSystemMetrics( SM_CYSMICON ), 0 ) : NULL;
643 classPtr->hCursor = wc->hCursor;
644 classPtr->hbrBackground = wc->hbrBackground;
645 classPtr->winproc = WINPROC_AllocProc( wc->lpfnWndProc, TRUE );
646 CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
647 release_class_ptr( classPtr );
648 return atom;
652 /***********************************************************************
653 * UnregisterClassA (USER32.@)
655 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
657 if (!IS_INTRESOURCE(className))
659 WCHAR name[MAX_ATOM_LEN + 1];
661 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, name, MAX_ATOM_LEN + 1 ))
662 return FALSE;
663 return UnregisterClassW( name, hInstance );
665 return UnregisterClassW( (LPCWSTR)className, hInstance );
668 /***********************************************************************
669 * UnregisterClassW (USER32.@)
671 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
673 CLASS *classPtr = NULL;
675 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
677 SERVER_START_REQ( destroy_class )
679 req->instance = wine_server_client_ptr( hInstance );
680 if (!(req->atom = get_int_atom_value(className)) && className)
681 wine_server_add_data( req, className, strlenW(className) * sizeof(WCHAR) );
682 if (!wine_server_call_err( req )) classPtr = wine_server_get_ptr( reply->client_ptr );
684 SERVER_END_REQ;
686 if (classPtr) CLASS_FreeClass( classPtr );
687 return (classPtr != NULL);
691 /***********************************************************************
692 * GetClassWord (USER32.@)
694 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
696 CLASS *class;
697 WORD retvalue = 0;
699 if (offset < 0) return GetClassLongA( hwnd, offset );
701 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
703 if (class == CLASS_OTHER_PROCESS)
705 SERVER_START_REQ( set_class_info )
707 req->window = wine_server_user_handle( hwnd );
708 req->flags = 0;
709 req->extra_offset = offset;
710 req->extra_size = sizeof(retvalue);
711 if (!wine_server_call_err( req ))
712 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
714 SERVER_END_REQ;
715 return retvalue;
718 if (offset <= class->cbClsExtra - sizeof(WORD))
719 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
720 else
721 SetLastError( ERROR_INVALID_INDEX );
722 release_class_ptr( class );
723 return retvalue;
727 /***********************************************************************
728 * CLASS_GetClassLong
730 * Implementation of GetClassLong(Ptr)A/W
732 static ULONG_PTR CLASS_GetClassLong( HWND hwnd, INT offset, UINT size,
733 BOOL unicode )
735 CLASS *class;
736 ULONG_PTR retvalue = 0;
738 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
740 if (class == CLASS_OTHER_PROCESS)
742 SERVER_START_REQ( set_class_info )
744 req->window = wine_server_user_handle( hwnd );
745 req->flags = 0;
746 req->extra_offset = (offset >= 0) ? offset : -1;
747 req->extra_size = (offset >= 0) ? size : 0;
748 if (!wine_server_call_err( req ))
750 switch(offset)
752 case GCLP_HBRBACKGROUND:
753 case GCLP_HCURSOR:
754 case GCLP_HICON:
755 case GCLP_HICONSM:
756 case GCLP_WNDPROC:
757 case GCLP_MENUNAME:
758 FIXME( "offset %d (%s) not supported on other process window %p\n",
759 offset, SPY_GetClassLongOffsetName(offset), hwnd );
760 SetLastError( ERROR_INVALID_HANDLE );
761 break;
762 case GCL_STYLE:
763 retvalue = reply->old_style;
764 break;
765 case GCL_CBWNDEXTRA:
766 retvalue = reply->old_win_extra;
767 break;
768 case GCL_CBCLSEXTRA:
769 retvalue = reply->old_extra;
770 break;
771 case GCLP_HMODULE:
772 retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
773 break;
774 case GCW_ATOM:
775 retvalue = reply->old_atom;
776 break;
777 default:
778 if (offset >= 0)
780 if (size == sizeof(DWORD))
782 DWORD retdword;
783 memcpy( &retdword, &reply->old_extra_value, sizeof(DWORD) );
784 retvalue = retdword;
786 else
787 memcpy( &retvalue, &reply->old_extra_value,
788 sizeof(ULONG_PTR) );
790 else SetLastError( ERROR_INVALID_INDEX );
791 break;
795 SERVER_END_REQ;
796 return retvalue;
799 if (offset >= 0)
801 if (offset <= class->cbClsExtra - size)
803 if (size == sizeof(DWORD))
805 DWORD retdword;
806 memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) );
807 retvalue = retdword;
809 else
810 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) );
812 else
813 SetLastError( ERROR_INVALID_INDEX );
814 release_class_ptr( class );
815 return retvalue;
818 switch(offset)
820 case GCLP_HBRBACKGROUND:
821 retvalue = (ULONG_PTR)class->hbrBackground;
822 break;
823 case GCLP_HCURSOR:
824 retvalue = (ULONG_PTR)class->hCursor;
825 break;
826 case GCLP_HICON:
827 retvalue = (ULONG_PTR)class->hIcon;
828 break;
829 case GCLP_HICONSM:
830 retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern);
831 break;
832 case GCL_STYLE:
833 retvalue = class->style;
834 break;
835 case GCL_CBWNDEXTRA:
836 retvalue = class->cbWndExtra;
837 break;
838 case GCL_CBCLSEXTRA:
839 retvalue = class->cbClsExtra;
840 break;
841 case GCLP_HMODULE:
842 retvalue = (ULONG_PTR)class->hInstance;
843 break;
844 case GCLP_WNDPROC:
845 retvalue = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
846 break;
847 case GCLP_MENUNAME:
848 retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
849 if (unicode)
850 retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
851 else
852 retvalue = (ULONG_PTR)CLASS_GetMenuNameA( class );
853 break;
854 case GCW_ATOM:
855 retvalue = class->atomName;
856 break;
857 default:
858 SetLastError( ERROR_INVALID_INDEX );
859 break;
861 release_class_ptr( class );
862 return retvalue;
866 /***********************************************************************
867 * GetClassLongW (USER32.@)
869 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
871 return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), TRUE );
876 /***********************************************************************
877 * GetClassLongA (USER32.@)
879 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
881 return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), FALSE );
885 /***********************************************************************
886 * SetClassWord (USER32.@)
888 WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
890 CLASS *class;
891 WORD retval = 0;
893 if (offset < 0) return SetClassLongA( hwnd, offset, (DWORD)newval );
895 if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
897 SERVER_START_REQ( set_class_info )
899 req->window = wine_server_user_handle( hwnd );
900 req->flags = SET_CLASS_EXTRA;
901 req->extra_offset = offset;
902 req->extra_size = sizeof(newval);
903 memcpy( &req->extra_value, &newval, sizeof(newval) );
904 if (!wine_server_call_err( req ))
906 void *ptr = (char *)(class + 1) + offset;
907 memcpy( &retval, ptr, sizeof(retval) );
908 memcpy( ptr, &newval, sizeof(newval) );
911 SERVER_END_REQ;
912 release_class_ptr( class );
913 return retval;
917 /***********************************************************************
918 * CLASS_SetClassLong
920 * Implementation of SetClassLong(Ptr)A/W
922 static ULONG_PTR CLASS_SetClassLong( HWND hwnd, INT offset, LONG_PTR newval,
923 UINT size, BOOL unicode )
925 CLASS *class;
926 ULONG_PTR retval = 0;
928 if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
930 if (offset >= 0)
932 if (set_server_info( hwnd, offset, newval, size ))
934 void *ptr = (char *)(class + 1) + offset;
935 if ( size == sizeof(LONG) )
937 DWORD retdword;
938 LONG newlong = newval;
939 memcpy( &retdword, ptr, sizeof(DWORD) );
940 memcpy( ptr, &newlong, sizeof(LONG) );
941 retval = retdword;
943 else
945 memcpy( &retval, ptr, sizeof(ULONG_PTR) );
946 memcpy( ptr, &newval, sizeof(LONG_PTR) );
950 else switch(offset)
952 case GCLP_MENUNAME:
953 if ( unicode )
954 CLASS_SetMenuNameW( class, (LPCWSTR)newval );
955 else
956 CLASS_SetMenuNameA( class, (LPCSTR)newval );
957 retval = 0; /* Old value is now meaningless anyway */
958 break;
959 case GCLP_WNDPROC:
960 retval = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
961 class->winproc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
962 break;
963 case GCLP_HBRBACKGROUND:
964 retval = (ULONG_PTR)class->hbrBackground;
965 class->hbrBackground = (HBRUSH)newval;
966 break;
967 case GCLP_HCURSOR:
968 retval = (ULONG_PTR)class->hCursor;
969 class->hCursor = (HCURSOR)newval;
970 break;
971 case GCLP_HICON:
972 retval = (ULONG_PTR)class->hIcon;
973 if (retval && class->hIconSmIntern)
975 DestroyIcon(class->hIconSmIntern);
976 class->hIconSmIntern = NULL;
978 if (newval && !class->hIconSm)
979 class->hIconSmIntern = CopyImage( (HICON)newval, IMAGE_ICON,
980 GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
981 class->hIcon = (HICON)newval;
982 break;
983 case GCLP_HICONSM:
984 retval = (ULONG_PTR)class->hIconSm;
985 if (retval && !newval)
986 class->hIconSmIntern = class->hIcon ? CopyImage( class->hIcon, IMAGE_ICON,
987 GetSystemMetrics( SM_CXSMICON ),
988 GetSystemMetrics( SM_CYSMICON ), 0 ) : NULL;
989 else if (!retval && newval && class->hIconSmIntern)
991 DestroyIcon(class->hIconSmIntern);
992 class->hIconSmIntern = NULL;
994 class->hIconSm = (HICON)newval;
995 break;
996 case GCL_STYLE:
997 if (!set_server_info( hwnd, offset, newval, size )) break;
998 retval = class->style;
999 class->style = newval;
1000 break;
1001 case GCL_CBWNDEXTRA:
1002 if (!set_server_info( hwnd, offset, newval, size )) break;
1003 retval = class->cbWndExtra;
1004 class->cbWndExtra = newval;
1005 break;
1006 case GCLP_HMODULE:
1007 if (!set_server_info( hwnd, offset, newval, size )) break;
1008 retval = (ULONG_PTR)class->hInstance;
1009 class->hInstance = (HINSTANCE)newval;
1010 break;
1011 case GCW_ATOM:
1012 if (!set_server_info( hwnd, offset, newval, size )) break;
1013 retval = class->atomName;
1014 class->atomName = newval;
1015 GlobalGetAtomNameW( newval, class->name, sizeof(class->name)/sizeof(WCHAR) );
1016 break;
1017 case GCL_CBCLSEXTRA: /* cannot change this one */
1018 SetLastError( ERROR_INVALID_PARAMETER );
1019 break;
1020 default:
1021 SetLastError( ERROR_INVALID_INDEX );
1022 break;
1024 release_class_ptr( class );
1025 return retval;
1029 /***********************************************************************
1030 * SetClassLongW (USER32.@)
1032 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
1034 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), TRUE );
1038 /***********************************************************************
1039 * SetClassLongA (USER32.@)
1041 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
1043 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), FALSE );
1047 /***********************************************************************
1048 * GetClassNameA (USER32.@)
1050 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
1052 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1053 DWORD len;
1055 if (count <= 0) return 0;
1056 if (!GetClassNameW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
1057 RtlUnicodeToMultiByteN( buffer, count - 1, &len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
1058 buffer[len] = 0;
1059 return len;
1063 /***********************************************************************
1064 * GetClassNameW (USER32.@)
1066 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
1068 CLASS *class;
1069 INT ret;
1071 TRACE("%p %p %d\n", hwnd, buffer, count);
1073 if (count <= 0) return 0;
1075 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
1077 if (class == CLASS_OTHER_PROCESS)
1079 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1081 ret = GlobalGetAtomNameW( GetClassLongW( hwnd, GCW_ATOM ), tmpbuf, MAX_ATOM_LEN + 1 );
1082 if (ret)
1084 ret = min(count - 1, ret);
1085 memcpy(buffer, tmpbuf, ret * sizeof(WCHAR));
1086 buffer[ret] = 0;
1089 else
1091 lstrcpynW( buffer, class->name, count );
1092 release_class_ptr( class );
1093 ret = strlenW( buffer );
1095 return ret;
1099 /***********************************************************************
1100 * RealGetWindowClassA (USER32.@)
1102 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
1104 return GetClassNameA( hwnd, buffer, count );
1108 /***********************************************************************
1109 * RealGetWindowClassW (USER32.@)
1111 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
1113 return GetClassNameW( hwnd, buffer, count );
1117 /***********************************************************************
1118 * GetClassInfoA (USER32.@)
1120 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
1122 WNDCLASSEXA wcex;
1123 UINT ret = GetClassInfoExA( hInstance, name, &wcex );
1125 if (ret)
1127 wc->style = wcex.style;
1128 wc->lpfnWndProc = wcex.lpfnWndProc;
1129 wc->cbClsExtra = wcex.cbClsExtra;
1130 wc->cbWndExtra = wcex.cbWndExtra;
1131 wc->hInstance = wcex.hInstance;
1132 wc->hIcon = wcex.hIcon;
1133 wc->hCursor = wcex.hCursor;
1134 wc->hbrBackground = wcex.hbrBackground;
1135 wc->lpszMenuName = wcex.lpszMenuName;
1136 wc->lpszClassName = wcex.lpszClassName;
1138 return ret;
1142 /***********************************************************************
1143 * GetClassInfoW (USER32.@)
1145 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
1147 WNDCLASSEXW wcex;
1148 UINT ret = GetClassInfoExW( hInstance, name, &wcex );
1150 if (ret)
1152 wc->style = wcex.style;
1153 wc->lpfnWndProc = wcex.lpfnWndProc;
1154 wc->cbClsExtra = wcex.cbClsExtra;
1155 wc->cbWndExtra = wcex.cbWndExtra;
1156 wc->hInstance = wcex.hInstance;
1157 wc->hIcon = wcex.hIcon;
1158 wc->hCursor = wcex.hCursor;
1159 wc->hbrBackground = wcex.hbrBackground;
1160 wc->lpszMenuName = wcex.lpszMenuName;
1161 wc->lpszClassName = wcex.lpszClassName;
1163 return ret;
1167 /***********************************************************************
1168 * GetClassInfoExA (USER32.@)
1170 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
1172 ATOM atom;
1173 CLASS *classPtr;
1175 TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
1177 if (!wc)
1179 SetLastError( ERROR_NOACCESS );
1180 return FALSE;
1183 if (!hInstance) hInstance = user32_module;
1185 if (!IS_INTRESOURCE(name))
1187 WCHAR nameW[MAX_ATOM_LEN + 1];
1188 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ))
1189 return FALSE;
1190 classPtr = CLASS_FindClass( nameW, hInstance );
1192 else classPtr = CLASS_FindClass( (LPCWSTR)name, hInstance );
1194 if (!classPtr)
1196 SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1197 return FALSE;
1199 wc->style = classPtr->style;
1200 wc->lpfnWndProc = WINPROC_GetProc( classPtr->winproc, FALSE );
1201 wc->cbClsExtra = classPtr->cbClsExtra;
1202 wc->cbWndExtra = classPtr->cbWndExtra;
1203 wc->hInstance = (hInstance == user32_module) ? 0 : hInstance;
1204 wc->hIcon = classPtr->hIcon;
1205 wc->hIconSm = classPtr->hIconSm ? classPtr->hIconSm : classPtr->hIconSmIntern;
1206 wc->hCursor = classPtr->hCursor;
1207 wc->hbrBackground = classPtr->hbrBackground;
1208 wc->lpszMenuName = CLASS_GetMenuNameA( classPtr );
1209 wc->lpszClassName = name;
1210 atom = classPtr->atomName;
1211 release_class_ptr( classPtr );
1213 /* We must return the atom of the class here instead of just TRUE. */
1214 return atom;
1218 /***********************************************************************
1219 * GetClassInfoExW (USER32.@)
1221 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
1223 ATOM atom;
1224 CLASS *classPtr;
1226 TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
1228 if (!wc)
1230 SetLastError( ERROR_NOACCESS );
1231 return FALSE;
1234 if (!hInstance) hInstance = user32_module;
1236 if (!(classPtr = CLASS_FindClass( name, hInstance )))
1238 SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1239 return FALSE;
1241 wc->style = classPtr->style;
1242 wc->lpfnWndProc = WINPROC_GetProc( classPtr->winproc, TRUE );
1243 wc->cbClsExtra = classPtr->cbClsExtra;
1244 wc->cbWndExtra = classPtr->cbWndExtra;
1245 wc->hInstance = (hInstance == user32_module) ? 0 : hInstance;
1246 wc->hIcon = classPtr->hIcon;
1247 wc->hIconSm = classPtr->hIconSm ? classPtr->hIconSm : classPtr->hIconSmIntern;
1248 wc->hCursor = classPtr->hCursor;
1249 wc->hbrBackground = classPtr->hbrBackground;
1250 wc->lpszMenuName = CLASS_GetMenuNameW( classPtr );
1251 wc->lpszClassName = name;
1252 atom = classPtr->atomName;
1253 release_class_ptr( classPtr );
1255 /* We must return the atom of the class here instead of just TRUE. */
1256 return atom;
1260 #if 0 /* toolhelp is in kernel, so this cannot work */
1262 /***********************************************************************
1263 * ClassFirst (TOOLHELP.69)
1265 BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
1267 TRACE("%p\n",pClassEntry);
1268 pClassEntry->wNext = 1;
1269 return ClassNext16( pClassEntry );
1273 /***********************************************************************
1274 * ClassNext (TOOLHELP.70)
1276 BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
1278 int i;
1279 CLASS *class = firstClass;
1281 TRACE("%p\n",pClassEntry);
1283 if (!pClassEntry->wNext) return FALSE;
1284 for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
1285 if (!class)
1287 pClassEntry->wNext = 0;
1288 return FALSE;
1290 pClassEntry->hInst = class->hInstance;
1291 pClassEntry->wNext++;
1292 GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
1293 sizeof(pClassEntry->szClassName) );
1294 return TRUE;
1296 #endif
1298 /* 64bit versions */
1300 #ifdef GetClassLongPtrA
1301 #undef GetClassLongPtrA
1302 #endif
1304 #ifdef GetClassLongPtrW
1305 #undef GetClassLongPtrW
1306 #endif
1308 #ifdef SetClassLongPtrA
1309 #undef SetClassLongPtrA
1310 #endif
1312 #ifdef SetClassLongPtrW
1313 #undef SetClassLongPtrW
1314 #endif
1316 /***********************************************************************
1317 * GetClassLongPtrA (USER32.@)
1319 ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
1321 return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1324 /***********************************************************************
1325 * GetClassLongPtrW (USER32.@)
1327 ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
1329 return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1332 /***********************************************************************
1333 * SetClassLongPtrW (USER32.@)
1335 ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
1337 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), TRUE );
1340 /***********************************************************************
1341 * SetClassLongPtrA (USER32.@)
1343 ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
1345 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), FALSE );