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
33 #include "user_private.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 /***********************************************************************
57 static CLASS
*get_class_ptr( HWND hwnd
, BOOL write_access
)
59 WND
*ptr
= WIN_GetPtr( hwnd
);
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
);
73 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
78 /***********************************************************************
81 static inline void release_class_ptr( CLASS
*ptr
)
87 /***********************************************************************
90 ATOM
get_int_atom_value( UNICODE_STRING
*name
)
92 const WCHAR
*ptr
= name
->Buffer
;
93 const WCHAR
*end
= ptr
+ name
->Length
/ sizeof(WCHAR
);
96 if (IS_INTRESOURCE(ptr
)) return LOWORD(ptr
);
98 if (*ptr
++ != '#') return 0;
101 if (*ptr
< '0' || *ptr
> '9') return 0;
102 ret
= ret
* 10 + *ptr
++ - '0';
103 if (ret
> 0xffff) return 0;
109 /***********************************************************************
112 static BOOL
is_comctl32_class( const WCHAR
*name
)
114 static const WCHAR
*classesW
[] =
118 L
"msctls_progress32",
119 L
"msctls_statusbar32",
120 L
"msctls_trackbar32",
125 L
"SysDateTimePick32",
138 int min
= 0, max
= ARRAY_SIZE( classesW
) - 1;
142 int res
, pos
= (min
+ max
) / 2;
143 if (!(res
= wcsicmp( name
, classesW
[pos
] ))) return TRUE
;
144 if (res
< 0) max
= pos
- 1;
150 static BOOL
is_builtin_class( const WCHAR
*name
)
152 static const WCHAR
*classesW
[] =
159 int min
= 0, max
= ARRAY_SIZE( classesW
) - 1;
163 int res
, pos
= (min
+ max
) / 2;
164 if (!(res
= wcsicmp( name
, classesW
[pos
] ))) return TRUE
;
165 if (res
< 0) max
= pos
- 1;
171 /***********************************************************************
174 * Set class info with the wine server.
176 static BOOL
set_server_info( HWND hwnd
, INT offset
, LONG_PTR newval
, UINT size
)
180 SERVER_START_REQ( set_class_info
)
182 req
->window
= wine_server_user_handle( hwnd
);
183 req
->extra_offset
= -1;
187 req
->flags
= SET_CLASS_ATOM
;
188 req
->atom
= LOWORD(newval
);
191 req
->flags
= SET_CLASS_STYLE
;
195 req
->flags
= SET_CLASS_WINEXTRA
;
196 req
->win_extra
= newval
;
199 req
->flags
= SET_CLASS_INSTANCE
;
200 req
->instance
= wine_server_client_ptr( (void *)newval
);
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
) );
213 memcpy( &req
->extra_value
, &newval
, sizeof(LONG_PTR
) );
216 ret
= !wine_server_call_err( req
);
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 /***********************************************************************
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 /***********************************************************************
248 * Get the menu name as a Unicode string.
250 static inline LPWSTR
CLASS_GetMenuNameW( CLASS
*classPtr
)
252 return classPtr
->menuName
;
256 /***********************************************************************
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 /***********************************************************************
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 /***********************************************************************
299 * Free a class structure.
301 static void CLASS_FreeClass( CLASS
*classPtr
)
303 TRACE("%p\n", classPtr
);
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
);
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;
324 LIST_FOR_EACH_ENTRY( class, &class_list
, CLASS
, entry
)
328 if (class->atomName
!= atom
) continue;
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 );
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
356 const WCHAR
*module
, *ptr
;
357 UNICODE_STRING name_us
;
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
);
370 data
.cbSize
= sizeof(data
);
371 RtlInitUnicodeString(&name_us
, name
);
372 if (RtlFindActivationContextSectionString( 0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
375 init_class_name( ret
, name
);
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
);
391 WCHAR
*combined
= version
->Buffer
;
392 memcpy( combined
, ptr
, offset
* sizeof(WCHAR
) );
393 lstrcpyW( &combined
[offset
], name
);
394 version
->Length
= offset
* sizeof(WCHAR
);
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
)
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
)
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
;
453 HeapFree( GetProcessHeap(), 0, classPtr
);
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 */
466 if (local
) list_add_head( &class_list
, &classPtr
->entry
);
467 else list_add_tail( &class_list
, &classPtr
->entry
);
472 /***********************************************************************
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
)
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
);
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);
505 uxtheme
= LoadLibraryA("uxtheme.dll");
508 pIsThemeActive
= (void *)GetProcAddress(uxtheme
, "IsThemeActive");
509 if (!pIsThemeActive
|| !pIsThemeActive())
510 FreeLibrary(uxtheme
);
514 /***********************************************************************
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 */
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 /***********************************************************************
560 WNDPROC
get_class_winproc( CLASS
*class )
562 return class->winproc
;
566 /***********************************************************************
569 struct dce
*get_class_dce( CLASS
*class )
575 /***********************************************************************
578 struct dce
*set_class_dce( CLASS
*class, struct dce
*dce
)
580 if (class->dce
) return class->dce
; /* already set, don't change it */
586 /***********************************************************************
587 * RegisterClassA (USER32.@)
589 * Register a window class.
592 * >0: Unique identifier
595 ATOM WINAPI
RegisterClassA( const WNDCLASSA
* wc
) /* [in] Address of structure with class data */
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
;
611 return RegisterClassExA( &wcex
);
615 /***********************************************************************
616 * RegisterClassW (USER32.@)
618 * See RegisterClassA.
620 ATOM WINAPI
RegisterClassW( const WNDCLASSW
* wc
)
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
;
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
;
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
);
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
);
670 init_class_name( &name
, (const WCHAR
*)wc
->lpszClassName
);
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
);
699 /***********************************************************************
700 * RegisterClassExW (USER32.@)
702 ATOM WINAPI
RegisterClassExW( const WNDCLASSEXW
* wc
)
704 WCHAR combined
[MAX_ATOM_LEN
+ 1];
705 UNICODE_STRING name
, version
;
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
);
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
)))
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
);
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 ))
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
;
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
);
786 if (classPtr
) CLASS_FreeClass( classPtr
);
787 return (classPtr
!= NULL
);
791 /***********************************************************************
792 * GetClassWord (USER32.@)
794 WORD WINAPI
GetClassWord( HWND hwnd
, INT offset
)
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
);
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
) );
818 if (offset
<= class->cbClsExtra
- sizeof(WORD
))
819 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
821 SetLastError( ERROR_INVALID_INDEX
);
822 release_class_ptr( class );
827 /***********************************************************************
830 * Implementation of GetClassLong(Ptr)A/W
832 static ULONG_PTR
CLASS_GetClassLong( HWND hwnd
, INT offset
, UINT size
,
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
);
846 req
->extra_offset
= (offset
>= 0) ? offset
: -1;
847 req
->extra_size
= (offset
>= 0) ? size
: 0;
848 if (!wine_server_call_err( req
))
852 case GCLP_HBRBACKGROUND
:
858 FIXME( "offset %d (%s) not supported on other process window %p\n",
859 offset
, SPY_GetClassLongOffsetName(offset
), hwnd
);
860 SetLastError( ERROR_INVALID_HANDLE
);
863 retvalue
= reply
->old_style
;
866 retvalue
= reply
->old_win_extra
;
869 retvalue
= reply
->old_extra
;
872 retvalue
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
);
875 retvalue
= reply
->old_atom
;
880 if (size
== sizeof(DWORD
))
883 memcpy( &retdword
, &reply
->old_extra_value
, sizeof(DWORD
) );
887 memcpy( &retvalue
, &reply
->old_extra_value
,
890 else SetLastError( ERROR_INVALID_INDEX
);
901 if (offset
<= class->cbClsExtra
- size
)
903 if (size
== sizeof(DWORD
))
906 memcpy( &retdword
, (char *)(class + 1) + offset
, sizeof(DWORD
) );
910 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(ULONG_PTR
) );
913 SetLastError( ERROR_INVALID_INDEX
);
914 release_class_ptr( class );
920 case GCLP_HBRBACKGROUND
:
921 retvalue
= (ULONG_PTR
)class->hbrBackground
;
924 retvalue
= (ULONG_PTR
)class->hCursor
;
927 retvalue
= (ULONG_PTR
)class->hIcon
;
930 retvalue
= (ULONG_PTR
)(class->hIconSm
? class->hIconSm
: class->hIconSmIntern
);
933 retvalue
= class->style
;
936 retvalue
= class->cbWndExtra
;
939 retvalue
= class->cbClsExtra
;
942 retvalue
= class->instance
;
945 retvalue
= (ULONG_PTR
)WINPROC_GetProc( class->winproc
, unicode
);
948 retvalue
= (ULONG_PTR
)CLASS_GetMenuNameW( class );
950 retvalue
= (ULONG_PTR
)CLASS_GetMenuNameW( class );
952 retvalue
= (ULONG_PTR
)CLASS_GetMenuNameA( class );
955 retvalue
= class->atomName
;
958 SetLastError( ERROR_INVALID_INDEX
);
961 release_class_ptr( class );
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
)
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
) );
1012 release_class_ptr( class );
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
)
1026 ULONG_PTR retval
= 0;
1028 if (!(class = get_class_ptr( hwnd
, TRUE
))) return 0;
1032 if (set_server_info( hwnd
, offset
, newval
, size
))
1034 void *ptr
= (char *)(class + 1) + offset
;
1035 if ( size
== sizeof(LONG
) )
1038 LONG newlong
= newval
;
1039 memcpy( &retdword
, ptr
, sizeof(DWORD
) );
1040 memcpy( ptr
, &newlong
, sizeof(LONG
) );
1045 memcpy( &retval
, ptr
, sizeof(ULONG_PTR
) );
1046 memcpy( ptr
, &newval
, sizeof(LONG_PTR
) );
1054 CLASS_SetMenuNameW( class, (LPCWSTR
)newval
);
1056 CLASS_SetMenuNameA( class, (LPCSTR
)newval
);
1057 retval
= 0; /* Old value is now meaningless anyway */
1060 retval
= (ULONG_PTR
)WINPROC_GetProc( class->winproc
, unicode
);
1061 class->winproc
= WINPROC_AllocProc( (WNDPROC
)newval
, unicode
);
1063 case GCLP_HBRBACKGROUND
:
1064 retval
= (ULONG_PTR
)class->hbrBackground
;
1065 class->hbrBackground
= (HBRUSH
)newval
;
1068 retval
= (ULONG_PTR
)class->hCursor
;
1069 class->hCursor
= (HCURSOR
)newval
;
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
;
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
;
1098 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
1099 retval
= class->style
;
1100 class->style
= newval
;
1102 case GCL_CBWNDEXTRA
:
1103 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
1104 retval
= class->cbWndExtra
;
1105 class->cbWndExtra
= newval
;
1108 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
1109 retval
= class->instance
;
1110 class->instance
= newval
;
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
));
1118 case GCL_CBCLSEXTRA
: /* cannot change this one */
1119 SetLastError( ERROR_INVALID_PARAMETER
);
1122 SetLastError( ERROR_INVALID_INDEX
);
1125 release_class_ptr( class );
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];
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
) );
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
)
1198 UINT ret
= GetClassInfoExA( hInstance
, name
, &wcex
);
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
;
1217 /***********************************************************************
1218 * GetClassInfoW (USER32.@)
1220 BOOL WINAPI
GetClassInfoW( HINSTANCE hInstance
, LPCWSTR name
, WNDCLASSW
*wc
)
1223 UINT ret
= GetClassInfoExW( hInstance
, name
, &wcex
);
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
;
1241 ATOM
get_class_info( HINSTANCE instance
, const WCHAR
*class_name
, WNDCLASSEXW
*info
,
1242 UNICODE_STRING
*name_str
, BOOL ansi
)
1244 UNICODE_STRING name
;
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
)))
1262 BOOL (WINAPI
*pRegisterClassNameW
)( const WCHAR
*class );
1263 pRegisterClassNameW
= (void *)GetProcAddress( module
, "RegisterClassNameW" );
1265 if (pRegisterClassNameW
)
1267 TRACE( "registering %s\n", debugstr_us(&name
) );
1268 pRegisterClassNameW( class_name
);
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
) );
1281 TRACE("%s %p -> not found\n", debugstr_w(class_name
), instance
);
1282 SetLastError( ERROR_CLASS_DOES_NOT_EXIST
);
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 );
1308 /***********************************************************************
1309 * GetClassInfoExA (USER32.@)
1311 BOOL WINAPI
GetClassInfoExA( HINSTANCE hInstance
, LPCSTR name
, WNDCLASSEXA
*wc
)
1315 TRACE("%p %s %p\n", hInstance
, debugstr_a(name
), wc
);
1319 SetLastError( ERROR_NOACCESS
);
1323 if (!IS_INTRESOURCE(name
))
1325 WCHAR nameW
[MAX_ATOM_LEN
+ 1];
1326 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, ARRAY_SIZE( nameW
)))
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. */
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
);
1347 SetLastError( ERROR_NOACCESS
);
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
)
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
;
1382 pClassEntry
->wNext
= 0;
1385 pClassEntry
->hInst
= class->hInstance
;
1386 pClassEntry
->wNext
++;
1387 GlobalGetAtomNameA( class->atomName
, pClassEntry
->szClassName
,
1388 sizeof(pClassEntry
->szClassName
) );
1393 /* 64bit versions */
1395 #ifdef GetClassLongPtrA
1396 #undef GetClassLongPtrA
1399 #ifdef GetClassLongPtrW
1400 #undef GetClassLongPtrW
1403 #ifdef SetClassLongPtrA
1404 #undef SetClassLongPtrA
1407 #ifdef SetClassLongPtrW
1408 #undef SetClassLongPtrW
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
);