cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / class.c
blob396e22857977014b3e58f50f4a5bacb931524efc
1 /*
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
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include <pthread.h>
28 #include <assert.h>
29 #include "ntstatus.h"
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 */
61 } CLASS;
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 */
78 } WINDOWPROC;
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 )
92 unsigned int i;
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];
106 return NULL;
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 )
129 WINDOWPROC *proc;
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 );
154 return proc;
157 /**********************************************************************
158 * alloc_winproc
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 )
168 WINDOWPROC *proc;
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;
181 if (ansi)
183 if (ptr->procA) return ptr->procA;
184 return proc;
186 else
188 if (ptr->procW) return ptr->procW;
189 return proc;
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 );
208 if (!proc)
210 params->procW = params->procA = NULL;
212 else if (proc == WINPROC_PROC16)
214 params->procW = params->procA = WINPROC_PROC16;
216 else
218 params->procA = proc->procA;
219 params->procW = proc->procW;
221 if (fixup_ansi_dst)
223 if (params->ansi)
225 if (params->procA) params->ansi_dst = TRUE;
226 else if (params->procW) params->ansi_dst = FALSE;
228 else
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 )
242 WINDOWPROC *proc;
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)
251 gdi_init();
252 winstation_init();
253 sysparams_init();
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 /***********************************************************************
302 * get_int_atom_value
304 ATOM get_int_atom_value( UNICODE_STRING *name )
306 const WCHAR *ptr = name->Buffer;
307 const WCHAR *end = ptr + name->Length / sizeof(WCHAR);
308 UINT ret = 0;
310 if (IS_INTRESOURCE(ptr)) return LOWORD(ptr);
312 if (*ptr++ != '#') return 0;
313 while (ptr < end)
315 if (*ptr < '0' || *ptr > '9') return 0;
316 ret = ret * 10 + *ptr++ - '0';
317 if (ret > 0xffff) return 0;
319 return ret;
322 /***********************************************************************
323 * get_class_ptr
325 static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
327 WND *ptr = get_win_ptr( hwnd );
329 if (ptr)
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 );
338 return NULL;
341 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
342 return NULL;
345 /***********************************************************************
346 * release_class_ptr
348 static void release_class_ptr( CLASS *ptr )
350 user_unlock();
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;
357 CLASS *class;
358 int is_win16;
360 user_lock();
361 LIST_FOR_EACH_ENTRY( class, &class_list, CLASS, entry )
363 if (atom)
365 if (class->atomName != atom) continue;
367 else
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 );
377 return class;
380 user_unlock();
381 return NULL;
384 /***********************************************************************
385 * get_class_winproc
387 WNDPROC get_class_winproc( CLASS *class )
389 return class->winproc;
392 /***********************************************************************
393 * get_class_dce
395 struct dce *get_class_dce( CLASS *class )
397 return class->dce;
400 /***********************************************************************
401 * set_class_dce
403 struct dce *set_class_dce( CLASS *class, struct dce *dce )
405 if (class->dce) return class->dce; /* already set, don't change it */
406 class->dce = dce;
407 return dce;
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;
418 HINSTANCE instance;
419 HICON sm_icon = 0;
420 CLASS *class;
421 ATOM atom;
422 BOOL ret;
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 );
431 return 0;
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);
455 else
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;
481 SERVER_END_REQ;
482 if (!ret)
484 free( class );
485 return 0;
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 );
495 user_lock();
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 );
513 return atom;
516 /***********************************************************************
517 * NtUserUnregisterClass (win32u.@)
519 BOOL WINAPI NtUserUnregisterClass( UNICODE_STRING *name, HINSTANCE instance,
520 struct client_menu_name *client_menu_name )
522 CLASS *class = NULL;
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 );
534 SERVER_END_REQ;
535 if (!class) return FALSE;
537 TRACE( "%p\n", class );
539 user_lock();
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 );
546 free( class );
547 user_unlock();
548 return TRUE;
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'};
558 CLASS *class;
559 ATOM atom;
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;
569 if (wc)
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 );
587 return atom;
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;
597 UINT size;
599 if (!set_ntstatus( NtQueryInformationAtom( atom, AtomBasicInformation,
600 buf, sizeof(buf), NULL )))
601 return 0;
603 if (name->MaximumLength < sizeof(WCHAR))
605 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
606 return 0;
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 )
620 CLASS *class;
621 int ret;
623 TRACE( "%p %x %p\n", hwnd, real, name );
625 if (name->MaximumLength <= sizeof(WCHAR))
627 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
628 return 0;
631 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
633 if (class == OBJ_OTHER_PROCESS)
635 ATOM atom = 0;
637 SERVER_START_REQ( set_class_info )
639 req->window = wine_server_user_handle( hwnd );
640 req->flags = 0;
641 req->extra_offset = -1;
642 req->extra_size = 0;
643 if (!wine_server_call_err( req ))
644 atom = reply->base_atom;
646 SERVER_END_REQ;
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 );
655 return ret;
658 /* Set class info with the wine server. */
659 static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size )
661 BOOL ret;
663 SERVER_START_REQ( set_class_info )
665 req->window = wine_server_user_handle( hwnd );
666 req->extra_offset = -1;
667 switch(offset)
669 case GCW_ATOM:
670 req->flags = SET_CLASS_ATOM;
671 req->atom = LOWORD(newval);
672 break;
673 case GCL_STYLE:
674 req->flags = SET_CLASS_STYLE;
675 req->style = newval;
676 break;
677 case GCL_CBWNDEXTRA:
678 req->flags = SET_CLASS_WINEXTRA;
679 req->win_extra = newval;
680 break;
681 case GCLP_HMODULE:
682 req->flags = SET_CLASS_INSTANCE;
683 req->instance = wine_server_client_ptr( (void *)newval );
684 break;
685 default:
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) );
695 else
696 memcpy( &req->extra_value, &newval, sizeof(LONG_PTR) );
697 break;
699 ret = !wine_server_call_err( req );
701 SERVER_END_REQ;
702 return ret;
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;
709 CLASS *class;
711 if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
713 if (offset >= 0)
715 if (set_server_info( hwnd, offset, newval, size ))
717 void *ptr = (char *)(class + 1) + offset;
718 if ( size == sizeof(LONG) )
720 DWORD retdword;
721 LONG newlong = newval;
722 memcpy( &retdword, ptr, sizeof(DWORD) );
723 memcpy( ptr, &newlong, sizeof(LONG) );
724 retval = retdword;
726 else
728 memcpy( &retval, ptr, sizeof(ULONG_PTR) );
729 memcpy( ptr, &newval, sizeof(LONG_PTR) );
733 else switch(offset)
735 case GCLP_MENUNAME:
737 struct client_menu_name *menu_name = (void *)newval;
738 struct client_menu_name prev = class->menu_name;
739 class->menu_name = *menu_name;
740 *menu_name = prev;
741 retval = 0; /* Old value is now meaningless anyway */
742 break;
744 case GCLP_WNDPROC:
745 retval = (ULONG_PTR)get_winproc( class->winproc, ansi );
746 class->winproc = alloc_winproc( (WNDPROC)newval, ansi );
747 break;
748 case GCLP_HBRBACKGROUND:
749 retval = (ULONG_PTR)class->hbrBackground;
750 class->hbrBackground = (HBRUSH)newval;
751 break;
752 case GCLP_HCURSOR:
753 retval = (ULONG_PTR)class->hCursor;
754 class->hCursor = (HCURSOR)newval;
755 break;
756 case GCLP_HICON:
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 );
771 return 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;
784 break;
785 case GCLP_HICONSM:
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 );
801 return 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;
814 break;
815 case GCL_STYLE:
816 if (!set_server_info( hwnd, offset, newval, size )) break;
817 retval = class->style;
818 class->style = newval;
819 break;
820 case GCL_CBWNDEXTRA:
821 if (!set_server_info( hwnd, offset, newval, size )) break;
822 retval = class->cbWndExtra;
823 class->cbWndExtra = newval;
824 break;
825 case GCLP_HMODULE:
826 if (!set_server_info( hwnd, offset, newval, size )) break;
827 retval = class->instance;
828 class->instance = newval;
829 break;
830 case GCW_ATOM:
832 UNICODE_STRING us;
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 );
840 break;
841 case GCL_CBCLSEXTRA: /* cannot change this one */
842 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
843 break;
844 default:
845 RtlSetLastWin32Error( ERROR_INVALID_INDEX );
846 break;
848 release_class_ptr( class );
849 return retval;
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 )
873 CLASS *class;
874 WORD retval = 0;
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) );
894 SERVER_END_REQ;
895 release_class_ptr( class );
896 return retval;
899 static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ansi )
901 CLASS *class;
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 );
911 req->flags = 0;
912 req->extra_offset = (offset >= 0) ? offset : -1;
913 req->extra_size = (offset >= 0) ? size : 0;
914 if (!wine_server_call_err( req ))
916 switch(offset)
918 case GCLP_HBRBACKGROUND:
919 case GCLP_HCURSOR:
920 case GCLP_HICON:
921 case GCLP_HICONSM:
922 case GCLP_WNDPROC:
923 case GCLP_MENUNAME:
924 FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
925 RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
926 break;
927 case GCL_STYLE:
928 retvalue = reply->old_style;
929 break;
930 case GCL_CBWNDEXTRA:
931 retvalue = reply->old_win_extra;
932 break;
933 case GCL_CBCLSEXTRA:
934 retvalue = reply->old_extra;
935 break;
936 case GCLP_HMODULE:
937 retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
938 break;
939 case GCW_ATOM:
940 retvalue = reply->old_atom;
941 break;
942 default:
943 if (offset >= 0)
945 if (size == sizeof(DWORD))
947 DWORD retdword;
948 memcpy( &retdword, &reply->old_extra_value, sizeof(DWORD) );
949 retvalue = retdword;
951 else
952 memcpy( &retvalue, &reply->old_extra_value,
953 sizeof(ULONG_PTR) );
955 else RtlSetLastWin32Error( ERROR_INVALID_INDEX );
956 break;
960 SERVER_END_REQ;
961 return retvalue;
964 if (offset >= 0)
966 if (offset <= class->cbClsExtra - size)
968 if (size == sizeof(DWORD))
970 DWORD retdword;
971 memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) );
972 retvalue = retdword;
974 else
975 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) );
977 else
978 RtlSetLastWin32Error( ERROR_INVALID_INDEX );
979 release_class_ptr( class );
980 return retvalue;
983 switch(offset)
985 case GCLP_HBRBACKGROUND:
986 retvalue = (ULONG_PTR)class->hbrBackground;
987 break;
988 case GCLP_HCURSOR:
989 retvalue = (ULONG_PTR)class->hCursor;
990 break;
991 case GCLP_HICON:
992 retvalue = (ULONG_PTR)class->hIcon;
993 break;
994 case GCLP_HICONSM:
995 retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern);
996 break;
997 case GCL_STYLE:
998 retvalue = class->style;
999 break;
1000 case GCL_CBWNDEXTRA:
1001 retvalue = class->cbWndExtra;
1002 break;
1003 case GCL_CBCLSEXTRA:
1004 retvalue = class->cbClsExtra;
1005 break;
1006 case GCLP_HMODULE:
1007 retvalue = class->instance;
1008 break;
1009 case GCLP_WNDPROC:
1010 retvalue = (ULONG_PTR)get_winproc( class->winproc, ansi );
1011 break;
1012 case GCLP_MENUNAME:
1013 retvalue = ansi ? (ULONG_PTR)class->menu_name.nameA : (ULONG_PTR)class->menu_name.nameW;
1014 break;
1015 case GCW_ATOM:
1016 retvalue = class->atomName;
1017 break;
1018 default:
1019 RtlSetLastWin32Error( ERROR_INVALID_INDEX );
1020 break;
1022 release_class_ptr( class );
1023 return retvalue;
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 )
1038 CLASS *class;
1039 WORD retvalue = 0;
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 );
1050 req->flags = 0;
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) );
1056 SERVER_END_REQ;
1057 return retvalue;
1060 if (offset <= class->cbClsExtra - sizeof(WORD))
1061 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
1062 else
1063 RtlSetLastWin32Error( ERROR_INVALID_INDEX );
1064 release_class_ptr( class );
1065 return retvalue;
1068 BOOL needs_ime_window( HWND hwnd )
1070 static const WCHAR imeW[] = {'I','M','E',0};
1071 CLASS *class;
1072 BOOL ret;
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 );
1077 return ret;
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 =
1090 .name = "Message",
1091 .proc = WINPROC_MESSAGE,
1094 static const struct builtin_class_descr builtin_classes[] =
1096 /* button */
1098 .name = "Button",
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,
1104 /* combo */
1106 .name = "ComboBox",
1107 .style = CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW,
1108 .proc = WINPROC_COMBO,
1109 .extra = sizeof(void *),
1110 .cursor = IDC_ARROW,
1112 /* combolbox */
1114 .name = "ComboLBox",
1115 .style = CS_DBLCLKS | CS_SAVEBITS,
1116 .proc = WINPROC_LISTBOX,
1117 .extra = sizeof(void *),
1118 .cursor = IDC_ARROW,
1120 /* dialog */
1122 .name = MAKEINTRESOURCEA(DIALOG_CLASS_ATOM),
1123 .style = CS_SAVEBITS | CS_DBLCLKS,
1124 .proc = WINPROC_DIALOG,
1125 .extra = DLGWINDOWEXTRA,
1126 .cursor = IDC_ARROW,
1128 /* edit */
1130 .name = "Edit",
1131 .style = CS_DBLCLKS | CS_PARENTDC,
1132 .proc = WINPROC_EDIT,
1133 .extra = sizeof(UINT64),
1134 .cursor = IDC_IBEAM,
1136 /* icon title */
1138 .name = MAKEINTRESOURCEA(ICONTITLE_CLASS_ATOM),
1139 .proc = WINPROC_ICONTITLE,
1140 .cursor = IDC_ARROW,
1142 /* IME */
1144 .name = "IME",
1145 .proc = WINPROC_IME,
1146 .extra = 2 * sizeof(LONG_PTR),
1147 .cursor = IDC_ARROW,
1149 /* listbox */
1151 .name = "ListBox",
1152 .style = CS_DBLCLKS,
1153 .proc = WINPROC_LISTBOX,
1154 .extra = sizeof(void *),
1155 .cursor = IDC_ARROW,
1157 /* menu */
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),
1166 /* MDIClient */
1168 .name = "MDIClient",
1169 .proc = WINPROC_MDICLIENT,
1170 .extra = 2 * sizeof(void *),
1171 .cursor = IDC_ARROW,
1172 .brush = (HBRUSH)(COLOR_APPWORKSPACE + 1),
1174 /* scrollbar */
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,
1182 /* static */
1184 .name = "Static",
1185 .style = CS_DBLCLKS | CS_PARENTDC,
1186 .proc = WINPROC_STATIC,
1187 .extra = 2 * sizeof(HANDLE),
1188 .cursor = IDC_ARROW,
1192 /***********************************************************************
1193 * register_builtin
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 };
1202 WCHAR nameW[64];
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 ),
1212 if (descr->cursor)
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;
1221 else
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)
1233 ULONG ret_len, i;
1234 void *ret_ptr;
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 );