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 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( ret
))) return ret
;
245 if (proc
== WINPROC_PROC16
) return WINPROC_PROC16
;
246 return 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
& ~0xffff;
360 LIST_FOR_EACH_ENTRY( class, &class_list
, CLASS
, entry
)
364 if (class->atomName
!= atom
) continue;
368 if (wcsnicmp( class->name
, name
->Buffer
, name
->Length
/ sizeof(WCHAR
) ) ||
369 class->name
[name
->Length
/ sizeof(WCHAR
)]) continue;
371 if (!class->local
|| !module
|| (class->instance
& ~0xffff) == instance
)
373 TRACE( "%s %lx -> %p\n", debugstr_us(name
), instance
, class );
381 /***********************************************************************
384 WNDPROC
get_class_winproc( CLASS
*class )
386 return class->winproc
;
389 /***********************************************************************
392 struct dce
*get_class_dce( CLASS
*class )
397 /***********************************************************************
400 struct dce
*set_class_dce( CLASS
*class, struct dce
*dce
)
402 if (class->dce
) return class->dce
; /* already set, don't change it */
407 /***********************************************************************
408 * NtUserRegisterClassExWOW (win32u.@)
410 ATOM WINAPI
NtUserRegisterClassExWOW( const WNDCLASSEXW
*wc
, UNICODE_STRING
*name
, UNICODE_STRING
*version
,
411 struct client_menu_name
*client_menu_name
, DWORD fnid
,
412 DWORD flags
, DWORD
*wow
)
414 const BOOL is_builtin
= fnid
, ansi
= flags
;
421 /* create the desktop window to trigger builtin class registration */
422 if (!is_builtin
) get_desktop_window();
424 if (wc
->cbSize
!= sizeof(*wc
) || wc
->cbClsExtra
< 0 || wc
->cbWndExtra
< 0 ||
425 (!is_builtin
&& wc
->hInstance
== user32_module
)) /* we can't register a class for user32 */
427 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
430 if (!(instance
= wc
->hInstance
)) instance
= NtCurrentTeb()->Peb
->ImageBaseAddress
;
432 TRACE( "name=%s hinst=%p style=0x%x clExtr=0x%x winExtr=0x%x\n",
433 debugstr_us(name
), instance
, wc
->style
, wc
->cbClsExtra
, wc
->cbWndExtra
);
435 /* Fix the extra bytes value */
437 if (wc
->cbClsExtra
> 40) /* Extra bytes are limited to 40 in Win32 */
438 WARN( "Class extra bytes %d is > 40\n", wc
->cbClsExtra
);
439 if (wc
->cbWndExtra
> 40) /* Extra bytes are limited to 40 in Win32 */
440 WARN("Win extra bytes %d is > 40\n", wc
->cbWndExtra
);
442 if (!(class = calloc( 1, sizeof(CLASS
) + wc
->cbClsExtra
))) return 0;
444 class->atomName
= get_int_atom_value( name
);
445 class->basename
= class->name
;
446 if (!class->atomName
&& name
)
448 memcpy( class->name
, name
->Buffer
, name
->Length
);
449 class->name
[name
->Length
/ sizeof(WCHAR
)] = 0;
450 class->basename
+= version
->Length
/ sizeof(WCHAR
);
454 UNICODE_STRING str
= { .MaximumLength
= sizeof(class->name
), .Buffer
= class->name
};
455 NtUserGetAtomName( class->atomName
, &str
);
458 class->style
= wc
->style
;
459 class->local
= !is_builtin
&& !(wc
->style
& CS_GLOBALCLASS
);
460 class->cbWndExtra
= wc
->cbWndExtra
;
461 class->cbClsExtra
= wc
->cbClsExtra
;
462 class->instance
= (UINT_PTR
)instance
;
464 SERVER_START_REQ( create_class
)
466 req
->local
= class->local
;
467 req
->style
= class->style
;
468 req
->instance
= class->instance
;
469 req
->extra
= class->cbClsExtra
;
470 req
->win_extra
= class->cbWndExtra
;
471 req
->client_ptr
= wine_server_client_ptr( class );
472 req
->atom
= class->atomName
;
473 req
->name_offset
= version
->Length
/ sizeof(WCHAR
);
474 if (!req
->atom
&& name
) wine_server_add_data( req
, name
->Buffer
, name
->Length
);
475 ret
= !wine_server_call_err( req
);
476 class->atomName
= reply
->atom
;
485 /* Other non-null values must be set by caller */
486 if (wc
->hIcon
&& !wc
->hIconSm
)
487 sm_icon
= CopyImage( wc
->hIcon
, IMAGE_ICON
,
488 get_system_metrics( SM_CXSMICON
),
489 get_system_metrics( SM_CYSMICON
),
490 LR_COPYFROMRESOURCE
);
493 if (class->local
) list_add_head( &class_list
, &class->entry
);
494 else list_add_tail( &class_list
, &class->entry
);
496 atom
= class->atomName
;
498 TRACE( "name=%s->%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
499 debugstr_w(wc
->lpszClassName
), debugstr_us(name
), atom
, wc
->lpfnWndProc
, instance
,
500 wc
->hbrBackground
, wc
->style
, wc
->cbClsExtra
, wc
->cbWndExtra
, class );
502 class->hIcon
= wc
->hIcon
;
503 class->hIconSm
= wc
->hIconSm
;
504 class->hIconSmIntern
= sm_icon
;
505 class->hCursor
= wc
->hCursor
;
506 class->hbrBackground
= wc
->hbrBackground
;
507 class->winproc
= alloc_winproc( wc
->lpfnWndProc
, ansi
);
508 if (client_menu_name
) class->menu_name
= *client_menu_name
;
509 release_class_ptr( class );
513 /***********************************************************************
514 * NtUserUnregisterClass (win32u.@)
516 BOOL WINAPI
NtUserUnregisterClass( UNICODE_STRING
*name
, HINSTANCE instance
,
517 struct client_menu_name
*client_menu_name
)
521 /* create the desktop window to trigger builtin class registration */
522 get_desktop_window();
524 SERVER_START_REQ( destroy_class
)
526 req
->instance
= wine_server_client_ptr( instance
);
527 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
528 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
529 if (!wine_server_call_err( req
)) class = wine_server_get_ptr( reply
->client_ptr
);
532 if (!class) return FALSE
;
534 TRACE( "%p\n", class );
537 if (class->dce
) free_dce( class->dce
, 0 );
538 list_remove( &class->entry
);
539 if (class->hbrBackground
> (HBRUSH
)(COLOR_GRADIENTINACTIVECAPTION
+ 1))
540 NtGdiDeleteObjectApp( class->hbrBackground
);
541 *client_menu_name
= class->menu_name
;
542 NtUserDestroyCursor( class->hIconSmIntern
, 0 );
548 /***********************************************************************
549 * NtUserGetClassInfo (win32u.@)
551 ATOM WINAPI
NtUserGetClassInfoEx( HINSTANCE instance
, UNICODE_STRING
*name
, WNDCLASSEXW
*wc
,
552 struct client_menu_name
*menu_name
, BOOL ansi
)
554 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
558 /* create the desktop window to trigger builtin class registration */
559 if (name
->Buffer
!= (const WCHAR
*)DESKTOP_CLASS_ATOM
&&
560 (IS_INTRESOURCE(name
->Buffer
) || name
->Length
!= sizeof(messageW
) ||
561 wcsnicmp( name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
562 get_desktop_window();
564 if (!(class = find_class( instance
, name
))) return 0;
568 wc
->style
= class->style
;
569 wc
->lpfnWndProc
= get_winproc( class->winproc
, ansi
);
570 wc
->cbClsExtra
= class->cbClsExtra
;
571 wc
->cbWndExtra
= class->cbWndExtra
;
572 wc
->hInstance
= (instance
== user32_module
) ? 0 : instance
;
573 wc
->hIcon
= class->hIcon
;
574 wc
->hIconSm
= class->hIconSm
? class->hIconSm
: class->hIconSmIntern
;
575 wc
->hCursor
= class->hCursor
;
576 wc
->hbrBackground
= class->hbrBackground
;
577 wc
->lpszMenuName
= ansi
? (const WCHAR
*)class->menu_name
.nameA
: class->menu_name
.nameW
;
578 wc
->lpszClassName
= name
->Buffer
;
581 if (menu_name
) *menu_name
= class->menu_name
;
582 atom
= class->atomName
;
583 release_class_ptr( class );
587 /***********************************************************************
588 * NtUserGetAtomName (win32u.@)
590 ULONG WINAPI
NtUserGetAtomName( ATOM atom
, UNICODE_STRING
*name
)
592 char buf
[sizeof(ATOM_BASIC_INFORMATION
) + MAX_ATOM_LEN
* sizeof(WCHAR
)];
593 ATOM_BASIC_INFORMATION
*abi
= (ATOM_BASIC_INFORMATION
*)buf
;
596 if (!set_ntstatus( NtQueryInformationAtom( atom
, AtomBasicInformation
,
597 buf
, sizeof(buf
), NULL
)))
600 if (name
->MaximumLength
< sizeof(WCHAR
))
602 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
606 size
= min( abi
->NameLength
, name
->MaximumLength
- sizeof(WCHAR
) );
607 if (size
) memcpy( name
->Buffer
, abi
->Name
, size
);
608 name
->Buffer
[size
/ sizeof(WCHAR
)] = 0;
609 return size
/ sizeof(WCHAR
);
612 /***********************************************************************
613 * NtUserGetClassName (win32u.@)
615 INT WINAPI
NtUserGetClassName( HWND hwnd
, BOOL real
, UNICODE_STRING
*name
)
620 TRACE( "%p %x %p\n", hwnd
, real
, name
);
622 if (name
->MaximumLength
<= sizeof(WCHAR
))
624 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
628 if (!(class = get_class_ptr( hwnd
, FALSE
))) return 0;
630 if (class == OBJ_OTHER_PROCESS
)
634 SERVER_START_REQ( set_class_info
)
636 req
->window
= wine_server_user_handle( hwnd
);
638 req
->extra_offset
= -1;
640 if (!wine_server_call_err( req
))
641 atom
= reply
->base_atom
;
645 return NtUserGetAtomName( atom
, name
);
648 ret
= min( name
->MaximumLength
/ sizeof(WCHAR
) - 1, lstrlenW(class->basename
) );
649 if (ret
) memcpy( name
->Buffer
, class->basename
, ret
* sizeof(WCHAR
) );
650 name
->Buffer
[ret
] = 0;
651 release_class_ptr( class );
655 /* Set class info with the wine server. */
656 static BOOL
set_server_info( HWND hwnd
, INT offset
, LONG_PTR newval
, UINT size
)
660 SERVER_START_REQ( set_class_info
)
662 req
->window
= wine_server_user_handle( hwnd
);
663 req
->extra_offset
= -1;
667 req
->flags
= SET_CLASS_ATOM
;
668 req
->atom
= LOWORD(newval
);
671 req
->flags
= SET_CLASS_STYLE
;
675 req
->flags
= SET_CLASS_WINEXTRA
;
676 req
->win_extra
= newval
;
679 req
->flags
= SET_CLASS_INSTANCE
;
680 req
->instance
= wine_server_client_ptr( (void *)newval
);
683 assert( offset
>= 0 );
684 req
->flags
= SET_CLASS_EXTRA
;
685 req
->extra_offset
= offset
;
686 req
->extra_size
= size
;
687 if ( size
== sizeof(LONG
) )
689 LONG newlong
= newval
;
690 memcpy( &req
->extra_value
, &newlong
, sizeof(LONG
) );
693 memcpy( &req
->extra_value
, &newval
, sizeof(LONG_PTR
) );
696 ret
= !wine_server_call_err( req
);
702 static ULONG_PTR
set_class_long( HWND hwnd
, INT offset
, LONG_PTR newval
, UINT size
, BOOL ansi
)
704 ULONG_PTR retval
= 0;
705 HICON small_icon
= 0;
708 if (!(class = get_class_ptr( hwnd
, TRUE
))) return 0;
712 if (set_server_info( hwnd
, offset
, newval
, size
))
714 void *ptr
= (char *)(class + 1) + offset
;
715 if ( size
== sizeof(LONG
) )
718 LONG newlong
= newval
;
719 memcpy( &retdword
, ptr
, sizeof(DWORD
) );
720 memcpy( ptr
, &newlong
, sizeof(LONG
) );
725 memcpy( &retval
, ptr
, sizeof(ULONG_PTR
) );
726 memcpy( ptr
, &newval
, sizeof(LONG_PTR
) );
734 struct client_menu_name
*menu_name
= (void *)newval
;
735 struct client_menu_name prev
= class->menu_name
;
736 class->menu_name
= *menu_name
;
738 retval
= 0; /* Old value is now meaningless anyway */
742 retval
= (ULONG_PTR
)get_winproc( class->winproc
, ansi
);
743 class->winproc
= alloc_winproc( (WNDPROC
)newval
, ansi
);
745 case GCLP_HBRBACKGROUND
:
746 retval
= (ULONG_PTR
)class->hbrBackground
;
747 class->hbrBackground
= (HBRUSH
)newval
;
750 retval
= (ULONG_PTR
)class->hCursor
;
751 class->hCursor
= (HCURSOR
)newval
;
754 retval
= (ULONG_PTR
)class->hIcon
;
755 if (retval
== newval
) break;
756 if (newval
&& !class->hIconSm
)
758 release_class_ptr( class );
760 small_icon
= CopyImage( (HICON
)newval
, IMAGE_ICON
,
761 get_system_metrics( SM_CXSMICON
),
762 get_system_metrics( SM_CYSMICON
),
763 LR_COPYFROMRESOURCE
);
765 if (!(class = get_class_ptr( hwnd
, TRUE
)))
767 NtUserDestroyCursor( small_icon
, 0 );
770 if (retval
!= HandleToUlong( class->hIcon
) || class->hIconSm
)
772 /* someone beat us, restart */
773 release_class_ptr( class );
774 NtUserDestroyCursor( small_icon
, 0 );
775 return set_class_long( hwnd
, offset
, newval
, size
, ansi
);
778 if (class->hIconSmIntern
) NtUserDestroyCursor( class->hIconSmIntern
, 0 );
779 class->hIcon
= (HICON
)newval
;
780 class->hIconSmIntern
= small_icon
;
783 retval
= (ULONG_PTR
)class->hIconSm
;
784 if (retval
== newval
) break;
785 if (retval
&& !newval
&& class->hIcon
)
787 HICON icon
= class->hIcon
;
788 release_class_ptr( class );
790 small_icon
= CopyImage( icon
, IMAGE_ICON
,
791 get_system_metrics( SM_CXSMICON
),
792 get_system_metrics( SM_CYSMICON
),
793 LR_COPYFROMRESOURCE
);
795 if (!(class = get_class_ptr( hwnd
, TRUE
)))
797 NtUserDestroyCursor( small_icon
, 0 );
800 if (class->hIcon
!= icon
|| !class->hIconSm
)
802 /* someone beat us, restart */
803 release_class_ptr( class );
804 NtUserDestroyCursor( small_icon
, 0 );
805 return set_class_long( hwnd
, offset
, newval
, size
, ansi
);
808 if (class->hIconSmIntern
) NtUserDestroyCursor( class->hIconSmIntern
, 0 );
809 class->hIconSm
= (HICON
)newval
;
810 class->hIconSmIntern
= small_icon
;
813 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
814 retval
= class->style
;
815 class->style
= newval
;
818 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
819 retval
= class->cbWndExtra
;
820 class->cbWndExtra
= newval
;
823 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
824 retval
= class->instance
;
825 class->instance
= newval
;
830 if (!set_server_info( hwnd
, offset
, newval
, size
)) break;
831 retval
= class->atomName
;
832 class->atomName
= newval
;
833 us
.Buffer
= class->name
;
834 us
.MaximumLength
= sizeof(class->name
);
835 NtUserGetAtomName( newval
, &us
);
838 case GCL_CBCLSEXTRA
: /* cannot change this one */
839 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
842 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
845 release_class_ptr( class );
849 /***********************************************************************
850 * NtUserSetClassLong (win32u.@)
852 DWORD WINAPI
NtUserSetClassLong( HWND hwnd
, INT offset
, LONG newval
, BOOL ansi
)
854 return set_class_long( hwnd
, offset
, newval
, sizeof(LONG
), ansi
);
857 /***********************************************************************
858 * NtUserSetClassLongPtr (win32u.@)
860 ULONG_PTR WINAPI
NtUserSetClassLongPtr( HWND hwnd
, INT offset
, LONG_PTR newval
, BOOL ansi
)
862 return set_class_long( hwnd
, offset
, newval
, sizeof(LONG_PTR
), ansi
);
865 /***********************************************************************
866 * NtUserSetClassWord (win32u.@)
868 WORD WINAPI
NtUserSetClassWord( HWND hwnd
, INT offset
, WORD newval
)
873 if (offset
< 0) return NtUserSetClassLong( hwnd
, offset
, (DWORD
)newval
, TRUE
);
875 if (!(class = get_class_ptr( hwnd
, TRUE
))) return 0;
877 SERVER_START_REQ( set_class_info
)
879 req
->window
= wine_server_user_handle( hwnd
);
880 req
->flags
= SET_CLASS_EXTRA
;
881 req
->extra_offset
= offset
;
882 req
->extra_size
= sizeof(newval
);
883 memcpy( &req
->extra_value
, &newval
, sizeof(newval
) );
884 if (!wine_server_call_err( req
))
886 void *ptr
= (char *)(class + 1) + offset
;
887 memcpy( &retval
, ptr
, sizeof(retval
) );
888 memcpy( ptr
, &newval
, sizeof(newval
) );
892 release_class_ptr( class );
896 static ULONG_PTR
get_class_long_size( HWND hwnd
, INT offset
, UINT size
, BOOL ansi
)
899 ULONG_PTR retvalue
= 0;
901 if (!(class = get_class_ptr( hwnd
, FALSE
))) return 0;
903 if (class == OBJ_OTHER_PROCESS
)
905 SERVER_START_REQ( set_class_info
)
907 req
->window
= wine_server_user_handle( hwnd
);
909 req
->extra_offset
= (offset
>= 0) ? offset
: -1;
910 req
->extra_size
= (offset
>= 0) ? size
: 0;
911 if (!wine_server_call_err( req
))
915 case GCLP_HBRBACKGROUND
:
921 FIXME( "offset %d not supported on other process window %p\n", offset
, hwnd
);
922 RtlSetLastWin32Error( ERROR_INVALID_HANDLE
);
925 retvalue
= reply
->old_style
;
928 retvalue
= reply
->old_win_extra
;
931 retvalue
= reply
->old_extra
;
934 retvalue
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
);
937 retvalue
= reply
->old_atom
;
942 if (size
== sizeof(DWORD
))
945 memcpy( &retdword
, &reply
->old_extra_value
, sizeof(DWORD
) );
949 memcpy( &retvalue
, &reply
->old_extra_value
,
952 else RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
963 if (offset
<= class->cbClsExtra
- size
)
965 if (size
== sizeof(DWORD
))
968 memcpy( &retdword
, (char *)(class + 1) + offset
, sizeof(DWORD
) );
972 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(ULONG_PTR
) );
975 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
976 release_class_ptr( class );
982 case GCLP_HBRBACKGROUND
:
983 retvalue
= (ULONG_PTR
)class->hbrBackground
;
986 retvalue
= (ULONG_PTR
)class->hCursor
;
989 retvalue
= (ULONG_PTR
)class->hIcon
;
992 retvalue
= (ULONG_PTR
)(class->hIconSm
? class->hIconSm
: class->hIconSmIntern
);
995 retvalue
= class->style
;
998 retvalue
= class->cbWndExtra
;
1000 case GCL_CBCLSEXTRA
:
1001 retvalue
= class->cbClsExtra
;
1004 retvalue
= class->instance
;
1007 retvalue
= (ULONG_PTR
)get_winproc( class->winproc
, ansi
);
1010 retvalue
= ansi
? (ULONG_PTR
)class->menu_name
.nameA
: (ULONG_PTR
)class->menu_name
.nameW
;
1013 retvalue
= class->atomName
;
1016 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1019 release_class_ptr( class );
1023 DWORD
get_class_long( HWND hwnd
, INT offset
, BOOL ansi
)
1025 return get_class_long_size( hwnd
, offset
, sizeof(DWORD
), ansi
);
1028 ULONG_PTR
get_class_long_ptr( HWND hwnd
, INT offset
, BOOL ansi
)
1030 return get_class_long_size( hwnd
, offset
, sizeof(ULONG_PTR
), ansi
);
1033 WORD
get_class_word( HWND hwnd
, INT offset
)
1038 if (offset
< 0) return get_class_long( hwnd
, offset
, TRUE
);
1040 if (!(class = get_class_ptr( hwnd
, FALSE
))) return 0;
1042 if (class == OBJ_OTHER_PROCESS
)
1044 SERVER_START_REQ( set_class_info
)
1046 req
->window
= wine_server_user_handle( hwnd
);
1048 req
->extra_offset
= offset
;
1049 req
->extra_size
= sizeof(retvalue
);
1050 if (!wine_server_call_err( req
))
1051 memcpy( &retvalue
, &reply
->old_extra_value
, sizeof(retvalue
) );
1057 if (offset
<= class->cbClsExtra
- sizeof(WORD
))
1058 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
1060 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1061 release_class_ptr( class );
1065 BOOL
needs_ime_window( HWND hwnd
)
1067 static const WCHAR imeW
[] = {'I','M','E',0};
1071 if (!(class = get_class_ptr( hwnd
, FALSE
))) return FALSE
;
1072 ret
= !(class->style
& CS_IME
) && wcscmp( imeW
, class->name
);
1073 release_class_ptr( class );
1077 static const struct builtin_class_descr desktop_builtin_class
=
1079 .name
= MAKEINTRESOURCEA(DESKTOP_CLASS_ATOM
),
1080 .style
= CS_DBLCLKS
,
1081 .proc
= WINPROC_DESKTOP
,
1082 .brush
= (HBRUSH
)(COLOR_BACKGROUND
+ 1),
1085 static const struct builtin_class_descr message_builtin_class
=
1088 .proc
= WINPROC_MESSAGE
,
1091 static const struct builtin_class_descr builtin_classes
[] =
1096 .style
= CS_DBLCLKS
| CS_VREDRAW
| CS_HREDRAW
| CS_PARENTDC
,
1097 .proc
= WINPROC_BUTTON
,
1098 .extra
= sizeof(UINT
) + 2 * sizeof(HANDLE
),
1099 .cursor
= IDC_ARROW
,
1104 .style
= CS_PARENTDC
| CS_DBLCLKS
| CS_HREDRAW
| CS_VREDRAW
,
1105 .proc
= WINPROC_COMBO
,
1106 .extra
= sizeof(void *),
1107 .cursor
= IDC_ARROW
,
1111 .name
= "ComboLBox",
1112 .style
= CS_DBLCLKS
| CS_SAVEBITS
,
1113 .proc
= WINPROC_LISTBOX
,
1114 .extra
= sizeof(void *),
1115 .cursor
= IDC_ARROW
,
1119 .name
= MAKEINTRESOURCEA(DIALOG_CLASS_ATOM
),
1120 .style
= CS_SAVEBITS
| CS_DBLCLKS
,
1121 .proc
= WINPROC_DIALOG
,
1122 .extra
= DLGWINDOWEXTRA
,
1123 .cursor
= IDC_ARROW
,
1128 .style
= CS_DBLCLKS
| CS_PARENTDC
,
1129 .proc
= WINPROC_EDIT
,
1130 .extra
= sizeof(UINT64
),
1131 .cursor
= IDC_IBEAM
,
1135 .name
= MAKEINTRESOURCEA(ICONTITLE_CLASS_ATOM
),
1136 .proc
= WINPROC_ICONTITLE
,
1137 .cursor
= IDC_ARROW
,
1142 .proc
= WINPROC_IME
,
1143 .extra
= 2 * sizeof(LONG_PTR
),
1144 .cursor
= IDC_ARROW
,
1149 .style
= CS_DBLCLKS
,
1150 .proc
= WINPROC_LISTBOX
,
1151 .extra
= sizeof(void *),
1152 .cursor
= IDC_ARROW
,
1156 .name
= MAKEINTRESOURCEA(POPUPMENU_CLASS_ATOM
),
1157 .style
= CS_DROPSHADOW
| CS_SAVEBITS
| CS_DBLCLKS
,
1158 .proc
= WINPROC_MENU
,
1159 .extra
= sizeof(HMENU
),
1160 .cursor
= IDC_ARROW
,
1161 .brush
= (HBRUSH
)(COLOR_MENU
+ 1),
1165 .name
= "MDIClient",
1166 .proc
= WINPROC_MDICLIENT
,
1167 .extra
= 2 * sizeof(void *),
1168 .cursor
= IDC_ARROW
,
1169 .brush
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1),
1173 .name
= "ScrollBar",
1174 .style
= CS_DBLCLKS
| CS_VREDRAW
| CS_HREDRAW
| CS_PARENTDC
,
1175 .proc
= WINPROC_SCROLLBAR
,
1176 .extra
= sizeof(struct scroll_bar_win_data
),
1177 .cursor
= IDC_ARROW
,
1182 .style
= CS_DBLCLKS
| CS_PARENTDC
,
1183 .proc
= WINPROC_STATIC
,
1184 .extra
= 2 * sizeof(HANDLE
),
1185 .cursor
= IDC_ARROW
,
1189 /***********************************************************************
1192 * Register a builtin control class.
1193 * This allows having both ANSI and Unicode winprocs for the same class.
1195 static void register_builtin( const struct builtin_class_descr
*descr
)
1197 UNICODE_STRING name
, version
= { .Length
= 0 };
1198 struct client_menu_name menu_name
= { 0 };
1200 WNDCLASSEXW
class = {
1201 .cbSize
= sizeof(class),
1202 .hInstance
= user32_module
,
1203 .style
= descr
->style
,
1204 .cbWndExtra
= descr
->extra
,
1205 .hbrBackground
= descr
->brush
,
1206 .lpfnWndProc
= BUILTIN_WINPROC( descr
->proc
),
1210 class.hCursor
= LoadImageW( 0, (const WCHAR
*)descr
->cursor
, IMAGE_CURSOR
,
1211 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
1213 if (IS_INTRESOURCE( descr
->name
))
1215 name
.Buffer
= (WCHAR
*)descr
->name
;
1216 name
.Length
= name
.MaximumLength
= 0;
1220 asciiz_to_unicode( nameW
, descr
->name
);
1221 RtlInitUnicodeString( &name
, nameW
);
1224 if (!NtUserRegisterClassExWOW( &class, &name
, &version
, &menu_name
, 1, 0, NULL
) && class.hCursor
)
1225 NtUserDestroyCursor( class.hCursor
, 0 );
1228 static void register_builtins(void)
1233 for (i
= 0; i
< ARRAYSIZE(builtin_classes
); i
++) register_builtin( &builtin_classes
[i
] );
1234 KeUserModeCallback( NtUserInitBuiltinClasses
, NULL
, 0, &ret_ptr
, &ret_len
);
1237 /***********************************************************************
1238 * register_builtin_classes
1240 void register_builtin_classes(void)
1242 static pthread_once_t init_once
= PTHREAD_ONCE_INIT
;
1243 pthread_once( &init_once
, register_builtins
);
1246 /***********************************************************************
1247 * register_desktop_class
1249 void register_desktop_class(void)
1251 register_builtin( &desktop_builtin_class
);
1252 register_builtin( &message_builtin_class
);