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
23 #define WIN32_NO_STATUS
24 #include "user_private.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(class);
30 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
32 static inline const char *debugstr_us( const UNICODE_STRING
*us
)
34 if (!us
) return "<null>";
35 return debugstr_wn( us
->Buffer
, us
->Length
/ sizeof(WCHAR
) );
39 /***********************************************************************
42 ATOM
get_int_atom_value( UNICODE_STRING
*name
)
44 const WCHAR
*ptr
= name
->Buffer
;
45 const WCHAR
*end
= ptr
+ name
->Length
/ sizeof(WCHAR
);
48 if (IS_INTRESOURCE(ptr
)) return LOWORD(ptr
);
50 if (*ptr
++ != '#') return 0;
53 if (*ptr
< '0' || *ptr
> '9') return 0;
54 ret
= ret
* 10 + *ptr
++ - '0';
55 if (ret
> 0xffff) return 0;
61 /***********************************************************************
64 static BOOL
is_comctl32_class( const WCHAR
*name
)
66 static const WCHAR
*classesW
[] =
71 L
"msctls_statusbar32",
90 int min
= 0, max
= ARRAY_SIZE( classesW
) - 1;
94 int res
, pos
= (min
+ max
) / 2;
95 if (!(res
= wcsicmp( name
, classesW
[pos
] ))) return TRUE
;
96 if (res
< 0) max
= pos
- 1;
102 static BOOL
is_builtin_class( const WCHAR
*name
)
104 static const WCHAR
*classesW
[] =
111 int min
= 0, max
= ARRAY_SIZE( classesW
) - 1;
115 int res
, pos
= (min
+ max
) / 2;
116 if (!(res
= wcsicmp( name
, classesW
[pos
] ))) return TRUE
;
117 if (res
< 0) max
= pos
- 1;
124 static void init_class_name( UNICODE_STRING
*str
, const WCHAR
*name
)
126 if (IS_INTRESOURCE( name
))
128 str
->Buffer
= (WCHAR
*)name
;
129 str
->Length
= str
->MaximumLength
= 0;
131 else RtlInitUnicodeString( str
, name
);
134 static BOOL
alloc_menu_nameA( struct client_menu_name
*ret
, const char *menu_name
)
136 if (!IS_INTRESOURCE(menu_name
))
138 DWORD lenA
= strlen( menu_name
) + 1;
139 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, menu_name
, lenA
, NULL
, 0 );
140 ret
->nameW
= HeapAlloc( GetProcessHeap(), 0, lenA
+ lenW
* sizeof(WCHAR
) );
141 if (!ret
->nameW
) return FALSE
;
142 ret
->nameA
= (char *)(ret
->nameW
+ lenW
);
143 MultiByteToWideChar( CP_ACP
, 0, menu_name
, lenA
, ret
->nameW
, lenW
);
144 memcpy( ret
->nameA
, menu_name
, lenA
);
148 ret
->nameW
= (WCHAR
*)menu_name
;
149 ret
->nameA
= (char *)menu_name
;
154 static BOOL
alloc_menu_nameW( struct client_menu_name
*ret
, const WCHAR
*menu_name
)
156 if (!IS_INTRESOURCE(menu_name
))
158 DWORD lenW
= lstrlenW( menu_name
) + 1;
159 DWORD lenA
= WideCharToMultiByte( CP_ACP
, 0, menu_name
, lenW
, NULL
, 0, NULL
, NULL
);
160 ret
->nameW
= HeapAlloc( GetProcessHeap(), 0, lenA
+ lenW
* sizeof(WCHAR
) );
161 if (!ret
->nameW
) return FALSE
;
162 ret
->nameA
= (char *)(ret
->nameW
+ lenW
);
163 memcpy( ret
->nameW
, menu_name
, lenW
* sizeof(WCHAR
) );
164 WideCharToMultiByte( CP_ACP
, 0, menu_name
, lenW
, ret
->nameA
, lenA
, NULL
, NULL
);
168 ret
->nameW
= (WCHAR
*)menu_name
;
169 ret
->nameA
= (char *)menu_name
;
174 static void free_menu_name( struct client_menu_name
*name
)
176 if (!IS_INTRESOURCE(name
->nameW
)) HeapFree( GetProcessHeap(), 0, name
->nameW
);
179 static ULONG_PTR
set_menu_nameW( HWND hwnd
, INT offset
, ULONG_PTR newval
)
181 struct client_menu_name menu_name
;
182 if (!alloc_menu_nameW( &menu_name
, (const WCHAR
*)newval
)) return 0;
183 NtUserSetClassLongPtr( hwnd
, offset
, (ULONG_PTR
)&menu_name
, FALSE
);
184 free_menu_name( &menu_name
);
188 static ULONG_PTR
set_menu_nameA( HWND hwnd
, INT offset
, ULONG_PTR newval
)
190 struct client_menu_name menu_name
;
191 if (!alloc_menu_nameA( &menu_name
, (const char *)newval
)) return 0;
192 NtUserSetClassLongPtr( hwnd
, offset
, (ULONG_PTR
)&menu_name
, TRUE
);
193 free_menu_name( &menu_name
);
197 static void get_versioned_name( const WCHAR
*name
, UNICODE_STRING
*ret
, UNICODE_STRING
*version
, HMODULE
*reg_module
)
199 ACTCTX_SECTION_KEYED_DATA data
;
200 struct wndclass_redirect_data
209 const WCHAR
*module
, *ptr
;
210 UNICODE_STRING name_us
;
214 if (reg_module
) *reg_module
= 0;
215 if (version
) version
->Length
= 0;
217 if (IS_INTRESOURCE( name
) || is_comctl32_class( name
) || is_builtin_class( name
))
219 init_class_name( ret
, name
);
223 data
.cbSize
= sizeof(data
);
224 RtlInitUnicodeString(&name_us
, name
);
225 if (RtlFindActivationContextSectionString( 0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
228 init_class_name( ret
, name
);
232 wndclass
= (struct wndclass_redirect_data
*)data
.lpData
;
233 offset
= wndclass
->name_len
/ sizeof(WCHAR
) - lstrlenW(name
);
235 module
= (const WCHAR
*)((BYTE
*)data
.lpSectionBase
+ wndclass
->module_offset
);
236 if (!(hmod
= GetModuleHandleW( module
)))
237 hmod
= LoadLibraryW( module
);
239 /* Combined name is used to register versioned class name. Base name part will match exactly
240 original class name and won't be reused from context data. */
241 ptr
= (const WCHAR
*)((BYTE
*)wndclass
+ wndclass
->name_offset
);
244 WCHAR
*combined
= version
->Buffer
;
245 memcpy( combined
, ptr
, offset
* sizeof(WCHAR
) );
246 lstrcpyW( &combined
[offset
], name
);
247 version
->Length
= offset
* sizeof(WCHAR
);
251 if (reg_module
) *reg_module
= hmod
;
252 init_class_name( ret
, ptr
);
256 static void load_uxtheme(void)
258 BOOL (WINAPI
* pIsThemeActive
)(void);
261 uxtheme
= LoadLibraryA("uxtheme.dll");
264 pIsThemeActive
= (void *)GetProcAddress(uxtheme
, "IsThemeActive");
265 if (!pIsThemeActive
|| !pIsThemeActive())
266 FreeLibrary(uxtheme
);
270 /***********************************************************************
271 * User32InitBuiltinClasses
273 NTSTATUS WINAPI
User32InitBuiltinClasses( void *args
, ULONG size
)
277 GetProcessDefaultLayout( &layout
); /* make sure that process layout is initialized */
279 /* Load uxtheme.dll so that standard scrollbars and dialogs are hooked for theming support */
281 return STATUS_SUCCESS
;
285 /***********************************************************************
286 * RegisterClassA (USER32.@)
288 * Register a window class.
291 * >0: Unique identifier
294 ATOM WINAPI
RegisterClassA( const WNDCLASSA
* wc
) /* [in] Address of structure with class data */
298 wcex
.cbSize
= sizeof(wcex
);
299 wcex
.style
= wc
->style
;
300 wcex
.lpfnWndProc
= wc
->lpfnWndProc
;
301 wcex
.cbClsExtra
= wc
->cbClsExtra
;
302 wcex
.cbWndExtra
= wc
->cbWndExtra
;
303 wcex
.hInstance
= wc
->hInstance
;
304 wcex
.hIcon
= wc
->hIcon
;
305 wcex
.hCursor
= wc
->hCursor
;
306 wcex
.hbrBackground
= wc
->hbrBackground
;
307 wcex
.lpszMenuName
= wc
->lpszMenuName
;
308 wcex
.lpszClassName
= wc
->lpszClassName
;
310 return RegisterClassExA( &wcex
);
314 /***********************************************************************
315 * RegisterClassW (USER32.@)
317 * See RegisterClassA.
319 ATOM WINAPI
RegisterClassW( const WNDCLASSW
* wc
)
323 wcex
.cbSize
= sizeof(wcex
);
324 wcex
.style
= wc
->style
;
325 wcex
.lpfnWndProc
= wc
->lpfnWndProc
;
326 wcex
.cbClsExtra
= wc
->cbClsExtra
;
327 wcex
.cbWndExtra
= wc
->cbWndExtra
;
328 wcex
.hInstance
= wc
->hInstance
;
329 wcex
.hIcon
= wc
->hIcon
;
330 wcex
.hCursor
= wc
->hCursor
;
331 wcex
.hbrBackground
= wc
->hbrBackground
;
332 wcex
.lpszMenuName
= wc
->lpszMenuName
;
333 wcex
.lpszClassName
= wc
->lpszClassName
;
335 return RegisterClassExW( &wcex
);
339 /***********************************************************************
340 * RegisterClassExA (USER32.@)
342 ATOM WINAPI
RegisterClassExA( const WNDCLASSEXA
* wc
)
344 WCHAR nameW
[MAX_ATOM_LEN
+ 1], combined
[MAX_ATOM_LEN
+ 1];
345 struct client_menu_name menu_name
;
346 UNICODE_STRING name
, version
;
349 version
.Buffer
= combined
;
350 version
.MaximumLength
= sizeof(combined
);
351 if (!IS_INTRESOURCE(wc
->lpszClassName
))
353 if (!MultiByteToWideChar( CP_ACP
, 0, wc
->lpszClassName
, -1, nameW
, MAX_ATOM_LEN
+ 1 )) return 0;
354 get_versioned_name( nameW
, &name
, &version
, FALSE
);
358 init_class_name( &name
, (const WCHAR
*)wc
->lpszClassName
);
362 if (!alloc_menu_nameA( &menu_name
, wc
->lpszMenuName
)) return 0;
364 atom
= NtUserRegisterClassExWOW( (WNDCLASSEXW
*)wc
, &name
, &version
, &menu_name
, 0, 1, NULL
);
365 if (!atom
) free_menu_name( &menu_name
);
370 /***********************************************************************
371 * RegisterClassExW (USER32.@)
373 ATOM WINAPI
RegisterClassExW( const WNDCLASSEXW
* wc
)
375 WCHAR combined
[MAX_ATOM_LEN
+ 1];
376 struct client_menu_name menu_name
;
377 UNICODE_STRING name
, version
;
380 version
.Buffer
= combined
;
381 version
.MaximumLength
= sizeof(combined
);
382 get_versioned_name( wc
->lpszClassName
, &name
, &version
, FALSE
);
384 if (!alloc_menu_nameW( &menu_name
, wc
->lpszMenuName
)) return 0;
386 atom
= NtUserRegisterClassExWOW( wc
, &name
, &version
, &menu_name
, 0, 0, NULL
);
387 if (!atom
) free_menu_name( &menu_name
);
392 /***********************************************************************
393 * UnregisterClassA (USER32.@)
395 BOOL WINAPI
UnregisterClassA( LPCSTR className
, HINSTANCE hInstance
)
397 if (!IS_INTRESOURCE(className
))
399 WCHAR name
[MAX_ATOM_LEN
+ 1];
401 if (!MultiByteToWideChar( CP_ACP
, 0, className
, -1, name
, MAX_ATOM_LEN
+ 1 ))
403 return UnregisterClassW( name
, hInstance
);
405 return UnregisterClassW( (LPCWSTR
)className
, hInstance
);
408 /***********************************************************************
409 * UnregisterClassW (USER32.@)
411 BOOL WINAPI
UnregisterClassW( LPCWSTR className
, HINSTANCE hInstance
)
413 struct client_menu_name menu_name
;
417 get_versioned_name( className
, &name
, NULL
, FALSE
);
418 ret
= NtUserUnregisterClass( &name
, hInstance
, &menu_name
);
419 if (ret
) free_menu_name( &menu_name
);
424 /***********************************************************************
425 * GetClassWord (USER32.@)
427 WORD WINAPI
GetClassWord( HWND hwnd
, INT offset
)
429 return NtUserGetClassWord( hwnd
, offset
);
433 /***********************************************************************
434 * GetClassLongW (USER32.@)
436 DWORD WINAPI
GetClassLongW( HWND hwnd
, INT offset
)
438 return NtUserGetClassLongW( hwnd
, offset
);
443 /***********************************************************************
444 * GetClassLongA (USER32.@)
446 DWORD WINAPI
GetClassLongA( HWND hwnd
, INT offset
)
448 return NtUserGetClassLongA( hwnd
, offset
);
452 /***********************************************************************
453 * SetClassLongW (USER32.@)
455 DWORD WINAPI
SetClassLongW( HWND hwnd
, INT offset
, LONG newval
)
457 if (offset
== GCLP_MENUNAME
) return set_menu_nameW( hwnd
, offset
, newval
);
458 return NtUserSetClassLong( hwnd
, offset
, newval
, FALSE
);
462 /***********************************************************************
463 * SetClassLongA (USER32.@)
465 DWORD WINAPI
SetClassLongA( HWND hwnd
, INT offset
, LONG newval
)
467 if (offset
== GCLP_MENUNAME
) return set_menu_nameA( hwnd
, offset
, newval
);
468 return NtUserSetClassLong( hwnd
, offset
, newval
, TRUE
);
472 /***********************************************************************
473 * GetClassNameA (USER32.@)
475 INT WINAPI
GetClassNameA( HWND hwnd
, LPSTR buffer
, INT count
)
477 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
480 if (count
<= 0) return 0;
481 if (!GetClassNameW( hwnd
, tmpbuf
, ARRAY_SIZE( tmpbuf
))) return 0;
482 RtlUnicodeToMultiByteN( buffer
, count
- 1, &len
, tmpbuf
, lstrlenW(tmpbuf
) * sizeof(WCHAR
) );
488 /***********************************************************************
489 * GetClassNameW (USER32.@)
491 INT WINAPI
GetClassNameW( HWND hwnd
, LPWSTR buffer
, INT count
)
493 UNICODE_STRING name
= { .Buffer
= buffer
, .MaximumLength
= count
* sizeof(WCHAR
) };
494 return NtUserGetClassName( hwnd
, FALSE
, &name
);
498 /***********************************************************************
499 * RealGetWindowClassA (USER32.@)
501 UINT WINAPI
RealGetWindowClassA( HWND hwnd
, LPSTR buffer
, UINT count
)
503 return GetClassNameA( hwnd
, buffer
, count
);
507 /***********************************************************************
508 * RealGetWindowClassW (USER32.@)
510 UINT WINAPI
RealGetWindowClassW( HWND hwnd
, LPWSTR buffer
, UINT count
)
512 return GetClassNameW( hwnd
, buffer
, count
);
516 /***********************************************************************
517 * GetClassInfoA (USER32.@)
519 BOOL WINAPI
GetClassInfoA( HINSTANCE hInstance
, LPCSTR name
, WNDCLASSA
*wc
)
522 UINT ret
= GetClassInfoExA( hInstance
, name
, &wcex
);
526 wc
->style
= wcex
.style
;
527 wc
->lpfnWndProc
= wcex
.lpfnWndProc
;
528 wc
->cbClsExtra
= wcex
.cbClsExtra
;
529 wc
->cbWndExtra
= wcex
.cbWndExtra
;
530 wc
->hInstance
= wcex
.hInstance
;
531 wc
->hIcon
= wcex
.hIcon
;
532 wc
->hCursor
= wcex
.hCursor
;
533 wc
->hbrBackground
= wcex
.hbrBackground
;
534 wc
->lpszMenuName
= wcex
.lpszMenuName
;
535 wc
->lpszClassName
= wcex
.lpszClassName
;
541 /***********************************************************************
542 * GetClassInfoW (USER32.@)
544 BOOL WINAPI
GetClassInfoW( HINSTANCE hInstance
, LPCWSTR name
, WNDCLASSW
*wc
)
547 UINT ret
= GetClassInfoExW( hInstance
, name
, &wcex
);
551 wc
->style
= wcex
.style
;
552 wc
->lpfnWndProc
= wcex
.lpfnWndProc
;
553 wc
->cbClsExtra
= wcex
.cbClsExtra
;
554 wc
->cbWndExtra
= wcex
.cbWndExtra
;
555 wc
->hInstance
= wcex
.hInstance
;
556 wc
->hIcon
= wcex
.hIcon
;
557 wc
->hCursor
= wcex
.hCursor
;
558 wc
->hbrBackground
= wcex
.hbrBackground
;
559 wc
->lpszMenuName
= wcex
.lpszMenuName
;
560 wc
->lpszClassName
= wcex
.lpszClassName
;
565 ATOM
get_class_info( HINSTANCE instance
, const WCHAR
*class_name
, WNDCLASSEXW
*info
,
566 UNICODE_STRING
*name_str
, BOOL ansi
)
572 get_versioned_name( class_name
, &name
, NULL
, &module
);
574 if (!name_str
&& !instance
) instance
= user32_module
;
576 while (!(atom
= NtUserGetClassInfoEx( instance
, &name
, info
, NULL
, ansi
)))
580 BOOL (WINAPI
*pRegisterClassNameW
)( const WCHAR
*class );
581 pRegisterClassNameW
= (void *)GetProcAddress( module
, "RegisterClassNameW" );
583 if (pRegisterClassNameW
)
585 TRACE( "registering %s\n", debugstr_us(&name
) );
586 pRegisterClassNameW( class_name
);
590 if (IS_INTRESOURCE( class_name
)) break;
591 if (!is_comctl32_class( class_name
)) break;
592 if (GetModuleHandleW( L
"comctl32.dll" )) break;
593 if (!LoadLibraryW( L
"comctl32.dll" )) break;
594 TRACE( "%s retrying after loading comctl32\n", debugstr_w(class_name
) );
599 TRACE( "%s %p -> not found\n", debugstr_w(class_name
), instance
);
600 SetLastError( ERROR_CLASS_DOES_NOT_EXIST
);
604 if (name_str
) *name_str
= name
;
608 /***********************************************************************
609 * GetClassInfoExA (USER32.@)
611 BOOL WINAPI
GetClassInfoExA( HINSTANCE hInstance
, LPCSTR name
, WNDCLASSEXA
*wc
)
615 TRACE("%p %s %p\n", hInstance
, debugstr_a(name
), wc
);
619 SetLastError( ERROR_NOACCESS
);
623 if (!IS_INTRESOURCE(name
))
625 WCHAR nameW
[MAX_ATOM_LEN
+ 1];
626 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, ARRAY_SIZE( nameW
)))
628 atom
= get_class_info( hInstance
, nameW
, (WNDCLASSEXW
*)wc
, NULL
, TRUE
);
630 else atom
= get_class_info( hInstance
, (const WCHAR
*)name
, (WNDCLASSEXW
*)wc
, NULL
, TRUE
);
631 if (atom
) wc
->lpszClassName
= name
;
633 /* We must return the atom of the class here instead of just TRUE. */
638 /***********************************************************************
639 * GetClassInfoExW (USER32.@)
641 BOOL WINAPI
GetClassInfoExW( HINSTANCE hInstance
, LPCWSTR name
, WNDCLASSEXW
*wc
)
645 TRACE("%p %s %p\n", hInstance
, debugstr_w(name
), wc
);
649 SetLastError( ERROR_NOACCESS
);
653 atom
= get_class_info( hInstance
, name
, wc
, NULL
, FALSE
);
654 if (atom
) wc
->lpszClassName
= name
;
656 /* We must return the atom of the class here instead of just TRUE. */
665 #undef GetClassLongPtrA
666 #undef GetClassLongPtrW
667 #undef SetClassLongPtrA
668 #undef SetClassLongPtrW
670 /***********************************************************************
671 * GetClassLongPtrA (USER32.@)
673 ULONG_PTR WINAPI
GetClassLongPtrA( HWND hwnd
, INT offset
)
675 return NtUserGetClassLongPtrA( hwnd
, offset
);
678 /***********************************************************************
679 * GetClassLongPtrW (USER32.@)
681 ULONG_PTR WINAPI
GetClassLongPtrW( HWND hwnd
, INT offset
)
683 return NtUserGetClassLongPtrW( hwnd
, offset
);
686 /***********************************************************************
687 * SetClassLongPtrW (USER32.@)
689 ULONG_PTR WINAPI
SetClassLongPtrW( HWND hwnd
, INT offset
, LONG_PTR newval
)
691 if (offset
== GCLP_MENUNAME
) return set_menu_nameW( hwnd
, offset
, newval
);
692 return NtUserSetClassLongPtr( hwnd
, offset
, newval
, FALSE
);
695 /***********************************************************************
696 * SetClassLongPtrA (USER32.@)
698 ULONG_PTR WINAPI
SetClassLongPtrA( HWND hwnd
, INT offset
, LONG_PTR newval
)
700 if (offset
== GCLP_MENUNAME
) return set_menu_nameA( hwnd
, offset
, newval
);
701 return NtUserSetClassLongPtr( hwnd
, offset
, newval
, TRUE
);