ntdll/tests: Adjust test_virtual_unwind() for Win11 results.
[wine.git] / dlls / user32 / class.c
blob0cfdf552a5dbf09abe7fa1b29b9a60c99c8edb8a
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 "user_private.h"
23 #include "controls.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(class);
28 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
30 static inline const char *debugstr_us( const UNICODE_STRING *us )
32 if (!us) return "<null>";
33 return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
37 /***********************************************************************
38 * get_int_atom_value
40 ATOM get_int_atom_value( UNICODE_STRING *name )
42 const WCHAR *ptr = name->Buffer;
43 const WCHAR *end = ptr + name->Length / sizeof(WCHAR);
44 UINT ret = 0;
46 if (IS_INTRESOURCE(ptr)) return LOWORD(ptr);
48 if (*ptr++ != '#') return 0;
49 while (ptr < end)
51 if (*ptr < '0' || *ptr > '9') return 0;
52 ret = ret * 10 + *ptr++ - '0';
53 if (ret > 0xffff) return 0;
55 return ret;
59 /***********************************************************************
60 * is_comctl32_class
62 static BOOL is_comctl32_class( const WCHAR *name )
64 static const WCHAR *classesW[] =
66 L"ComboBoxEx32",
67 L"msctls_hotkey32",
68 L"msctls_progress32",
69 L"msctls_statusbar32",
70 L"msctls_trackbar32",
71 L"msctls_updown32",
72 L"NativeFontCtl",
73 L"ReBarWindow32",
74 L"SysAnimate32",
75 L"SysDateTimePick32",
76 L"SysHeader32",
77 L"SysIPAddress32",
78 L"SysLink",
79 L"SysListView32",
80 L"SysMonthCal32",
81 L"SysPager",
82 L"SysTabControl32",
83 L"SysTreeView32",
84 L"ToolbarWindow32",
85 L"tooltips_class32",
88 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
90 while (min <= max)
92 int res, pos = (min + max) / 2;
93 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
94 if (res < 0) max = pos - 1;
95 else min = pos + 1;
97 return FALSE;
100 static BOOL is_builtin_class( const WCHAR *name )
102 static const WCHAR *classesW[] =
104 L"IME",
105 L"MDIClient",
106 L"Scrollbar",
109 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
111 while (min <= max)
113 int res, pos = (min + max) / 2;
114 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
115 if (res < 0) max = pos - 1;
116 else min = pos + 1;
118 return FALSE;
122 static void init_class_name( UNICODE_STRING *str, const WCHAR *name )
124 if (IS_INTRESOURCE( name ))
126 str->Buffer = (WCHAR *)name;
127 str->Length = str->MaximumLength = 0;
129 else RtlInitUnicodeString( str, name );
132 static BOOL alloc_menu_nameA( struct client_menu_name *ret, const char *menu_name )
134 if (!IS_INTRESOURCE(menu_name))
136 DWORD lenA = strlen( menu_name ) + 1;
137 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, menu_name, lenA, NULL, 0 );
138 ret->nameW = HeapAlloc( GetProcessHeap(), 0, lenA + lenW * sizeof(WCHAR) );
139 if (!ret->nameW) return FALSE;
140 ret->nameA = (char *)(ret->nameW + lenW);
141 MultiByteToWideChar( CP_ACP, 0, menu_name, lenA, ret->nameW, lenW );
142 memcpy( ret->nameA, menu_name, lenA );
144 else
146 ret->nameW = (WCHAR *)menu_name;
147 ret->nameA = (char *)menu_name;
149 return TRUE;
152 static BOOL alloc_menu_nameW( struct client_menu_name *ret, const WCHAR *menu_name )
154 if (!IS_INTRESOURCE(menu_name))
156 DWORD lenW = lstrlenW( menu_name ) + 1;
157 DWORD lenA = WideCharToMultiByte( CP_ACP, 0, menu_name, lenW, NULL, 0, NULL, NULL );
158 ret->nameW = HeapAlloc( GetProcessHeap(), 0, lenA + lenW * sizeof(WCHAR) );
159 if (!ret->nameW) return FALSE;
160 ret->nameA = (char *)(ret->nameW + lenW);
161 memcpy( ret->nameW, menu_name, lenW * sizeof(WCHAR) );
162 WideCharToMultiByte( CP_ACP, 0, menu_name, lenW, ret->nameA, lenA, NULL, NULL );
164 else
166 ret->nameW = (WCHAR *)menu_name;
167 ret->nameA = (char *)menu_name;
169 return TRUE;
172 static void free_menu_name( struct client_menu_name *name )
174 if (!IS_INTRESOURCE(name->nameW)) HeapFree( GetProcessHeap(), 0, name->nameW );
177 static ULONG_PTR set_menu_nameW( HWND hwnd, INT offset, ULONG_PTR newval )
179 struct client_menu_name menu_name;
180 if (!alloc_menu_nameW( &menu_name, (const WCHAR *)newval )) return 0;
181 NtUserSetClassLongPtr( hwnd, offset, (ULONG_PTR)&menu_name, FALSE );
182 free_menu_name( &menu_name );
183 return 0;
186 static ULONG_PTR set_menu_nameA( HWND hwnd, INT offset, ULONG_PTR newval )
188 struct client_menu_name menu_name;
189 if (!alloc_menu_nameA( &menu_name, (const char *)newval )) return 0;
190 NtUserSetClassLongPtr( hwnd, offset, (ULONG_PTR)&menu_name, TRUE );
191 free_menu_name( &menu_name );
192 return 0;
195 static void get_versioned_name( const WCHAR *name, UNICODE_STRING *ret, UNICODE_STRING *version, HMODULE *reg_module )
197 ACTCTX_SECTION_KEYED_DATA data;
198 struct wndclass_redirect_data
200 ULONG size;
201 DWORD res;
202 ULONG name_len;
203 ULONG name_offset;
204 ULONG module_len;
205 ULONG module_offset;
206 } *wndclass;
207 const WCHAR *module, *ptr;
208 UNICODE_STRING name_us;
209 HMODULE hmod;
210 UINT offset = 0;
212 if (reg_module) *reg_module = 0;
213 if (version) version->Length = 0;
215 if (IS_INTRESOURCE( name ) || is_comctl32_class( name ) || is_builtin_class( name ))
217 init_class_name( ret, name );
218 return;
221 data.cbSize = sizeof(data);
222 RtlInitUnicodeString(&name_us, name);
223 if (RtlFindActivationContextSectionString( 0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
224 &name_us, &data ))
226 init_class_name( ret, name );
227 return;
230 wndclass = (struct wndclass_redirect_data *)data.lpData;
231 offset = wndclass->name_len / sizeof(WCHAR) - lstrlenW(name);
233 module = (const WCHAR *)((BYTE *)data.lpSectionBase + wndclass->module_offset);
234 if (!(hmod = GetModuleHandleW( module )))
235 hmod = LoadLibraryW( module );
237 /* Combined name is used to register versioned class name. Base name part will match exactly
238 original class name and won't be reused from context data. */
239 ptr = (const WCHAR *)((BYTE *)wndclass + wndclass->name_offset);
240 if (version)
242 WCHAR *combined = version->Buffer;
243 memcpy( combined, ptr, offset * sizeof(WCHAR) );
244 lstrcpyW( &combined[offset], name );
245 version->Length = offset * sizeof(WCHAR);
246 ptr = combined;
249 if (reg_module) *reg_module = hmod;
250 init_class_name( ret, ptr );
254 static void load_uxtheme(void)
256 BOOL (WINAPI * pIsThemeActive)(void);
257 HMODULE uxtheme;
259 uxtheme = LoadLibraryA("uxtheme.dll");
260 if (uxtheme)
262 pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive");
263 if (!pIsThemeActive || !pIsThemeActive())
264 FreeLibrary(uxtheme);
268 /***********************************************************************
269 * User32InitBuiltinClasses
271 BOOL WINAPI User32InitBuiltinClasses( const struct win_hook_params *params, ULONG size )
273 DWORD layout;
275 GetProcessDefaultLayout( &layout ); /* make sure that process layout is initialized */
277 /* Load uxtheme.dll so that standard scrollbars and dialogs are hooked for theming support */
278 load_uxtheme();
279 return TRUE;
283 /***********************************************************************
284 * RegisterClassA (USER32.@)
286 * Register a window class.
288 * RETURNS
289 * >0: Unique identifier
290 * 0: Failure
292 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
294 WNDCLASSEXA wcex;
296 wcex.cbSize = sizeof(wcex);
297 wcex.style = wc->style;
298 wcex.lpfnWndProc = wc->lpfnWndProc;
299 wcex.cbClsExtra = wc->cbClsExtra;
300 wcex.cbWndExtra = wc->cbWndExtra;
301 wcex.hInstance = wc->hInstance;
302 wcex.hIcon = wc->hIcon;
303 wcex.hCursor = wc->hCursor;
304 wcex.hbrBackground = wc->hbrBackground;
305 wcex.lpszMenuName = wc->lpszMenuName;
306 wcex.lpszClassName = wc->lpszClassName;
307 wcex.hIconSm = 0;
308 return RegisterClassExA( &wcex );
312 /***********************************************************************
313 * RegisterClassW (USER32.@)
315 * See RegisterClassA.
317 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
319 WNDCLASSEXW wcex;
321 wcex.cbSize = sizeof(wcex);
322 wcex.style = wc->style;
323 wcex.lpfnWndProc = wc->lpfnWndProc;
324 wcex.cbClsExtra = wc->cbClsExtra;
325 wcex.cbWndExtra = wc->cbWndExtra;
326 wcex.hInstance = wc->hInstance;
327 wcex.hIcon = wc->hIcon;
328 wcex.hCursor = wc->hCursor;
329 wcex.hbrBackground = wc->hbrBackground;
330 wcex.lpszMenuName = wc->lpszMenuName;
331 wcex.lpszClassName = wc->lpszClassName;
332 wcex.hIconSm = 0;
333 return RegisterClassExW( &wcex );
337 /***********************************************************************
338 * RegisterClassExA (USER32.@)
340 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
342 WCHAR nameW[MAX_ATOM_LEN + 1], combined[MAX_ATOM_LEN + 1];
343 struct client_menu_name menu_name;
344 UNICODE_STRING name, version;
345 ATOM atom;
347 version.Buffer = combined;
348 version.MaximumLength = sizeof(combined);
349 if (!IS_INTRESOURCE(wc->lpszClassName))
351 if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, nameW, MAX_ATOM_LEN + 1 )) return 0;
352 get_versioned_name( nameW, &name, &version, FALSE );
354 else
356 init_class_name( &name, (const WCHAR *)wc->lpszClassName );
357 version.Length = 0;
360 if (!alloc_menu_nameA( &menu_name, wc->lpszMenuName )) return 0;
362 atom = NtUserRegisterClassExWOW( (WNDCLASSEXW *)wc, &name, &version, &menu_name, 0, 1, NULL );
363 if (!atom) free_menu_name( &menu_name );
364 return atom;
368 /***********************************************************************
369 * RegisterClassExW (USER32.@)
371 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
373 WCHAR combined[MAX_ATOM_LEN + 1];
374 struct client_menu_name menu_name;
375 UNICODE_STRING name, version;
376 ATOM atom;
378 version.Buffer = combined;
379 version.MaximumLength = sizeof(combined);
380 get_versioned_name( wc->lpszClassName, &name, &version, FALSE );
382 if (!alloc_menu_nameW( &menu_name, wc->lpszMenuName )) return 0;
384 atom = NtUserRegisterClassExWOW( wc, &name, &version, &menu_name, 0, 0, NULL );
385 if (!atom) free_menu_name( &menu_name );
386 return atom;
390 /***********************************************************************
391 * UnregisterClassA (USER32.@)
393 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
395 if (!IS_INTRESOURCE(className))
397 WCHAR name[MAX_ATOM_LEN + 1];
399 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, name, MAX_ATOM_LEN + 1 ))
400 return FALSE;
401 return UnregisterClassW( name, hInstance );
403 return UnregisterClassW( (LPCWSTR)className, hInstance );
406 /***********************************************************************
407 * UnregisterClassW (USER32.@)
409 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
411 struct client_menu_name menu_name;
412 UNICODE_STRING name;
413 BOOL ret;
415 get_versioned_name( className, &name, NULL, FALSE );
416 ret = NtUserUnregisterClass( &name, hInstance, &menu_name );
417 if (ret) free_menu_name( &menu_name );
418 return ret;
422 /***********************************************************************
423 * GetClassWord (USER32.@)
425 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
427 return NtUserGetClassWord( hwnd, offset );
431 /***********************************************************************
432 * GetClassLongW (USER32.@)
434 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
436 return NtUserGetClassLongW( hwnd, offset );
441 /***********************************************************************
442 * GetClassLongA (USER32.@)
444 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
446 return NtUserGetClassLongA( hwnd, offset );
450 /***********************************************************************
451 * SetClassLongW (USER32.@)
453 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
455 if (offset == GCLP_MENUNAME) return set_menu_nameW( hwnd, offset, newval );
456 return NtUserSetClassLong( hwnd, offset, newval, FALSE );
460 /***********************************************************************
461 * SetClassLongA (USER32.@)
463 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
465 if (offset == GCLP_MENUNAME) return set_menu_nameA( hwnd, offset, newval );
466 return NtUserSetClassLong( hwnd, offset, newval, TRUE );
470 /***********************************************************************
471 * GetClassNameA (USER32.@)
473 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
475 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
476 DWORD len;
478 if (count <= 0) return 0;
479 if (!GetClassNameW( hwnd, tmpbuf, ARRAY_SIZE( tmpbuf ))) return 0;
480 RtlUnicodeToMultiByteN( buffer, count - 1, &len, tmpbuf, lstrlenW(tmpbuf) * sizeof(WCHAR) );
481 buffer[len] = 0;
482 return len;
486 /***********************************************************************
487 * GetClassNameW (USER32.@)
489 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
491 UNICODE_STRING name = { .Buffer = buffer, .MaximumLength = count * sizeof(WCHAR) };
492 return NtUserGetClassName( hwnd, FALSE, &name );
496 /***********************************************************************
497 * RealGetWindowClassA (USER32.@)
499 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
501 return GetClassNameA( hwnd, buffer, count );
505 /***********************************************************************
506 * RealGetWindowClassW (USER32.@)
508 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
510 return GetClassNameW( hwnd, buffer, count );
514 /***********************************************************************
515 * GetClassInfoA (USER32.@)
517 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
519 WNDCLASSEXA wcex;
520 UINT ret = GetClassInfoExA( hInstance, name, &wcex );
522 if (ret)
524 wc->style = wcex.style;
525 wc->lpfnWndProc = wcex.lpfnWndProc;
526 wc->cbClsExtra = wcex.cbClsExtra;
527 wc->cbWndExtra = wcex.cbWndExtra;
528 wc->hInstance = wcex.hInstance;
529 wc->hIcon = wcex.hIcon;
530 wc->hCursor = wcex.hCursor;
531 wc->hbrBackground = wcex.hbrBackground;
532 wc->lpszMenuName = wcex.lpszMenuName;
533 wc->lpszClassName = wcex.lpszClassName;
535 return ret;
539 /***********************************************************************
540 * GetClassInfoW (USER32.@)
542 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
544 WNDCLASSEXW wcex;
545 UINT ret = GetClassInfoExW( hInstance, name, &wcex );
547 if (ret)
549 wc->style = wcex.style;
550 wc->lpfnWndProc = wcex.lpfnWndProc;
551 wc->cbClsExtra = wcex.cbClsExtra;
552 wc->cbWndExtra = wcex.cbWndExtra;
553 wc->hInstance = wcex.hInstance;
554 wc->hIcon = wcex.hIcon;
555 wc->hCursor = wcex.hCursor;
556 wc->hbrBackground = wcex.hbrBackground;
557 wc->lpszMenuName = wcex.lpszMenuName;
558 wc->lpszClassName = wcex.lpszClassName;
560 return ret;
563 ATOM get_class_info( HINSTANCE instance, const WCHAR *class_name, WNDCLASSEXW *info,
564 UNICODE_STRING *name_str, BOOL ansi )
566 UNICODE_STRING name;
567 HMODULE module;
568 ATOM atom;
570 get_versioned_name( class_name, &name, NULL, &module );
572 if (!name_str && !instance) instance = user32_module;
574 while (!(atom = NtUserGetClassInfoEx( instance, &name, info, NULL, ansi )))
576 if (module)
578 BOOL (WINAPI *pRegisterClassNameW)( const WCHAR *class );
579 pRegisterClassNameW = (void *)GetProcAddress( module, "RegisterClassNameW" );
580 module = NULL;
581 if (pRegisterClassNameW)
583 TRACE( "registering %s\n", debugstr_us(&name) );
584 pRegisterClassNameW( class_name );
585 continue;
588 if (IS_INTRESOURCE( class_name )) break;
589 if (!is_comctl32_class( class_name )) break;
590 if (GetModuleHandleW( L"comctl32.dll" )) break;
591 if (!LoadLibraryW( L"comctl32.dll" )) break;
592 TRACE( "%s retrying after loading comctl32\n", debugstr_w(class_name) );
595 if (!atom)
597 TRACE( "%s %p -> not found\n", debugstr_w(class_name), instance );
598 SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
599 return 0;
602 if (name_str) *name_str = name;
603 return atom;
606 /***********************************************************************
607 * GetClassInfoExA (USER32.@)
609 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
611 ATOM atom;
613 TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
615 if (!wc)
617 SetLastError( ERROR_NOACCESS );
618 return FALSE;
621 if (!IS_INTRESOURCE(name))
623 WCHAR nameW[MAX_ATOM_LEN + 1];
624 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE( nameW )))
625 return FALSE;
626 atom = get_class_info( hInstance, nameW, (WNDCLASSEXW *)wc, NULL, TRUE );
628 else atom = get_class_info( hInstance, (const WCHAR *)name, (WNDCLASSEXW *)wc, NULL, TRUE );
629 if (atom) wc->lpszClassName = name;
631 /* We must return the atom of the class here instead of just TRUE. */
632 return atom;
636 /***********************************************************************
637 * GetClassInfoExW (USER32.@)
639 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
641 ATOM atom;
643 TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
645 if (!wc)
647 SetLastError( ERROR_NOACCESS );
648 return FALSE;
651 atom = get_class_info( hInstance, name, wc, NULL, FALSE );
652 if (atom) wc->lpszClassName = name;
654 /* We must return the atom of the class here instead of just TRUE. */
655 return atom;
659 #ifdef _WIN64
661 /* 64bit versions */
663 #undef GetClassLongPtrA
664 #undef GetClassLongPtrW
665 #undef SetClassLongPtrA
666 #undef SetClassLongPtrW
668 /***********************************************************************
669 * GetClassLongPtrA (USER32.@)
671 ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
673 return NtUserGetClassLongPtrA( hwnd, offset );
676 /***********************************************************************
677 * GetClassLongPtrW (USER32.@)
679 ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
681 return NtUserGetClassLongPtrW( hwnd, offset );
684 /***********************************************************************
685 * SetClassLongPtrW (USER32.@)
687 ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
689 if (offset == GCLP_MENUNAME) return set_menu_nameW( hwnd, offset, newval );
690 return NtUserSetClassLongPtr( hwnd, offset, newval, FALSE );
693 /***********************************************************************
694 * SetClassLongPtrA (USER32.@)
696 ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
698 if (offset == GCLP_MENUNAME) return set_menu_nameA( hwnd, offset, newval );
699 return NtUserSetClassLongPtr( hwnd, offset, newval, TRUE );
702 #endif /* _WIN64 */