2 * Window classes functions
4 * Copyright 1993, 1996, 2003 Alexandre Julliard
5 * Copyright 1995 Martin von Loewis
6 * Copyright 1998 Juergen Schmied (jsch)
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #define WIN32_NO_STATUS
31 #include "win32u_private.h"
32 #include "ntuser_private.h"
33 #include "wine/server.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(class);
37 WINE_DECLARE_DEBUG_CHANNEL(win
);
39 #define MAX_WINPROCS 4096
40 #define WINPROC_PROC16 ((void *)1) /* placeholder for 16-bit window procs */
42 typedef struct tagCLASS
44 struct list entry
; /* Entry in class list */
45 UINT style
; /* Class style */
46 BOOL local
; /* Local class? */
47 WNDPROC winproc
; /* Window procedure */
48 INT cbClsExtra
; /* Class extra bytes */
49 INT cbWndExtra
; /* Window extra bytes */
50 struct dce
*dce
; /* Opaque pointer to class DCE */
51 UINT_PTR instance
; /* Module that created the task */
52 HICON hIcon
; /* Default icon */
53 HICON hIconSm
; /* Default small icon */
54 HICON hIconSmIntern
; /* Internal small icon, derived from hIcon */
55 HCURSOR hCursor
; /* Default cursor */
56 HBRUSH hbrBackground
; /* Default background */
57 ATOM atomName
; /* Name of the class */
58 WCHAR name
[MAX_ATOM_LEN
+ 1];
59 WCHAR
*basename
; /* Base name for redirected classes, pointer within 'name'. */
60 struct client_menu_name menu_name
; /* Default menu name */
63 /* Built-in class descriptor */
64 struct builtin_class_descr
66 const char *name
; /* class name */
67 UINT style
; /* class style */
68 INT extra
; /* window extra bytes */
69 ULONG_PTR cursor
; /* cursor id */
70 HBRUSH brush
; /* brush or system color */
71 enum builtin_winprocs proc
;
74 typedef struct tagWINDOWPROC
76 WNDPROC procA
; /* ANSI window proc */
77 WNDPROC procW
; /* Unicode window proc */
80 static WINDOWPROC winproc_array
[MAX_WINPROCS
];
81 static UINT winproc_used
= NB_BUILTIN_WINPROCS
;
82 static pthread_mutex_t winproc_lock
= PTHREAD_MUTEX_INITIALIZER
;
84 static struct list class_list
= LIST_INIT( class_list
);
86 HINSTANCE user32_module
= 0;
88 /* find an existing winproc for a given function and type */
89 /* FIXME: probably should do something more clever than a linear search */
90 static WINDOWPROC
*find_winproc( WNDPROC func
, BOOL ansi
)
94 for (i
= 0; i
< NB_BUILTIN_AW_WINPROCS
; i
++)
96 /* match either proc, some apps confuse A and W */
97 if (winproc_array
[i
].procA
!= func
&& winproc_array
[i
].procW
!= func
) continue;
98 return &winproc_array
[i
];
100 for (i
= NB_BUILTIN_AW_WINPROCS
; i
< winproc_used
; i
++)
102 if (ansi
&& winproc_array
[i
].procA
!= func
) continue;
103 if (!ansi
&& winproc_array
[i
].procW
!= func
) continue;
104 return &winproc_array
[i
];
109 /* return the window proc for a given handle, or NULL for an invalid handle,
110 * or WINPROC_PROC16 for a handle to a 16-bit proc. */
111 static WINDOWPROC
*get_winproc_ptr( WNDPROC handle
)
113 UINT index
= LOWORD(handle
);
114 if ((ULONG_PTR
)handle
>> 16 != WINPROC_HANDLE
) return NULL
;
115 if (index
>= MAX_WINPROCS
) return WINPROC_PROC16
;
116 if (index
>= winproc_used
) return NULL
;
117 return &winproc_array
[index
];
120 /* create a handle for a given window proc */
121 static inline WNDPROC
proc_to_handle( WINDOWPROC
*proc
)
123 return (WNDPROC
)(ULONG_PTR
)((proc
- winproc_array
) | (WINPROC_HANDLE
<< 16));
126 /* allocate and initialize a new winproc */
127 static inline WINDOWPROC
*alloc_winproc_ptr( WNDPROC func
, BOOL ansi
)
131 /* check if the function is already a win proc */
132 if (!func
) return NULL
;
133 if ((proc
= get_winproc_ptr( func
))) return proc
;
135 pthread_mutex_lock( &winproc_lock
);
137 /* check if we already have a winproc for that function */
138 if (!(proc
= find_winproc( func
, ansi
)))
140 if (winproc_used
< MAX_WINPROCS
)
142 proc
= &winproc_array
[winproc_used
++];
143 if (ansi
) proc
->procA
= func
;
144 else proc
->procW
= func
;
145 TRACE_(win
)( "allocated %p for %c %p (%d/%d used)\n",
146 proc_to_handle(proc
), ansi
? 'A' : 'W', func
,
147 winproc_used
, MAX_WINPROCS
);
149 else WARN_(win
)( "too many winprocs, cannot allocate one for %p\n", func
);
151 else TRACE_(win
)( "reusing %p for %p\n", proc_to_handle(proc
), func
);
153 pthread_mutex_unlock( &winproc_lock
);
157 /**********************************************************************
160 * Allocate a window procedure for a window or class.
162 * Note that allocated winprocs are never freed; the idea is that even if an app creates a
163 * lot of windows, it will usually only have a limited number of window procedures, so the
164 * array won't grow too large, and this way we avoid the need to track allocations per window.
166 WNDPROC
alloc_winproc( WNDPROC func
, BOOL ansi
)
170 if (!(proc
= alloc_winproc_ptr( func
, ansi
))) return func
;
171 if (proc
== WINPROC_PROC16
) return func
;
172 return proc_to_handle( proc
);
175 /* Get a window procedure pointer that can be passed to the Windows program. */
176 WNDPROC
get_winproc( WNDPROC proc
, BOOL ansi
)
178 WINDOWPROC
*ptr
= get_winproc_ptr( proc
);
180 if (!ptr
|| ptr
== WINPROC_PROC16
) return proc
;
183 if (ptr
->procA
) return ptr
->procA
;
188 if (ptr
->procW
) return ptr
->procW
;
193 /* Return the window procedure type, or the default value if not a winproc handle. */
194 BOOL
is_winproc_unicode( WNDPROC proc
, BOOL def_val
)
196 WINDOWPROC
*ptr
= get_winproc_ptr( proc
);
198 if (!ptr
) return def_val
;
199 if (ptr
== WINPROC_PROC16
) return FALSE
; /* 16-bit is always A */
200 if (ptr
->procA
&& ptr
->procW
) return def_val
; /* can be both */
201 return ptr
->procW
!= NULL
;
204 void get_winproc_params( struct win_proc_params
*params
, BOOL fixup_ansi_dst
)
206 WINDOWPROC
*proc
= get_winproc_ptr( params
->func
);
210 params
->procW
= params
->procA
= NULL
;
212 else if (proc
== WINPROC_PROC16
)
214 params
->procW
= params
->procA
= WINPROC_PROC16
;
218 params
->procA
= proc
->procA
;
219 params
->procW
= proc
->procW
;
225 if (params
->procA
) params
->ansi_dst
= TRUE
;
226 else if (params
->procW
) params
->ansi_dst
= FALSE
;
230 if (params
->procW
) params
->ansi_dst
= FALSE
;
231 else if (params
->procA
) params
->ansi_dst
= TRUE
;
236 if (!params
->procA
) params
->procA
= params
->func
;
237 if (!params
->procW
) params
->procW
= params
->func
;
240 DLGPROC
get_dialog_proc( DLGPROC ret
, BOOL ansi
)
244 if (!(proc
= get_winproc_ptr( (WNDPROC
)ret
))) return ret
;
245 if (proc
== WINPROC_PROC16
) return WINPROC_PROC16
;
246 return (DLGPROC
)(ansi
? proc
->procA
: proc
->procW
);
249 static void init_user(void)
254 register_desktop_class();
257 /***********************************************************************
258 * NtUserInitializeClientPfnArrays (win32u.@)
260 NTSTATUS WINAPI
NtUserInitializeClientPfnArrays( const struct user_client_procs
*client_procsA
,
261 const struct user_client_procs
*client_procsW
,
262 const void *client_workers
, HINSTANCE user_module
)
264 static pthread_once_t init_once
= PTHREAD_ONCE_INIT
;
266 winproc_array
[WINPROC_BUTTON
].procA
= client_procsA
->pButtonWndProc
;
267 winproc_array
[WINPROC_BUTTON
].procW
= client_procsW
->pButtonWndProc
;
268 winproc_array
[WINPROC_COMBO
].procA
= client_procsA
->pComboWndProc
;
269 winproc_array
[WINPROC_COMBO
].procW
= client_procsW
->pComboWndProc
;
270 winproc_array
[WINPROC_DEFWND
].procA
= client_procsA
->pDefWindowProc
;
271 winproc_array
[WINPROC_DEFWND
].procW
= client_procsW
->pDefWindowProc
;
272 winproc_array
[WINPROC_DIALOG
].procA
= client_procsA
->pDefDlgProc
;
273 winproc_array
[WINPROC_DIALOG
].procW
= client_procsW
->pDefDlgProc
;
274 winproc_array
[WINPROC_EDIT
].procA
= client_procsA
->pEditWndProc
;
275 winproc_array
[WINPROC_EDIT
].procW
= client_procsW
->pEditWndProc
;
276 winproc_array
[WINPROC_LISTBOX
].procA
= client_procsA
->pListBoxWndProc
;
277 winproc_array
[WINPROC_LISTBOX
].procW
= client_procsW
->pListBoxWndProc
;
278 winproc_array
[WINPROC_MDICLIENT
].procA
= client_procsA
->pMDIClientWndProc
;
279 winproc_array
[WINPROC_MDICLIENT
].procW
= client_procsW
->pMDIClientWndProc
;
280 winproc_array
[WINPROC_SCROLLBAR
].procA
= client_procsA
->pScrollBarWndProc
;
281 winproc_array
[WINPROC_SCROLLBAR
].procW
= client_procsW
->pScrollBarWndProc
;
282 winproc_array
[WINPROC_STATIC
].procA
= client_procsA
->pStaticWndProc
;
283 winproc_array
[WINPROC_STATIC
].procW
= client_procsW
->pStaticWndProc
;
284 winproc_array
[WINPROC_IME
].procA
= client_procsA
->pImeWndProc
;
285 winproc_array
[WINPROC_IME
].procW
= client_procsW
->pImeWndProc
;
286 winproc_array
[WINPROC_DESKTOP
].procA
= client_procsA
->pDesktopWndProc
;
287 winproc_array
[WINPROC_DESKTOP
].procW
= client_procsW
->pDesktopWndProc
;
288 winproc_array
[WINPROC_ICONTITLE
].procA
= client_procsA
->pIconTitleWndProc
;
289 winproc_array
[WINPROC_ICONTITLE
].procW
= client_procsW
->pIconTitleWndProc
;
290 winproc_array
[WINPROC_MENU
].procA
= client_procsA
->pPopupMenuWndProc
;
291 winproc_array
[WINPROC_MENU
].procW
= client_procsW
->pPopupMenuWndProc
;
292 winproc_array
[WINPROC_MESSAGE
].procA
= client_procsA
->pMessageWndProc
;
293 winproc_array
[WINPROC_MESSAGE
].procW
= client_procsW
->pMessageWndProc
;
295 user32_module
= user_module
;
297 pthread_once( &init_once
, init_user
);
298 return STATUS_SUCCESS
;
301 /***********************************************************************
304 ATOM
get_int_atom_value( UNICODE_STRING
*name
)
306 const WCHAR
*ptr
= name
->Buffer
;
307 const WCHAR
*end
= ptr
+ name
->Length
/ sizeof(WCHAR
);
310 if (IS_INTRESOURCE(ptr
)) return LOWORD(ptr
);
312 if (*ptr
++ != '#') return 0;
315 if (*ptr
< '0' || *ptr
> '9') return 0;
316 ret
= ret
* 10 + *ptr
++ - '0';
317 if (ret
> 0xffff) return 0;
322 /***********************************************************************
325 static CLASS
*get_class_ptr( HWND hwnd
, BOOL write_access
)
327 WND
*ptr
= get_win_ptr( hwnd
);
331 if (ptr
!= WND_OTHER_PROCESS
&& ptr
!= WND_DESKTOP
) return ptr
->class;
332 if (!write_access
) return OBJ_OTHER_PROCESS
;
334 /* modifying classes in other processes is not allowed */
335 if (ptr
== WND_DESKTOP
|| is_window( hwnd
))
337 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
341 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
345 /***********************************************************************
348 static void release_class_ptr( CLASS
*ptr
)
353 static CLASS
*find_class( HINSTANCE module
, UNICODE_STRING
*name
)
355 ATOM atom
= get_int_atom_value( name
);
356 ULONG_PTR instance
= (UINT_PTR
)module
;
361 LIST_FOR_EACH_ENTRY( class, &class_list
, CLASS
, entry
)
365 if (class->atomName
!= atom
) continue;
369 if (wcsnicmp( class->name
, name
->Buffer
, name
->Length
/ sizeof(WCHAR
) ) ||
370 class->name
[name
->Length
/ sizeof(WCHAR
)]) continue;
372 is_win16
= !(class->instance
>> 16);
373 if (!instance
|| !class->local
|| class->instance
== instance
||
374 (!is_win16
&& ((class->instance
& ~0xffff) == (instance
& ~0xffff))))
376 TRACE( "%s %lx -> %p\n", debugstr_us(name
), instance
, class );
384 /***********************************************************************
387 WNDPROC
get_class_winproc( CLASS
*class )
389 return class->winproc
;
392 /***********************************************************************
395 struct dce
*get_class_dce( CLASS
*class )
400 /***********************************************************************
403 struct dce
*set_class_dce( CLASS
*class, struct dce
*dce
)
405 if (class->dce
) return class->dce
; /* already set, don't change it */
410 /***********************************************************************
411 * NtUserRegisterClassExWOW (win32u.@)
413 ATOM WINAPI
NtUserRegisterClassExWOW( const WNDCLASSEXW
*wc
, UNICODE_STRING
*name
, UNICODE_STRING
*version
,
414 struct client_menu_name
*client_menu_name
, DWORD fnid
,
415 DWORD flags
, DWORD
*wow
)
417 const BOOL is_builtin
= fnid
, ansi
= flags
;
424 /* create the desktop window to trigger builtin class registration */
425 if (!is_builtin
) get_desktop_window();
427 if (wc
->cbSize
!= sizeof(*wc
) || wc
->cbClsExtra
< 0 || wc
->cbWndExtra
< 0 ||
428 (!is_builtin
&& wc
->hInstance
== user32_module
)) /* we can't register a class for user32 */
430 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
433 if (!(instance
= wc
->hInstance
)) instance
= NtCurrentTeb()->Peb
->ImageBaseAddress
;
435 TRACE( "name=%s hinst=%p style=0x%x clExtr=0x%x winExtr=0x%x\n",
436 debugstr_us(name
), instance
, wc
->style
, wc
->cbClsExtra
, wc
->cbWndExtra
);
438 /* Fix the extra bytes value */
440 if (wc
->cbClsExtra
> 40) /* Extra bytes are limited to 40 in Win32 */
441 WARN( "Class extra bytes %d is > 40\n", wc
->cbClsExtra
);
442 if (wc
->cbWndExtra
> 40) /* Extra bytes are limited to 40 in Win32 */
443 WARN("Win extra bytes %d is > 40\n", wc
->cbWndExtra
);
445 if (!(class = calloc( 1, sizeof(CLASS
) + wc
->cbClsExtra
))) return 0;
447 class->atomName
= get_int_atom_value( name
);
448 class->basename
= class->name
;
449 if (!class->atomName
&& name
)
451 memcpy( class->name
, name
->Buffer
, name
->Length
);
452 class->name
[name
->Length
/ sizeof(WCHAR
)] = 0;
453 class->basename
+= version
->Length
/ sizeof(WCHAR
);
457 UNICODE_STRING str
= { .MaximumLength
= sizeof(class->name
), .Buffer
= class->name
};
458 NtUserGetAtomName( class->atomName
, &str
);
461 class->style
= wc
->style
;
462 class->local
= !is_builtin
&& !(wc
->style
& CS_GLOBALCLASS
);
463 class->cbWndExtra
= wc
->cbWndExtra
;
464 class->cbClsExtra
= wc
->cbClsExtra
;
465 class->instance
= (UINT_PTR
)instance
;
467 SERVER_START_REQ( create_class
)
469 req
->local
= class->local
;
470 req
->style
= class->style
;
471 req
->instance
= class->instance
;
472 req
->extra
= class->cbClsExtra
;
473 req
->win_extra
= class->cbWndExtra
;
474 req
->client_ptr
= wine_server_client_ptr( class );
475 req
->atom
= class->atomName
;
476 req
->name_offset
= version
->Length
/ sizeof(WCHAR
);
477 if (!req
->atom
&& name
) wine_server_add_data( req
, name
->Buffer
, name
->Length
);
478 ret
= !wine_server_call_err( req
);
479 class->atomName
= reply
->atom
;
488 /* Other non-null values must be set by caller */
489 if (wc
->hIcon
&& !wc
->hIconSm
)
490 sm_icon
= CopyImage( wc
->hIcon
, IMAGE_ICON
,
491 get_system_metrics( SM_CXSMICON
),
492 get_system_metrics( SM_CYSMICON
),
493 LR_COPYFROMRESOURCE
);
496 if (class->local
) list_add_head( &class_list
, &class->entry
);
497 else list_add_tail( &class_list
, &class->entry
);
499 atom
= class->atomName
;
501 TRACE( "name=%s->%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
502 debugstr_w(wc
->lpszClassName
), debugstr_us(name
), atom
, wc
->lpfnWndProc
, instance
,
503 wc
->hbrBackground
, wc
->style
, wc
->cbClsExtra
, wc
->cbWndExtra
, class );
505 class->hIcon
= wc
->hIcon
;
506 class->hIconSm
= wc
->hIconSm
;
507 class->hIconSmIntern
= sm_icon
;
508 class->hCursor
= wc
->hCursor
;
509 class->hbrBackground
= wc
->hbrBackground
;
510 class->winproc
= alloc_winproc( wc
->lpfnWndProc
, ansi
);
511 if (client_menu_name
) class->menu_name
= *client_menu_name
;
512 release_class_ptr( class );
516 /***********************************************************************
517 * NtUserUnregisterClass (win32u.@)
519 BOOL WINAPI
NtUserUnregisterClass( UNICODE_STRING
*name
, HINSTANCE instance
,
520 struct client_menu_name
*client_menu_name
)
524 /* create the desktop window to trigger builtin class registration */
525 get_desktop_window();
527 SERVER_START_REQ( destroy_class
)
529 req
->instance
= wine_server_client_ptr( instance
);
530 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
531 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
532 if (!wine_server_call_err( req
)) class = wine_server_get_ptr( reply
->client_ptr
);
535 if (!class) return FALSE
;
537 TRACE( "%p\n", class );
540 if (class->dce
) free_dce( class->dce
, 0 );
541 list_remove( &class->entry
);
542 if (class->hbrBackground
> (HBRUSH
)(COLOR_GRADIENTINACTIVECAPTION
+ 1))
543 NtGdiDeleteObjectApp( class->hbrBackground
);
544 *client_menu_name
= class->menu_name
;
545 NtUserDestroyCursor( class->hIconSmIntern
, 0 );
551 /***********************************************************************
552 * NtUserGetClassInfo (win32u.@)
554 ATOM WINAPI
NtUserGetClassInfoEx( HINSTANCE instance
, UNICODE_STRING
*name
, WNDCLASSEXW
*wc
,
555 struct client_menu_name
*menu_name
, BOOL ansi
)
557 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
561 /* create the desktop window to trigger builtin class registration */
562 if (name
->Buffer
!= (const WCHAR
*)DESKTOP_CLASS_ATOM
&&
563 (IS_INTRESOURCE(name
->Buffer
) || name
->Length
!= sizeof(messageW
) ||
564 wcsnicmp( name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
565 get_desktop_window();
567 if (!(class = find_class( instance
, name
))) return 0;
571 wc
->style
= class->style
;
572 wc
->lpfnWndProc
= get_winproc( class->winproc
, ansi
);
573 wc
->cbClsExtra
= class->cbClsExtra
;
574 wc
->cbWndExtra
= class->cbWndExtra
;
575 wc
->hInstance
= (instance
== user32_module
) ? 0 : instance
;
576 wc
->hIcon
= class->hIcon
;
577 wc
->hIconSm
= class->hIconSm
? class->hIconSm
: class->hIconSmIntern
;
578 wc
->hCursor
= class->hCursor
;
579 wc
->hbrBackground
= class->hbrBackground
;
580 wc
->lpszMenuName
= ansi
? (const WCHAR
*)class->menu_name
.nameA
: class->menu_name
.nameW
;
581 wc
->lpszClassName
= name
->Buffer
;
584 if (menu_name
) *menu_name
= class->menu_name
;
585 atom
= class->atomName
;
586 release_class_ptr( class );
590 /***********************************************************************
591 * NtUserGetAtomName (win32u.@)
593 ULONG WINAPI
NtUserGetAtomName( ATOM atom
, UNICODE_STRING
*name
)
595 char buf
[sizeof(ATOM_BASIC_INFORMATION
) + MAX_ATOM_LEN
* sizeof(WCHAR
)];
596 ATOM_BASIC_INFORMATION
*abi
= (ATOM_BASIC_INFORMATION
*)buf
;
599 if (!set_ntstatus( NtQueryInformationAtom( atom
, AtomBasicInformation
,
600 buf
, sizeof(buf
), NULL
)))
603 if (name
->MaximumLength
< sizeof(WCHAR
))
605 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
609 size
= min( abi
->NameLength
, name
->MaximumLength
- sizeof(WCHAR
) );
610 if (size
) memcpy( name
->Buffer
, abi
->Name
, size
);
611 name
->Buffer
[size
/ sizeof(WCHAR
)] = 0;
612 return size
/ sizeof(WCHAR
);
615 /***********************************************************************
616 * NtUserGetClassName (win32u.@)
618 INT WINAPI
NtUserGetClassName( HWND hwnd
, BOOL real
, UNICODE_STRING
*name
)
623 TRACE( "%p %x %p\n", hwnd
, real
, name
);
625 if (name
->MaximumLength
<= sizeof(WCHAR
))
627 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
631 if (!(class = get_class_ptr( hwnd
, FALSE
))) return 0;
633 if (class == OBJ_OTHER_PROCESS
)
637 SERVER_START_REQ( set_class_info
)
639 req
->window
= wine_server_user_handle( hwnd
);
641 req
->extra_offset
= -1;
643 if (!wine_server_call_err( req
))
644 atom
= reply
->base_atom
;
648 return NtUserGetAtomName( atom
, name
);
651 ret
= min( name
->MaximumLength
/ sizeof(WCHAR
) - 1, lstrlenW(class->basename
) );
652 if (ret
) memcpy( name
->Buffer
, class->basename
, ret
* sizeof(WCHAR
) );
653 name
->Buffer
[ret
] = 0;
654 release_class_ptr( class );
658 /* Set class info with the wine server. */
659 static BOOL
set_server_info( HWND hwnd
, INT offset
, LONG_PTR newval
, UINT size
)
663 SERVER_START_REQ( set_class_info
)
665 req
->window
= wine_server_user_handle( hwnd
);
666 req
->extra_offset
= -1;
670 req
->flags
= SET_CLASS_ATOM
;
671 req
->atom
= LOWORD(newval
);
674 req
->flags
= SET_CLASS_STYLE
;
678 req
->flags
= SET_CLASS_WINEXTRA
;
679 req
->win_extra
= newval
;
682 req
->flags
= SET_CLASS_INSTANCE
;
683 req
->instance
= wine_server_client_ptr( (void *)newval
);
686 assert( offset
>= 0 );
687 req
->flags
= SET_CLASS_EXTRA
;
688 req
->extra_offset
= offset
;
689 req
->extra_size
= size
;
690 if ( size
== sizeof(LONG
) )
692 LONG newlong
= newval
;
693 memcpy( &req
->extra_value
, &newlong
, sizeof(LONG
) );
696 memcpy( &req
->extra_value
, &newval
, sizeof(LONG_PTR
) );
699 ret
= !wine_server_call_err( req
);
705 static ULONG_PTR
set_class_long( HWND hwnd
, INT offset
, LONG_PTR newval
, UINT size
, BOOL ansi
)
707 ULONG_PTR retval
= 0;
708 HICON small_icon
= 0;
711 if (!(class = get_class_ptr( hwnd
, TRUE
))) return 0;
715 if (set_server_info( hwnd
, offset
, newval
, size
))
717 void *ptr
= (char *)(class + 1) + offset
;
718 if ( size
== sizeof(LONG
) )
721 LONG newlong
= newval
;
722 memcpy( &retdword
, ptr
, sizeof(DWORD
) );
723 memcpy( ptr
, &newlong
, sizeof(LONG
) );
728 memcpy( &retval
, ptr
, sizeof(ULONG_PTR
) );
729 memcpy( ptr
, &newval
, sizeof(LONG_PTR
) );
737 struct client_menu_name
*menu_name
= (void *)newval
;
738 struct client_menu_name prev
= class->menu_name
;
739 class->menu_name
= *menu_name
;
741 retval
= 0; /* Old value is now meaningless anyway */
745 retval
= (ULONG_PTR
)get_winproc( class->winproc
, ansi
);
746 class->winproc
= alloc_winproc( (WNDPROC
)newval
, ansi
);
748 case GCLP_HBRBACKGROUND
:
749 retval
= (ULONG_PTR
)class->hbrBackground
;
750 class->hbrBackground
= (HBRUSH
)newval
;
753 retval
= (ULONG_PTR
)class->hCursor
;
754 class->hCursor
= (HCURSOR
)newval
;
757 retval
= (ULONG_PTR
)class->hIcon
;
758 if (retval
== newval
) break;
759 if (newval
&& !class->hIconSm
)
761 release_class_ptr( class );
763 small_icon
= CopyImage( (HICON
)newval
, IMAGE_ICON
,
764 get_system_metrics( SM_CXSMICON
),
765 get_system_metrics( SM_CYSMICON
),
766 LR_COPYFROMRESOURCE
);
768 if (!(class = get_class_ptr( hwnd
, TRUE
)))
770 NtUserDestroyCursor( small_icon
, 0 );
773 if (retval
!= HandleToUlong( class->hIcon
) || class->hIconSm
)
775 /* someone beat us, restart */
776 release_class_ptr( class );
777 NtUserDestroyCursor( small_icon
, 0 );
778 return set_class_long( hwnd
, offset
, newval
, size
, ansi
);
781 if (class->hIconSmIntern
) NtUserDestroyCursor( class->hIconSmIntern
, 0 );
782 class->hIcon
= (HICON
)newval
;
783 class->hIconSmIntern
= small_icon
;
786 retval
= (ULONG_PTR
)class->hIconSm
;
787 if (retval
== newval
) break;
788 if (retval
&& !newval
&& class->hIcon
)
790 HICON icon
= class->hIcon
;
791 release_class_ptr( class );
793 small_icon
= CopyImage( icon
, IMAGE_ICON
,
794 get_system_metrics( SM_CXSMICON
),
795 get_system_metrics( SM_CYSMICON
),
796 LR_COPYFROMRESOURCE
);
798 if (!(class = get_class_ptr( hwnd
, TRUE
)))
800 NtUserDestroyCursor( small_icon
, 0 );
803 if (class->hIcon
!= icon
|| !class->hIconSm
)
805 /* someone beat us, restart */
806 release_class_ptr( class );
807 NtUserDestroyCursor( small_icon
, 0 );
808 return set_class_long( hwnd
, offset
, newval
, size
, ansi
);
811 if (class->hIconSmIntern
) NtUserDestroyCursor( class->hIconSmIntern
, 0 );
812 class->hIconSm
= (HICON
)newval
;
813 class->hIconSmIntern
= small_icon
;
816 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
817 retval
= class->style
;
818 class->style
= newval
;
821 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
822 retval
= class->cbWndExtra
;
823 class->cbWndExtra
= newval
;
826 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
827 retval
= class->instance
;
828 class->instance
= newval
;
833 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
834 retval
= class->atomName
;
835 class->atomName
= newval
;
836 us
.Buffer
= class->name
;
837 us
.MaximumLength
= sizeof(class->name
);
838 NtUserGetAtomName( newval
, &us
);
841 case GCL_CBCLSEXTRA
: /* cannot change this one */
842 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
845 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
848 release_class_ptr( class );
852 /***********************************************************************
853 * NtUserSetClassLong (win32u.@)
855 DWORD WINAPI
NtUserSetClassLong( HWND hwnd
, INT offset
, LONG newval
, BOOL ansi
)
857 return set_class_long( hwnd
, offset
, newval
, sizeof(LONG
), ansi
);
860 /***********************************************************************
861 * NtUserSetClassLongPtr (win32u.@)
863 ULONG_PTR WINAPI
NtUserSetClassLongPtr( HWND hwnd
, INT offset
, LONG_PTR newval
, BOOL ansi
)
865 return set_class_long( hwnd
, offset
, newval
, sizeof(LONG_PTR
), ansi
);
868 /***********************************************************************
869 * NtUserSetClassWord (win32u.@)
871 WORD WINAPI
NtUserSetClassWord( HWND hwnd
, INT offset
, WORD newval
)
876 if (offset
< 0) return NtUserSetClassLong( hwnd
, offset
, (DWORD
)newval
, TRUE
);
878 if (!(class = get_class_ptr( hwnd
, TRUE
))) return 0;
880 SERVER_START_REQ( set_class_info
)
882 req
->window
= wine_server_user_handle( hwnd
);
883 req
->flags
= SET_CLASS_EXTRA
;
884 req
->extra_offset
= offset
;
885 req
->extra_size
= sizeof(newval
);
886 memcpy( &req
->extra_value
, &newval
, sizeof(newval
) );
887 if (!wine_server_call_err( req
))
889 void *ptr
= (char *)(class + 1) + offset
;
890 memcpy( &retval
, ptr
, sizeof(retval
) );
891 memcpy( ptr
, &newval
, sizeof(newval
) );
895 release_class_ptr( class );
899 static ULONG_PTR
get_class_long_size( HWND hwnd
, INT offset
, UINT size
, BOOL ansi
)
902 ULONG_PTR retvalue
= 0;
904 if (!(class = get_class_ptr( hwnd
, FALSE
))) return 0;
906 if (class == OBJ_OTHER_PROCESS
)
908 SERVER_START_REQ( set_class_info
)
910 req
->window
= wine_server_user_handle( hwnd
);
912 req
->extra_offset
= (offset
>= 0) ? offset
: -1;
913 req
->extra_size
= (offset
>= 0) ? size
: 0;
914 if (!wine_server_call_err( req
))
918 case GCLP_HBRBACKGROUND
:
924 FIXME( "offset %d not supported on other process window %p\n", offset
, hwnd
);
925 RtlSetLastWin32Error( ERROR_INVALID_HANDLE
);
928 retvalue
= reply
->old_style
;
931 retvalue
= reply
->old_win_extra
;
934 retvalue
= reply
->old_extra
;
937 retvalue
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
);
940 retvalue
= reply
->old_atom
;
945 if (size
== sizeof(DWORD
))
948 memcpy( &retdword
, &reply
->old_extra_value
, sizeof(DWORD
) );
952 memcpy( &retvalue
, &reply
->old_extra_value
,
955 else RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
966 if (offset
<= class->cbClsExtra
- size
)
968 if (size
== sizeof(DWORD
))
971 memcpy( &retdword
, (char *)(class + 1) + offset
, sizeof(DWORD
) );
975 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(ULONG_PTR
) );
978 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
979 release_class_ptr( class );
985 case GCLP_HBRBACKGROUND
:
986 retvalue
= (ULONG_PTR
)class->hbrBackground
;
989 retvalue
= (ULONG_PTR
)class->hCursor
;
992 retvalue
= (ULONG_PTR
)class->hIcon
;
995 retvalue
= (ULONG_PTR
)(class->hIconSm
? class->hIconSm
: class->hIconSmIntern
);
998 retvalue
= class->style
;
1000 case GCL_CBWNDEXTRA
:
1001 retvalue
= class->cbWndExtra
;
1003 case GCL_CBCLSEXTRA
:
1004 retvalue
= class->cbClsExtra
;
1007 retvalue
= class->instance
;
1010 retvalue
= (ULONG_PTR
)get_winproc( class->winproc
, ansi
);
1013 retvalue
= ansi
? (ULONG_PTR
)class->menu_name
.nameA
: (ULONG_PTR
)class->menu_name
.nameW
;
1016 retvalue
= class->atomName
;
1019 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1022 release_class_ptr( class );
1026 DWORD
get_class_long( HWND hwnd
, INT offset
, BOOL ansi
)
1028 return get_class_long_size( hwnd
, offset
, sizeof(DWORD
), ansi
);
1031 ULONG_PTR
get_class_long_ptr( HWND hwnd
, INT offset
, BOOL ansi
)
1033 return get_class_long_size( hwnd
, offset
, sizeof(ULONG_PTR
), ansi
);
1036 WORD
get_class_word( HWND hwnd
, INT offset
)
1041 if (offset
< 0) return get_class_long( hwnd
, offset
, TRUE
);
1043 if (!(class = get_class_ptr( hwnd
, FALSE
))) return 0;
1045 if (class == OBJ_OTHER_PROCESS
)
1047 SERVER_START_REQ( set_class_info
)
1049 req
->window
= wine_server_user_handle( hwnd
);
1051 req
->extra_offset
= offset
;
1052 req
->extra_size
= sizeof(retvalue
);
1053 if (!wine_server_call_err( req
))
1054 memcpy( &retvalue
, &reply
->old_extra_value
, sizeof(retvalue
) );
1060 if (offset
<= class->cbClsExtra
- sizeof(WORD
))
1061 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
1063 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1064 release_class_ptr( class );
1068 BOOL
needs_ime_window( HWND hwnd
)
1070 static const WCHAR imeW
[] = {'I','M','E',0};
1074 if (!(class = get_class_ptr( hwnd
, FALSE
))) return FALSE
;
1075 ret
= !(class->style
& CS_IME
) && wcscmp( imeW
, class->name
);
1076 release_class_ptr( class );
1080 static const struct builtin_class_descr desktop_builtin_class
=
1082 .name
= MAKEINTRESOURCEA(DESKTOP_CLASS_ATOM
),
1083 .style
= CS_DBLCLKS
,
1084 .proc
= WINPROC_DESKTOP
,
1085 .brush
= (HBRUSH
)(COLOR_BACKGROUND
+ 1),
1088 static const struct builtin_class_descr message_builtin_class
=
1091 .proc
= WINPROC_MESSAGE
,
1094 static const struct builtin_class_descr builtin_classes
[] =
1099 .style
= CS_DBLCLKS
| CS_VREDRAW
| CS_HREDRAW
| CS_PARENTDC
,
1100 .proc
= WINPROC_BUTTON
,
1101 .extra
= sizeof(UINT
) + 2 * sizeof(HANDLE
),
1102 .cursor
= IDC_ARROW
,
1107 .style
= CS_PARENTDC
| CS_DBLCLKS
| CS_HREDRAW
| CS_VREDRAW
,
1108 .proc
= WINPROC_COMBO
,
1109 .extra
= sizeof(void *),
1110 .cursor
= IDC_ARROW
,
1114 .name
= "ComboLBox",
1115 .style
= CS_DBLCLKS
| CS_SAVEBITS
,
1116 .proc
= WINPROC_LISTBOX
,
1117 .extra
= sizeof(void *),
1118 .cursor
= IDC_ARROW
,
1122 .name
= MAKEINTRESOURCEA(DIALOG_CLASS_ATOM
),
1123 .style
= CS_SAVEBITS
| CS_DBLCLKS
,
1124 .proc
= WINPROC_DIALOG
,
1125 .extra
= DLGWINDOWEXTRA
,
1126 .cursor
= IDC_ARROW
,
1131 .style
= CS_DBLCLKS
| CS_PARENTDC
,
1132 .proc
= WINPROC_EDIT
,
1133 .extra
= sizeof(UINT64
),
1134 .cursor
= IDC_IBEAM
,
1138 .name
= MAKEINTRESOURCEA(ICONTITLE_CLASS_ATOM
),
1139 .proc
= WINPROC_ICONTITLE
,
1140 .cursor
= IDC_ARROW
,
1145 .proc
= WINPROC_IME
,
1146 .extra
= 2 * sizeof(LONG_PTR
),
1147 .cursor
= IDC_ARROW
,
1152 .style
= CS_DBLCLKS
,
1153 .proc
= WINPROC_LISTBOX
,
1154 .extra
= sizeof(void *),
1155 .cursor
= IDC_ARROW
,
1159 .name
= MAKEINTRESOURCEA(POPUPMENU_CLASS_ATOM
),
1160 .style
= CS_DROPSHADOW
| CS_SAVEBITS
| CS_DBLCLKS
,
1161 .proc
= WINPROC_MENU
,
1162 .extra
= sizeof(HMENU
),
1163 .cursor
= IDC_ARROW
,
1164 .brush
= (HBRUSH
)(COLOR_MENU
+ 1),
1168 .name
= "MDIClient",
1169 .proc
= WINPROC_MDICLIENT
,
1170 .extra
= 2 * sizeof(void *),
1171 .cursor
= IDC_ARROW
,
1172 .brush
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1),
1176 .name
= "ScrollBar",
1177 .style
= CS_DBLCLKS
| CS_VREDRAW
| CS_HREDRAW
| CS_PARENTDC
,
1178 .proc
= WINPROC_SCROLLBAR
,
1179 .extra
= sizeof(struct scroll_bar_win_data
),
1180 .cursor
= IDC_ARROW
,
1185 .style
= CS_DBLCLKS
| CS_PARENTDC
,
1186 .proc
= WINPROC_STATIC
,
1187 .extra
= 2 * sizeof(HANDLE
),
1188 .cursor
= IDC_ARROW
,
1192 /***********************************************************************
1195 * Register a builtin control class.
1196 * This allows having both ANSI and Unicode winprocs for the same class.
1198 static void register_builtin( const struct builtin_class_descr
*descr
)
1200 UNICODE_STRING name
, version
= { .Length
= 0 };
1201 struct client_menu_name menu_name
= { 0 };
1203 WNDCLASSEXW
class = {
1204 .cbSize
= sizeof(class),
1205 .hInstance
= user32_module
,
1206 .style
= descr
->style
,
1207 .cbWndExtra
= descr
->extra
,
1208 .hbrBackground
= descr
->brush
,
1209 .lpfnWndProc
= BUILTIN_WINPROC( descr
->proc
),
1213 class.hCursor
= LoadImageW( 0, (const WCHAR
*)descr
->cursor
, IMAGE_CURSOR
,
1214 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
1216 if (IS_INTRESOURCE( descr
->name
))
1218 name
.Buffer
= (WCHAR
*)descr
->name
;
1219 name
.Length
= name
.MaximumLength
= 0;
1223 asciiz_to_unicode( nameW
, descr
->name
);
1224 RtlInitUnicodeString( &name
, nameW
);
1227 if (!NtUserRegisterClassExWOW( &class, &name
, &version
, &menu_name
, 1, 0, NULL
) && class.hCursor
)
1228 NtUserDestroyCursor( class.hCursor
, 0 );
1231 static void register_builtins(void)
1236 for (i
= 0; i
< ARRAYSIZE(builtin_classes
); i
++) register_builtin( &builtin_classes
[i
] );
1237 KeUserModeCallback( NtUserInitBuiltinClasses
, NULL
, 0, &ret_ptr
, &ret_len
);
1240 /***********************************************************************
1241 * register_builtin_classes
1243 void register_builtin_classes(void)
1245 static pthread_once_t init_once
= PTHREAD_ONCE_INIT
;
1246 pthread_once( &init_once
, register_builtins
);
1249 /***********************************************************************
1250 * register_desktop_class
1252 void register_desktop_class(void)
1254 register_builtin( &desktop_builtin_class
);
1255 register_builtin( &message_builtin_class
);