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"
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 /***********************************************************************
40 ATOM
get_int_atom_value( UNICODE_STRING
*name
)
42 const WCHAR
*ptr
= name
->Buffer
;
43 const WCHAR
*end
= ptr
+ name
->Length
/ sizeof(WCHAR
);
46 if (IS_INTRESOURCE(ptr
)) return LOWORD(ptr
);
48 if (*ptr
++ != '#') return 0;
51 if (*ptr
< '0' || *ptr
> '9') return 0;
52 ret
= ret
* 10 + *ptr
++ - '0';
53 if (ret
> 0xffff) return 0;
59 /***********************************************************************
62 static BOOL
is_comctl32_class( const WCHAR
*name
)
64 static const WCHAR
*classesW
[] =
69 L
"msctls_statusbar32",
88 int min
= 0, max
= ARRAY_SIZE( classesW
) - 1;
92 int res
, pos
= (min
+ max
) / 2;
93 if (!(res
= wcsicmp( name
, classesW
[pos
] ))) return TRUE
;
94 if (res
< 0) max
= pos
- 1;
100 static BOOL
is_builtin_class( const WCHAR
*name
)
102 static const WCHAR
*classesW
[] =
109 int min
= 0, max
= ARRAY_SIZE( classesW
) - 1;
113 int res
, pos
= (min
+ max
) / 2;
114 if (!(res
= wcsicmp( name
, classesW
[pos
] ))) return TRUE
;
115 if (res
< 0) max
= pos
- 1;
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
);
146 ret
->nameW
= (WCHAR
*)menu_name
;
147 ret
->nameA
= (char *)menu_name
;
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
);
166 ret
->nameW
= (WCHAR
*)menu_name
;
167 ret
->nameA
= (char *)menu_name
;
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
);
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
);
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
207 const WCHAR
*module
, *ptr
;
208 UNICODE_STRING name_us
;
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
);
221 data
.cbSize
= sizeof(data
);
222 RtlInitUnicodeString(&name_us
, name
);
223 if (RtlFindActivationContextSectionString( 0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
226 init_class_name( ret
, name
);
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
);
242 WCHAR
*combined
= version
->Buffer
;
243 memcpy( combined
, ptr
, offset
* sizeof(WCHAR
) );
244 lstrcpyW( &combined
[offset
], name
);
245 version
->Length
= offset
* sizeof(WCHAR
);
249 if (reg_module
) *reg_module
= hmod
;
250 init_class_name( ret
, ptr
);
254 static void load_uxtheme(void)
256 BOOL (WINAPI
* pIsThemeActive
)(void);
259 uxtheme
= LoadLibraryA("uxtheme.dll");
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
)
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 */
283 /***********************************************************************
284 * RegisterClassA (USER32.@)
286 * Register a window class.
289 * >0: Unique identifier
292 ATOM WINAPI
RegisterClassA( const WNDCLASSA
* wc
) /* [in] Address of structure with class data */
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
;
308 return RegisterClassExA( &wcex
);
312 /***********************************************************************
313 * RegisterClassW (USER32.@)
315 * See RegisterClassA.
317 ATOM WINAPI
RegisterClassW( const WNDCLASSW
* wc
)
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
;
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
;
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
);
356 init_class_name( &name
, (const WCHAR
*)wc
->lpszClassName
);
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
);
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
;
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
);
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 ))
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
;
415 get_versioned_name( className
, &name
, NULL
, FALSE
);
416 ret
= NtUserUnregisterClass( &name
, hInstance
, &menu_name
);
417 if (ret
) free_menu_name( &menu_name
);
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];
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
) );
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
)
520 UINT ret
= GetClassInfoExA( hInstance
, name
, &wcex
);
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
;
539 /***********************************************************************
540 * GetClassInfoW (USER32.@)
542 BOOL WINAPI
GetClassInfoW( HINSTANCE hInstance
, LPCWSTR name
, WNDCLASSW
*wc
)
545 UINT ret
= GetClassInfoExW( hInstance
, name
, &wcex
);
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
;
563 ATOM
get_class_info( HINSTANCE instance
, const WCHAR
*class_name
, WNDCLASSEXW
*info
,
564 UNICODE_STRING
*name_str
, BOOL ansi
)
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
)))
578 BOOL (WINAPI
*pRegisterClassNameW
)( const WCHAR
*class );
579 pRegisterClassNameW
= (void *)GetProcAddress( module
, "RegisterClassNameW" );
581 if (pRegisterClassNameW
)
583 TRACE( "registering %s\n", debugstr_us(&name
) );
584 pRegisterClassNameW( class_name
);
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
) );
597 TRACE( "%s %p -> not found\n", debugstr_w(class_name
), instance
);
598 SetLastError( ERROR_CLASS_DOES_NOT_EXIST
);
602 if (name_str
) *name_str
= name
;
606 /***********************************************************************
607 * GetClassInfoExA (USER32.@)
609 BOOL WINAPI
GetClassInfoExA( HINSTANCE hInstance
, LPCSTR name
, WNDCLASSEXA
*wc
)
613 TRACE("%p %s %p\n", hInstance
, debugstr_a(name
), wc
);
617 SetLastError( ERROR_NOACCESS
);
621 if (!IS_INTRESOURCE(name
))
623 WCHAR nameW
[MAX_ATOM_LEN
+ 1];
624 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, ARRAY_SIZE( nameW
)))
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. */
636 /***********************************************************************
637 * GetClassInfoExW (USER32.@)
639 BOOL WINAPI
GetClassInfoExW( HINSTANCE hInstance
, LPCWSTR name
, WNDCLASSEXW
*wc
)
643 TRACE("%p %s %p\n", hInstance
, debugstr_w(name
), wc
);
647 SetLastError( ERROR_NOACCESS
);
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. */
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
);