user32: Use UNICODE_STRING for passing window classes internally.
[wine.git] / dlls / user32 / class.c
blob5b3243ca8d5efd1ce122bf0b8e54e7947c2b6ce6
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 <assert.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winnls.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "controls.h"
35 #include "wine/server.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(class);
41 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
43 static struct list class_list = LIST_INIT( class_list );
44 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
46 #define CLASS_OTHER_PROCESS ((CLASS *)1)
48 static inline const char *debugstr_us( const UNICODE_STRING *us )
50 if (!us) return "<null>";
51 return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
54 /***********************************************************************
55 * get_class_ptr
57 static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
59 WND *ptr = WIN_GetPtr( hwnd );
61 if (ptr)
63 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class;
64 if (!write_access) return CLASS_OTHER_PROCESS;
66 /* modifying classes in other processes is not allowed */
67 if (ptr == WND_DESKTOP || IsWindow( hwnd ))
69 SetLastError( ERROR_ACCESS_DENIED );
70 return NULL;
73 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
74 return NULL;
78 /***********************************************************************
79 * release_class_ptr
81 static inline void release_class_ptr( CLASS *ptr )
83 USER_Unlock();
87 /***********************************************************************
88 * get_int_atom_value
90 ATOM get_int_atom_value( UNICODE_STRING *name )
92 const WCHAR *ptr = name->Buffer;
93 const WCHAR *end = ptr + name->Length / sizeof(WCHAR);
94 UINT ret = 0;
96 if (IS_INTRESOURCE(ptr)) return LOWORD(ptr);
98 if (*ptr++ != '#') return 0;
99 while (ptr < end)
101 if (*ptr < '0' || *ptr > '9') return 0;
102 ret = ret * 10 + *ptr++ - '0';
103 if (ret > 0xffff) return 0;
105 return ret;
109 /***********************************************************************
110 * is_comctl32_class
112 static BOOL is_comctl32_class( const WCHAR *name )
114 static const WCHAR *classesW[] =
116 L"ComboBoxEx32",
117 L"msctls_hotkey32",
118 L"msctls_progress32",
119 L"msctls_statusbar32",
120 L"msctls_trackbar32",
121 L"msctls_updown32",
122 L"NativeFontCtl",
123 L"ReBarWindow32",
124 L"SysAnimate32",
125 L"SysDateTimePick32",
126 L"SysHeader32",
127 L"SysIPAddress32",
128 L"SysLink",
129 L"SysListView32",
130 L"SysMonthCal32",
131 L"SysPager",
132 L"SysTabControl32",
133 L"SysTreeView32",
134 L"ToolbarWindow32",
135 L"tooltips_class32",
138 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
140 while (min <= max)
142 int res, pos = (min + max) / 2;
143 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
144 if (res < 0) max = pos - 1;
145 else min = pos + 1;
147 return FALSE;
150 static BOOL is_builtin_class( const WCHAR *name )
152 static const WCHAR *classesW[] =
154 L"IME",
155 L"MDIClient",
156 L"Scrollbar",
159 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
161 while (min <= max)
163 int res, pos = (min + max) / 2;
164 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
165 if (res < 0) max = pos - 1;
166 else min = pos + 1;
168 return FALSE;
171 /***********************************************************************
172 * set_server_info
174 * Set class info with the wine server.
176 static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size )
178 BOOL ret;
180 SERVER_START_REQ( set_class_info )
182 req->window = wine_server_user_handle( hwnd );
183 req->extra_offset = -1;
184 switch(offset)
186 case GCW_ATOM:
187 req->flags = SET_CLASS_ATOM;
188 req->atom = LOWORD(newval);
189 break;
190 case GCL_STYLE:
191 req->flags = SET_CLASS_STYLE;
192 req->style = newval;
193 break;
194 case GCL_CBWNDEXTRA:
195 req->flags = SET_CLASS_WINEXTRA;
196 req->win_extra = newval;
197 break;
198 case GCLP_HMODULE:
199 req->flags = SET_CLASS_INSTANCE;
200 req->instance = wine_server_client_ptr( (void *)newval );
201 break;
202 default:
203 assert( offset >= 0 );
204 req->flags = SET_CLASS_EXTRA;
205 req->extra_offset = offset;
206 req->extra_size = size;
207 if ( size == sizeof(LONG) )
209 LONG newlong = newval;
210 memcpy( &req->extra_value, &newlong, sizeof(LONG) );
212 else
213 memcpy( &req->extra_value, &newval, sizeof(LONG_PTR) );
214 break;
216 ret = !wine_server_call_err( req );
218 SERVER_END_REQ;
219 return ret;
223 static void init_class_name( UNICODE_STRING *str, const WCHAR *name )
225 if (IS_INTRESOURCE( name ))
227 str->Buffer = (WCHAR *)name;
228 str->Length = str->MaximumLength = 0;
230 else RtlInitUnicodeString( str, name );
233 /***********************************************************************
234 * CLASS_GetMenuNameA
236 * Get the menu name as an ANSI string.
238 static inline LPSTR CLASS_GetMenuNameA( CLASS *classPtr )
240 if (IS_INTRESOURCE(classPtr->menuName)) return (LPSTR)classPtr->menuName;
241 return (LPSTR)(classPtr->menuName + lstrlenW(classPtr->menuName) + 1);
245 /***********************************************************************
246 * CLASS_GetMenuNameW
248 * Get the menu name as a Unicode string.
250 static inline LPWSTR CLASS_GetMenuNameW( CLASS *classPtr )
252 return classPtr->menuName;
256 /***********************************************************************
257 * CLASS_SetMenuNameA
259 * Set the menu name in a class structure by copying the string.
261 static void CLASS_SetMenuNameA( CLASS *classPtr, LPCSTR name )
263 if (!IS_INTRESOURCE(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
264 if (!IS_INTRESOURCE(name))
266 DWORD lenA = strlen(name) + 1;
267 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, name, lenA, NULL, 0 );
268 classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
269 MultiByteToWideChar( CP_ACP, 0, name, lenA, classPtr->menuName, lenW );
270 memcpy( classPtr->menuName + lenW, name, lenA );
272 else classPtr->menuName = (LPWSTR)name;
275 /***********************************************************************
276 * CLASS_SetMenuNameW
278 * Set the menu name in a class structure by copying the string.
280 static void CLASS_SetMenuNameW( CLASS *classPtr, LPCWSTR name )
282 if (!IS_INTRESOURCE(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
283 if (!IS_INTRESOURCE(name))
285 DWORD lenW = lstrlenW(name) + 1;
286 DWORD lenA = WideCharToMultiByte( CP_ACP, 0, name, lenW, NULL, 0, NULL, NULL );
287 classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
288 memcpy( classPtr->menuName, name, lenW*sizeof(WCHAR) );
289 WideCharToMultiByte( CP_ACP, 0, name, lenW,
290 (char *)(classPtr->menuName + lenW), lenA, NULL, NULL );
292 else classPtr->menuName = (LPWSTR)name;
296 /***********************************************************************
297 * CLASS_FreeClass
299 * Free a class structure.
301 static void CLASS_FreeClass( CLASS *classPtr )
303 TRACE("%p\n", classPtr);
305 USER_Lock();
307 if (classPtr->dce) free_dce( classPtr->dce, 0 );
308 list_remove( &classPtr->entry );
309 if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
310 DeleteObject( classPtr->hbrBackground );
311 DestroyIcon( classPtr->hIconSmIntern );
312 HeapFree( GetProcessHeap(), 0, classPtr->menuName );
313 HeapFree( GetProcessHeap(), 0, classPtr );
314 USER_Unlock();
317 static CLASS *find_class( HINSTANCE module, UNICODE_STRING *name )
319 ATOM atom = get_int_atom_value( name );
320 UINT_PTR instance = (UINT_PTR)module & ~0xffff;
321 CLASS *class;
323 USER_Lock();
324 LIST_FOR_EACH_ENTRY( class, &class_list, CLASS, entry )
326 if (atom)
328 if (class->atomName != atom) continue;
330 else
332 if (wcsnicmp( class->name, name->Buffer, name->Length / sizeof(WCHAR) )) continue;
334 if (!class->local || !module || (class->instance & ~0xffff) == instance)
336 TRACE( "%s %Ix -> %p\n", debugstr_us(name), instance, class );
337 return class;
340 USER_Unlock();
341 return NULL;
344 static void get_versioned_name( const WCHAR *name, UNICODE_STRING *ret, UNICODE_STRING *version, HMODULE *reg_module )
346 ACTCTX_SECTION_KEYED_DATA data;
347 struct wndclass_redirect_data
349 ULONG size;
350 DWORD res;
351 ULONG name_len;
352 ULONG name_offset;
353 ULONG module_len;
354 ULONG module_offset;
355 } *wndclass;
356 const WCHAR *module, *ptr;
357 UNICODE_STRING name_us;
358 HMODULE hmod;
359 UINT offset = 0;
361 if (reg_module) *reg_module = 0;
362 if (version) version->Length = 0;
364 if (IS_INTRESOURCE( name ) || is_comctl32_class( name ) || is_builtin_class( name ))
366 init_class_name( ret, name );
367 return;
370 data.cbSize = sizeof(data);
371 RtlInitUnicodeString(&name_us, name);
372 if (RtlFindActivationContextSectionString( 0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
373 &name_us, &data ))
375 init_class_name( ret, name );
376 return;
379 wndclass = (struct wndclass_redirect_data *)data.lpData;
380 offset = wndclass->name_len / sizeof(WCHAR) - lstrlenW(name);
382 module = (const WCHAR *)((BYTE *)data.lpSectionBase + wndclass->module_offset);
383 if (!(hmod = GetModuleHandleW( module )))
384 hmod = LoadLibraryW( module );
386 /* Combined name is used to register versioned class name. Base name part will match exactly
387 original class name and won't be reused from context data. */
388 ptr = (const WCHAR *)((BYTE *)wndclass + wndclass->name_offset);
389 if (version)
391 WCHAR *combined = version->Buffer;
392 memcpy( combined, ptr, offset * sizeof(WCHAR) );
393 lstrcpyW( &combined[offset], name );
394 version->Length = offset * sizeof(WCHAR);
395 ptr = combined;
398 if (reg_module) *reg_module = hmod;
399 init_class_name( ret, ptr );
402 /***********************************************************************
403 * CLASS_RegisterClass
405 * The real RegisterClass() functionality.
407 static CLASS *CLASS_RegisterClass( UNICODE_STRING *name, UINT basename_offset, HINSTANCE hInstance,
408 BOOL local, DWORD style, INT classExtra, INT winExtra )
410 CLASS *classPtr;
411 BOOL ret;
413 TRACE("name=%s hinst=%p style=0x%x clExtr=0x%x winExtr=0x%x\n",
414 debugstr_us(name), hInstance, style, classExtra, winExtra );
416 /* Fix the extra bytes value */
418 if (classExtra > 40) /* Extra bytes are limited to 40 in Win32 */
419 WARN("Class extra bytes %d is > 40\n", classExtra);
420 if (winExtra > 40) /* Extra bytes are limited to 40 in Win32 */
421 WARN("Win extra bytes %d is > 40\n", winExtra );
423 classPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS) + classExtra );
424 if (!classPtr) return NULL;
426 classPtr->atomName = get_int_atom_value( name );
427 classPtr->basename = classPtr->name;
428 if (!classPtr->atomName && name)
430 memcpy( classPtr->name, name->Buffer, name->Length );
431 classPtr->name[name->Length / sizeof(WCHAR)] = 0;
432 classPtr->basename += basename_offset;
434 else GlobalGetAtomNameW( classPtr->atomName, classPtr->name, ARRAY_SIZE( classPtr->name ));
436 SERVER_START_REQ( create_class )
438 req->local = local;
439 req->style = style;
440 req->instance = wine_server_client_ptr( hInstance );
441 req->extra = classExtra;
442 req->win_extra = winExtra;
443 req->client_ptr = wine_server_client_ptr( classPtr );
444 req->atom = classPtr->atomName;
445 req->name_offset = basename_offset;
446 if (!req->atom && name) wine_server_add_data( req, name->Buffer, name->Length );
447 ret = !wine_server_call_err( req );
448 classPtr->atomName = reply->atom;
450 SERVER_END_REQ;
451 if (!ret)
453 HeapFree( GetProcessHeap(), 0, classPtr );
454 return NULL;
457 classPtr->style = style;
458 classPtr->local = local;
459 classPtr->cbWndExtra = winExtra;
460 classPtr->cbClsExtra = classExtra;
461 classPtr->instance = (UINT_PTR)hInstance;
463 /* Other non-null values must be set by caller */
465 USER_Lock();
466 if (local) list_add_head( &class_list, &classPtr->entry );
467 else list_add_tail( &class_list, &classPtr->entry );
468 return classPtr;
472 /***********************************************************************
473 * register_builtin
475 * Register a builtin control class.
476 * This allows having both ANSI and Unicode winprocs for the same class.
478 static void register_builtin( const struct builtin_class_descr *descr )
480 UNICODE_STRING name;
481 CLASS *classPtr;
482 HCURSOR cursor = 0;
484 if (descr->cursor) cursor = LoadCursorA( 0, (LPSTR)descr->cursor );
486 init_class_name( &name, descr->name );
487 if (!(classPtr = CLASS_RegisterClass( &name, 0, user32_module, FALSE,
488 descr->style, 0, descr->extra )))
490 if (cursor) DestroyCursor( cursor );
491 return;
494 classPtr->hCursor = cursor;
495 classPtr->hbrBackground = descr->brush;
496 classPtr->winproc = BUILTIN_WINPROC( descr->proc );
497 release_class_ptr( classPtr );
500 static void load_uxtheme(void)
502 BOOL (WINAPI * pIsThemeActive)(void);
503 HMODULE uxtheme;
505 uxtheme = LoadLibraryA("uxtheme.dll");
506 if (uxtheme)
508 pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive");
509 if (!pIsThemeActive || !pIsThemeActive())
510 FreeLibrary(uxtheme);
514 /***********************************************************************
515 * register_builtins
517 static BOOL WINAPI register_builtins( INIT_ONCE *once, void *param, void **context )
519 register_builtin( &BUTTON_builtin_class );
520 register_builtin( &COMBO_builtin_class );
521 register_builtin( &COMBOLBOX_builtin_class );
522 register_builtin( &DIALOG_builtin_class );
523 register_builtin( &EDIT_builtin_class );
524 register_builtin( &ICONTITLE_builtin_class );
525 register_builtin( &LISTBOX_builtin_class );
526 register_builtin( &MDICLIENT_builtin_class );
527 register_builtin( &MENU_builtin_class );
528 register_builtin( &SCROLL_builtin_class );
529 register_builtin( &STATIC_builtin_class );
530 register_builtin( &IME_builtin_class );
532 /* Load uxtheme.dll so that standard scrollbars and dialogs are hooked for theming support */
533 load_uxtheme();
534 return TRUE;
538 /***********************************************************************
539 * register_builtin_classes
541 void register_builtin_classes(void)
543 InitOnceExecuteOnce( &init_once, register_builtins, NULL, NULL );
547 /***********************************************************************
548 * register_desktop_class
550 void register_desktop_class(void)
552 register_builtin( &DESKTOP_builtin_class );
553 register_builtin( &MESSAGE_builtin_class );
557 /***********************************************************************
558 * get_class_winproc
560 WNDPROC get_class_winproc( CLASS *class )
562 return class->winproc;
566 /***********************************************************************
567 * get_class_dce
569 struct dce *get_class_dce( CLASS *class )
571 return class->dce;
575 /***********************************************************************
576 * set_class_dce
578 struct dce *set_class_dce( CLASS *class, struct dce *dce )
580 if (class->dce) return class->dce; /* already set, don't change it */
581 class->dce = dce;
582 return dce;
586 /***********************************************************************
587 * RegisterClassA (USER32.@)
589 * Register a window class.
591 * RETURNS
592 * >0: Unique identifier
593 * 0: Failure
595 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
597 WNDCLASSEXA wcex;
599 wcex.cbSize = sizeof(wcex);
600 wcex.style = wc->style;
601 wcex.lpfnWndProc = wc->lpfnWndProc;
602 wcex.cbClsExtra = wc->cbClsExtra;
603 wcex.cbWndExtra = wc->cbWndExtra;
604 wcex.hInstance = wc->hInstance;
605 wcex.hIcon = wc->hIcon;
606 wcex.hCursor = wc->hCursor;
607 wcex.hbrBackground = wc->hbrBackground;
608 wcex.lpszMenuName = wc->lpszMenuName;
609 wcex.lpszClassName = wc->lpszClassName;
610 wcex.hIconSm = 0;
611 return RegisterClassExA( &wcex );
615 /***********************************************************************
616 * RegisterClassW (USER32.@)
618 * See RegisterClassA.
620 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
622 WNDCLASSEXW wcex;
624 wcex.cbSize = sizeof(wcex);
625 wcex.style = wc->style;
626 wcex.lpfnWndProc = wc->lpfnWndProc;
627 wcex.cbClsExtra = wc->cbClsExtra;
628 wcex.cbWndExtra = wc->cbWndExtra;
629 wcex.hInstance = wc->hInstance;
630 wcex.hIcon = wc->hIcon;
631 wcex.hCursor = wc->hCursor;
632 wcex.hbrBackground = wc->hbrBackground;
633 wcex.lpszMenuName = wc->lpszMenuName;
634 wcex.lpszClassName = wc->lpszClassName;
635 wcex.hIconSm = 0;
636 return RegisterClassExW( &wcex );
640 /***********************************************************************
641 * RegisterClassExA (USER32.@)
643 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
645 WCHAR nameW[MAX_ATOM_LEN + 1], combined[MAX_ATOM_LEN + 1];
646 UNICODE_STRING name, version;
647 ATOM atom;
648 CLASS *classPtr;
649 HINSTANCE instance;
651 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
653 if (wc->cbSize != sizeof(*wc) || wc->cbClsExtra < 0 || wc->cbWndExtra < 0 ||
654 wc->hInstance == user32_module) /* we can't register a class for user32 */
656 SetLastError( ERROR_INVALID_PARAMETER );
657 return 0;
659 if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
661 version.Buffer = combined;
662 version.MaximumLength = sizeof(combined);
663 if (!IS_INTRESOURCE(wc->lpszClassName))
665 if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, nameW, MAX_ATOM_LEN + 1 )) return 0;
666 get_versioned_name( nameW, &name, &version, FALSE );
668 else
670 init_class_name( &name, (const WCHAR *)wc->lpszClassName );
671 version.Length = 0;
674 classPtr = CLASS_RegisterClass( &name, version.Length / sizeof(WCHAR), instance, !(wc->style & CS_GLOBALCLASS),
675 wc->style, wc->cbClsExtra, wc->cbWndExtra );
676 if (!classPtr) return 0;
677 atom = classPtr->atomName;
679 TRACE( "name=%s->%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
680 debugstr_a(wc->lpszClassName), debugstr_us(&name), atom, wc->lpfnWndProc,
681 instance, wc->hbrBackground, wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
683 classPtr->hIcon = wc->hIcon;
684 classPtr->hIconSm = wc->hIconSm;
685 classPtr->hIconSmIntern = wc->hIcon && !wc->hIconSm ?
686 CopyImage( wc->hIcon, IMAGE_ICON,
687 GetSystemMetrics( SM_CXSMICON ),
688 GetSystemMetrics( SM_CYSMICON ),
689 LR_COPYFROMRESOURCE ) : NULL;
690 classPtr->hCursor = wc->hCursor;
691 classPtr->hbrBackground = wc->hbrBackground;
692 classPtr->winproc = WINPROC_AllocProc( wc->lpfnWndProc, FALSE );
693 CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
694 release_class_ptr( classPtr );
695 return atom;
699 /***********************************************************************
700 * RegisterClassExW (USER32.@)
702 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
704 WCHAR combined[MAX_ATOM_LEN + 1];
705 UNICODE_STRING name, version;
706 ATOM atom;
707 CLASS *classPtr;
708 HINSTANCE instance;
710 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
712 if (wc->cbSize != sizeof(*wc) || wc->cbClsExtra < 0 || wc->cbWndExtra < 0 ||
713 wc->hInstance == user32_module) /* we can't register a class for user32 */
715 SetLastError( ERROR_INVALID_PARAMETER );
716 return 0;
718 if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
720 version.Buffer = combined;
721 version.MaximumLength = sizeof(combined);
722 get_versioned_name( wc->lpszClassName, &name, &version, FALSE );
723 if (!(classPtr = CLASS_RegisterClass( &name, version.Length / sizeof(WCHAR), instance,
724 !(wc->style & CS_GLOBALCLASS),
725 wc->style, wc->cbClsExtra, wc->cbWndExtra )))
726 return 0;
728 atom = classPtr->atomName;
730 TRACE( "name=%s->%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
731 debugstr_w(wc->lpszClassName), debugstr_us(&name), atom, wc->lpfnWndProc, instance,
732 wc->hbrBackground, wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
734 classPtr->hIcon = wc->hIcon;
735 classPtr->hIconSm = wc->hIconSm;
736 classPtr->hIconSmIntern = wc->hIcon && !wc->hIconSm ?
737 CopyImage( wc->hIcon, IMAGE_ICON,
738 GetSystemMetrics( SM_CXSMICON ),
739 GetSystemMetrics( SM_CYSMICON ),
740 LR_COPYFROMRESOURCE ) : NULL;
741 classPtr->hCursor = wc->hCursor;
742 classPtr->hbrBackground = wc->hbrBackground;
743 classPtr->winproc = WINPROC_AllocProc( wc->lpfnWndProc, TRUE );
744 CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
745 release_class_ptr( classPtr );
746 return atom;
750 /***********************************************************************
751 * UnregisterClassA (USER32.@)
753 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
755 if (!IS_INTRESOURCE(className))
757 WCHAR name[MAX_ATOM_LEN + 1];
759 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, name, MAX_ATOM_LEN + 1 ))
760 return FALSE;
761 return UnregisterClassW( name, hInstance );
763 return UnregisterClassW( (LPCWSTR)className, hInstance );
766 /***********************************************************************
767 * UnregisterClassW (USER32.@)
769 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
771 CLASS *classPtr = NULL;
772 UNICODE_STRING name;
774 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
776 get_versioned_name( className, &name, NULL, FALSE );
777 SERVER_START_REQ( destroy_class )
779 req->instance = wine_server_client_ptr( hInstance );
780 if (!(req->atom = get_int_atom_value(&name)) && name.Length)
781 wine_server_add_data( req, name.Buffer, name.Length );
782 if (!wine_server_call_err( req )) classPtr = wine_server_get_ptr( reply->client_ptr );
784 SERVER_END_REQ;
786 if (classPtr) CLASS_FreeClass( classPtr );
787 return (classPtr != NULL);
791 /***********************************************************************
792 * GetClassWord (USER32.@)
794 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
796 CLASS *class;
797 WORD retvalue = 0;
799 if (offset < 0) return GetClassLongA( hwnd, offset );
801 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
803 if (class == CLASS_OTHER_PROCESS)
805 SERVER_START_REQ( set_class_info )
807 req->window = wine_server_user_handle( hwnd );
808 req->flags = 0;
809 req->extra_offset = offset;
810 req->extra_size = sizeof(retvalue);
811 if (!wine_server_call_err( req ))
812 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
814 SERVER_END_REQ;
815 return retvalue;
818 if (offset <= class->cbClsExtra - sizeof(WORD))
819 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
820 else
821 SetLastError( ERROR_INVALID_INDEX );
822 release_class_ptr( class );
823 return retvalue;
827 /***********************************************************************
828 * CLASS_GetClassLong
830 * Implementation of GetClassLong(Ptr)A/W
832 static ULONG_PTR CLASS_GetClassLong( HWND hwnd, INT offset, UINT size,
833 BOOL unicode )
835 CLASS *class;
836 ULONG_PTR retvalue = 0;
838 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
840 if (class == CLASS_OTHER_PROCESS)
842 SERVER_START_REQ( set_class_info )
844 req->window = wine_server_user_handle( hwnd );
845 req->flags = 0;
846 req->extra_offset = (offset >= 0) ? offset : -1;
847 req->extra_size = (offset >= 0) ? size : 0;
848 if (!wine_server_call_err( req ))
850 switch(offset)
852 case GCLP_HBRBACKGROUND:
853 case GCLP_HCURSOR:
854 case GCLP_HICON:
855 case GCLP_HICONSM:
856 case GCLP_WNDPROC:
857 case GCLP_MENUNAME:
858 FIXME( "offset %d (%s) not supported on other process window %p\n",
859 offset, SPY_GetClassLongOffsetName(offset), hwnd );
860 SetLastError( ERROR_INVALID_HANDLE );
861 break;
862 case GCL_STYLE:
863 retvalue = reply->old_style;
864 break;
865 case GCL_CBWNDEXTRA:
866 retvalue = reply->old_win_extra;
867 break;
868 case GCL_CBCLSEXTRA:
869 retvalue = reply->old_extra;
870 break;
871 case GCLP_HMODULE:
872 retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
873 break;
874 case GCW_ATOM:
875 retvalue = reply->old_atom;
876 break;
877 default:
878 if (offset >= 0)
880 if (size == sizeof(DWORD))
882 DWORD retdword;
883 memcpy( &retdword, &reply->old_extra_value, sizeof(DWORD) );
884 retvalue = retdword;
886 else
887 memcpy( &retvalue, &reply->old_extra_value,
888 sizeof(ULONG_PTR) );
890 else SetLastError( ERROR_INVALID_INDEX );
891 break;
895 SERVER_END_REQ;
896 return retvalue;
899 if (offset >= 0)
901 if (offset <= class->cbClsExtra - size)
903 if (size == sizeof(DWORD))
905 DWORD retdword;
906 memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) );
907 retvalue = retdword;
909 else
910 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) );
912 else
913 SetLastError( ERROR_INVALID_INDEX );
914 release_class_ptr( class );
915 return retvalue;
918 switch(offset)
920 case GCLP_HBRBACKGROUND:
921 retvalue = (ULONG_PTR)class->hbrBackground;
922 break;
923 case GCLP_HCURSOR:
924 retvalue = (ULONG_PTR)class->hCursor;
925 break;
926 case GCLP_HICON:
927 retvalue = (ULONG_PTR)class->hIcon;
928 break;
929 case GCLP_HICONSM:
930 retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern);
931 break;
932 case GCL_STYLE:
933 retvalue = class->style;
934 break;
935 case GCL_CBWNDEXTRA:
936 retvalue = class->cbWndExtra;
937 break;
938 case GCL_CBCLSEXTRA:
939 retvalue = class->cbClsExtra;
940 break;
941 case GCLP_HMODULE:
942 retvalue = class->instance;
943 break;
944 case GCLP_WNDPROC:
945 retvalue = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
946 break;
947 case GCLP_MENUNAME:
948 retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
949 if (unicode)
950 retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
951 else
952 retvalue = (ULONG_PTR)CLASS_GetMenuNameA( class );
953 break;
954 case GCW_ATOM:
955 retvalue = class->atomName;
956 break;
957 default:
958 SetLastError( ERROR_INVALID_INDEX );
959 break;
961 release_class_ptr( class );
962 return retvalue;
966 /***********************************************************************
967 * GetClassLongW (USER32.@)
969 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
971 return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), TRUE );
976 /***********************************************************************
977 * GetClassLongA (USER32.@)
979 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
981 return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), FALSE );
985 /***********************************************************************
986 * SetClassWord (USER32.@)
988 WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
990 CLASS *class;
991 WORD retval = 0;
993 if (offset < 0) return SetClassLongA( hwnd, offset, (DWORD)newval );
995 if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
997 SERVER_START_REQ( set_class_info )
999 req->window = wine_server_user_handle( hwnd );
1000 req->flags = SET_CLASS_EXTRA;
1001 req->extra_offset = offset;
1002 req->extra_size = sizeof(newval);
1003 memcpy( &req->extra_value, &newval, sizeof(newval) );
1004 if (!wine_server_call_err( req ))
1006 void *ptr = (char *)(class + 1) + offset;
1007 memcpy( &retval, ptr, sizeof(retval) );
1008 memcpy( ptr, &newval, sizeof(newval) );
1011 SERVER_END_REQ;
1012 release_class_ptr( class );
1013 return retval;
1017 /***********************************************************************
1018 * CLASS_SetClassLong
1020 * Implementation of SetClassLong(Ptr)A/W
1022 static ULONG_PTR CLASS_SetClassLong( HWND hwnd, INT offset, LONG_PTR newval,
1023 UINT size, BOOL unicode )
1025 CLASS *class;
1026 ULONG_PTR retval = 0;
1028 if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
1030 if (offset >= 0)
1032 if (set_server_info( hwnd, offset, newval, size ))
1034 void *ptr = (char *)(class + 1) + offset;
1035 if ( size == sizeof(LONG) )
1037 DWORD retdword;
1038 LONG newlong = newval;
1039 memcpy( &retdword, ptr, sizeof(DWORD) );
1040 memcpy( ptr, &newlong, sizeof(LONG) );
1041 retval = retdword;
1043 else
1045 memcpy( &retval, ptr, sizeof(ULONG_PTR) );
1046 memcpy( ptr, &newval, sizeof(LONG_PTR) );
1050 else switch(offset)
1052 case GCLP_MENUNAME:
1053 if ( unicode )
1054 CLASS_SetMenuNameW( class, (LPCWSTR)newval );
1055 else
1056 CLASS_SetMenuNameA( class, (LPCSTR)newval );
1057 retval = 0; /* Old value is now meaningless anyway */
1058 break;
1059 case GCLP_WNDPROC:
1060 retval = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
1061 class->winproc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
1062 break;
1063 case GCLP_HBRBACKGROUND:
1064 retval = (ULONG_PTR)class->hbrBackground;
1065 class->hbrBackground = (HBRUSH)newval;
1066 break;
1067 case GCLP_HCURSOR:
1068 retval = (ULONG_PTR)class->hCursor;
1069 class->hCursor = (HCURSOR)newval;
1070 break;
1071 case GCLP_HICON:
1072 retval = (ULONG_PTR)class->hIcon;
1073 if (class->hIconSmIntern)
1075 DestroyIcon(class->hIconSmIntern);
1076 class->hIconSmIntern = NULL;
1078 if (newval && !class->hIconSm)
1079 class->hIconSmIntern = CopyImage( (HICON)newval, IMAGE_ICON,
1080 GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
1081 LR_COPYFROMRESOURCE );
1082 class->hIcon = (HICON)newval;
1083 break;
1084 case GCLP_HICONSM:
1085 retval = (ULONG_PTR)class->hIconSm;
1086 if (retval && !newval && class->hIcon)
1087 class->hIconSmIntern = CopyImage( class->hIcon, IMAGE_ICON,
1088 GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
1089 LR_COPYFROMRESOURCE );
1090 else if (newval && class->hIconSmIntern)
1092 DestroyIcon(class->hIconSmIntern);
1093 class->hIconSmIntern = NULL;
1095 class->hIconSm = (HICON)newval;
1096 break;
1097 case GCL_STYLE:
1098 if (!set_server_info( hwnd, offset, newval, size )) break;
1099 retval = class->style;
1100 class->style = newval;
1101 break;
1102 case GCL_CBWNDEXTRA:
1103 if (!set_server_info( hwnd, offset, newval, size )) break;
1104 retval = class->cbWndExtra;
1105 class->cbWndExtra = newval;
1106 break;
1107 case GCLP_HMODULE:
1108 if (!set_server_info( hwnd, offset, newval, size )) break;
1109 retval = class->instance;
1110 class->instance = newval;
1111 break;
1112 case GCW_ATOM:
1113 if (!set_server_info( hwnd, offset, newval, size )) break;
1114 retval = class->atomName;
1115 class->atomName = newval;
1116 GlobalGetAtomNameW( newval, class->name, ARRAY_SIZE( class->name ));
1117 break;
1118 case GCL_CBCLSEXTRA: /* cannot change this one */
1119 SetLastError( ERROR_INVALID_PARAMETER );
1120 break;
1121 default:
1122 SetLastError( ERROR_INVALID_INDEX );
1123 break;
1125 release_class_ptr( class );
1126 return retval;
1130 /***********************************************************************
1131 * SetClassLongW (USER32.@)
1133 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
1135 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), TRUE );
1139 /***********************************************************************
1140 * SetClassLongA (USER32.@)
1142 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
1144 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), FALSE );
1148 /***********************************************************************
1149 * GetClassNameA (USER32.@)
1151 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
1153 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1154 DWORD len;
1156 if (count <= 0) return 0;
1157 if (!GetClassNameW( hwnd, tmpbuf, ARRAY_SIZE( tmpbuf ))) return 0;
1158 RtlUnicodeToMultiByteN( buffer, count - 1, &len, tmpbuf, lstrlenW(tmpbuf) * sizeof(WCHAR) );
1159 buffer[len] = 0;
1160 return len;
1164 /***********************************************************************
1165 * GetClassNameW (USER32.@)
1167 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
1169 UNICODE_STRING name = { .Buffer = buffer, .MaximumLength = count * sizeof(WCHAR) };
1170 return NtUserGetClassName( hwnd, FALSE, &name );
1174 /***********************************************************************
1175 * RealGetWindowClassA (USER32.@)
1177 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
1179 return GetClassNameA( hwnd, buffer, count );
1183 /***********************************************************************
1184 * RealGetWindowClassW (USER32.@)
1186 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
1188 return GetClassNameW( hwnd, buffer, count );
1192 /***********************************************************************
1193 * GetClassInfoA (USER32.@)
1195 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
1197 WNDCLASSEXA wcex;
1198 UINT ret = GetClassInfoExA( hInstance, name, &wcex );
1200 if (ret)
1202 wc->style = wcex.style;
1203 wc->lpfnWndProc = wcex.lpfnWndProc;
1204 wc->cbClsExtra = wcex.cbClsExtra;
1205 wc->cbWndExtra = wcex.cbWndExtra;
1206 wc->hInstance = wcex.hInstance;
1207 wc->hIcon = wcex.hIcon;
1208 wc->hCursor = wcex.hCursor;
1209 wc->hbrBackground = wcex.hbrBackground;
1210 wc->lpszMenuName = wcex.lpszMenuName;
1211 wc->lpszClassName = wcex.lpszClassName;
1213 return ret;
1217 /***********************************************************************
1218 * GetClassInfoW (USER32.@)
1220 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
1222 WNDCLASSEXW wcex;
1223 UINT ret = GetClassInfoExW( hInstance, name, &wcex );
1225 if (ret)
1227 wc->style = wcex.style;
1228 wc->lpfnWndProc = wcex.lpfnWndProc;
1229 wc->cbClsExtra = wcex.cbClsExtra;
1230 wc->cbWndExtra = wcex.cbWndExtra;
1231 wc->hInstance = wcex.hInstance;
1232 wc->hIcon = wcex.hIcon;
1233 wc->hCursor = wcex.hCursor;
1234 wc->hbrBackground = wcex.hbrBackground;
1235 wc->lpszMenuName = wcex.lpszMenuName;
1236 wc->lpszClassName = wcex.lpszClassName;
1238 return ret;
1241 ATOM get_class_info( HINSTANCE instance, const WCHAR *class_name, WNDCLASSEXW *info,
1242 UNICODE_STRING *name_str, BOOL ansi )
1244 UNICODE_STRING name;
1245 HMODULE module;
1246 CLASS *class;
1247 ATOM atom;
1249 get_versioned_name( class_name, &name, NULL, &module );
1251 if (!name_str && !instance) instance = user32_module;
1253 if (name.Buffer != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1254 (IS_INTRESOURCE(name.Buffer) || name.Length != sizeof(L"Message") ||
1255 wcsnicmp( name.Buffer, L"Message", ARRAYSIZE(L"Message") )))
1256 GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
1258 while (class_name && !(class = find_class( instance, &name )))
1260 if (module)
1262 BOOL (WINAPI *pRegisterClassNameW)( const WCHAR *class );
1263 pRegisterClassNameW = (void *)GetProcAddress( module, "RegisterClassNameW" );
1264 module = NULL;
1265 if (pRegisterClassNameW)
1267 TRACE( "registering %s\n", debugstr_us(&name) );
1268 pRegisterClassNameW( class_name );
1269 continue;
1272 if (IS_INTRESOURCE( class_name )) break;
1273 if (!is_comctl32_class( class_name )) break;
1274 if (GetModuleHandleW( L"comctl32.dll" )) break;
1275 if (!LoadLibraryW( L"comctl32.dll" )) break;
1276 TRACE( "%s retrying after loading comctl32\n", debugstr_w(class_name) );
1279 if (!class)
1281 TRACE("%s %p -> not found\n", debugstr_w(class_name), instance);
1282 SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
1283 return 0;
1286 if (info)
1288 info->style = class->style;
1289 info->lpfnWndProc = WINPROC_GetProc( class->winproc, !ansi );
1290 info->cbClsExtra = class->cbClsExtra;
1291 info->cbWndExtra = class->cbWndExtra;
1292 info->hInstance = (instance == user32_module) ? 0 : instance;
1293 info->hIcon = class->hIcon;
1294 info->hIconSm = class->hIconSm ? class->hIconSm : class->hIconSmIntern;
1295 info->hCursor = class->hCursor;
1296 info->hbrBackground = class->hbrBackground;
1297 info->lpszMenuName = ansi ? (const WCHAR *)CLASS_GetMenuNameA( class )
1298 : CLASS_GetMenuNameW( class );
1299 info->lpszClassName = class_name;
1302 if (name_str) *name_str = name;
1303 atom = class->atomName;
1304 release_class_ptr( class );
1305 return atom;
1308 /***********************************************************************
1309 * GetClassInfoExA (USER32.@)
1311 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
1313 ATOM atom;
1315 TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
1317 if (!wc)
1319 SetLastError( ERROR_NOACCESS );
1320 return FALSE;
1323 if (!IS_INTRESOURCE(name))
1325 WCHAR nameW[MAX_ATOM_LEN + 1];
1326 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE( nameW )))
1327 return FALSE;
1328 atom = get_class_info( hInstance, nameW, (WNDCLASSEXW *)wc, NULL, TRUE );
1330 else atom = get_class_info( hInstance, (const WCHAR *)name, (WNDCLASSEXW *)wc, NULL, TRUE );
1331 if (atom) wc->lpszClassName = name;
1333 /* We must return the atom of the class here instead of just TRUE. */
1334 return atom;
1338 /***********************************************************************
1339 * GetClassInfoExW (USER32.@)
1341 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
1343 TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
1345 if (!wc)
1347 SetLastError( ERROR_NOACCESS );
1348 return FALSE;
1351 return get_class_info( hInstance, name, wc, NULL, FALSE );
1355 #if 0 /* toolhelp is in kernel, so this cannot work */
1357 /***********************************************************************
1358 * ClassFirst (TOOLHELP.69)
1360 BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
1362 TRACE("%p\n",pClassEntry);
1363 pClassEntry->wNext = 1;
1364 return ClassNext16( pClassEntry );
1368 /***********************************************************************
1369 * ClassNext (TOOLHELP.70)
1371 BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
1373 int i;
1374 CLASS *class = firstClass;
1376 TRACE("%p\n",pClassEntry);
1378 if (!pClassEntry->wNext) return FALSE;
1379 for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
1380 if (!class)
1382 pClassEntry->wNext = 0;
1383 return FALSE;
1385 pClassEntry->hInst = class->hInstance;
1386 pClassEntry->wNext++;
1387 GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
1388 sizeof(pClassEntry->szClassName) );
1389 return TRUE;
1391 #endif
1393 /* 64bit versions */
1395 #ifdef GetClassLongPtrA
1396 #undef GetClassLongPtrA
1397 #endif
1399 #ifdef GetClassLongPtrW
1400 #undef GetClassLongPtrW
1401 #endif
1403 #ifdef SetClassLongPtrA
1404 #undef SetClassLongPtrA
1405 #endif
1407 #ifdef SetClassLongPtrW
1408 #undef SetClassLongPtrW
1409 #endif
1411 /***********************************************************************
1412 * GetClassLongPtrA (USER32.@)
1414 ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
1416 return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1419 /***********************************************************************
1420 * GetClassLongPtrW (USER32.@)
1422 ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
1424 return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1427 /***********************************************************************
1428 * SetClassLongPtrW (USER32.@)
1430 ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
1432 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), TRUE );
1435 /***********************************************************************
1436 * SetClassLongPtrA (USER32.@)
1438 ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
1440 return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), FALSE );