/* * Window classes functions * * Copyright 1993, 1996, 2003 Alexandre Julliard * Copyright 1995 Martin von Loewis * Copyright 1998 Juergen Schmied (jsch) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #if 0 #pragma makedep unix #endif #include #include "ntstatus.h" #define WIN32_NO_STATUS #include "win32u_private.h" #include "ntuser_private.h" #include "wine/server.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(class); WINE_DECLARE_DEBUG_CHANNEL(win); #define MAX_WINPROCS 4096 #define WINPROC_PROC16 ((WINDOWPROC *)1) /* placeholder for 16-bit window procs */ static WINDOWPROC winproc_array[MAX_WINPROCS]; static UINT winproc_used = NB_BUILTIN_WINPROCS; static pthread_mutex_t winproc_lock = PTHREAD_MUTEX_INITIALIZER; /* find an existing winproc for a given function and type */ /* FIXME: probably should do something more clever than a linear search */ static WINDOWPROC *find_winproc( WNDPROC func, BOOL ansi ) { unsigned int i; for (i = 0; i < NB_BUILTIN_AW_WINPROCS; i++) { /* match either proc, some apps confuse A and W */ if (winproc_array[i].procA != func && winproc_array[i].procW != func) continue; return &winproc_array[i]; } for (i = NB_BUILTIN_AW_WINPROCS; i < winproc_used; i++) { if (ansi && winproc_array[i].procA != func) continue; if (!ansi && winproc_array[i].procW != func) continue; return &winproc_array[i]; } return NULL; } /* return the window proc for a given handle, or NULL for an invalid handle, * or WINPROC_PROC16 for a handle to a 16-bit proc. */ WINDOWPROC *get_winproc_ptr( WNDPROC handle ) { UINT index = LOWORD(handle); if ((ULONG_PTR)handle >> 16 != WINPROC_HANDLE) return NULL; if (index >= MAX_WINPROCS) return WINPROC_PROC16; if (index >= winproc_used) return NULL; return &winproc_array[index]; } /* create a handle for a given window proc */ static inline WNDPROC proc_to_handle( WINDOWPROC *proc ) { return (WNDPROC)(ULONG_PTR)((proc - winproc_array) | (WINPROC_HANDLE << 16)); } /* allocate and initialize a new winproc */ static inline WINDOWPROC *alloc_winproc_ptr( WNDPROC func, BOOL ansi ) { WINDOWPROC *proc; /* check if the function is already a win proc */ if (!func) return NULL; if ((proc = get_winproc_ptr( func ))) return proc; pthread_mutex_lock( &winproc_lock ); /* check if we already have a winproc for that function */ if (!(proc = find_winproc( func, ansi ))) { if (winproc_used < MAX_WINPROCS) { proc = &winproc_array[winproc_used++]; if (ansi) proc->procA = func; else proc->procW = func; TRACE_(win)( "allocated %p for %c %p (%d/%d used)\n", proc_to_handle(proc), ansi ? 'A' : 'W', func, winproc_used, MAX_WINPROCS ); } else WARN_(win)( "too many winprocs, cannot allocate one for %p\n", func ); } else TRACE_(win)( "reusing %p for %p\n", proc_to_handle(proc), func ); pthread_mutex_unlock( &winproc_lock ); return proc; } /********************************************************************** * alloc_winproc * * Allocate a window procedure for a window or class. * * Note that allocated winprocs are never freed; the idea is that even if an app creates a * lot of windows, it will usually only have a limited number of window procedures, so the * array won't grow too large, and this way we avoid the need to track allocations per window. */ WNDPROC alloc_winproc( WNDPROC func, BOOL ansi ) { WINDOWPROC *proc; if (!(proc = alloc_winproc_ptr( func, ansi ))) return func; if (proc == WINPROC_PROC16) return func; return proc_to_handle( proc ); } /*********************************************************************** * NtUserInitializeClientPfnArrays (win32u.@) */ NTSTATUS WINAPI NtUserInitializeClientPfnArrays( const struct user_client_procs *client_procsA, const struct user_client_procs *client_procsW, const void *client_workers, HINSTANCE user_module ) { winproc_array[WINPROC_BUTTON].procA = client_procsA->pButtonWndProc; winproc_array[WINPROC_BUTTON].procW = client_procsW->pButtonWndProc; winproc_array[WINPROC_COMBO].procA = client_procsA->pComboWndProc; winproc_array[WINPROC_COMBO].procW = client_procsW->pComboWndProc; winproc_array[WINPROC_DEFWND].procA = client_procsA->pDefWindowProc; winproc_array[WINPROC_DEFWND].procW = client_procsW->pDefWindowProc; winproc_array[WINPROC_DIALOG].procA = client_procsA->pDefDlgProc; winproc_array[WINPROC_DIALOG].procW = client_procsW->pDefDlgProc; winproc_array[WINPROC_EDIT].procA = client_procsA->pEditWndProc; winproc_array[WINPROC_EDIT].procW = client_procsW->pEditWndProc; winproc_array[WINPROC_LISTBOX].procA = client_procsA->pListBoxWndProc; winproc_array[WINPROC_LISTBOX].procW = client_procsW->pListBoxWndProc; winproc_array[WINPROC_MDICLIENT].procA = client_procsA->pMDIClientWndProc; winproc_array[WINPROC_MDICLIENT].procW = client_procsW->pMDIClientWndProc; winproc_array[WINPROC_SCROLLBAR].procA = client_procsA->pScrollBarWndProc; winproc_array[WINPROC_SCROLLBAR].procW = client_procsW->pScrollBarWndProc; winproc_array[WINPROC_STATIC].procA = client_procsA->pStaticWndProc; winproc_array[WINPROC_STATIC].procW = client_procsW->pStaticWndProc; winproc_array[WINPROC_IME].procA = client_procsA->pImeWndProc; winproc_array[WINPROC_IME].procW = client_procsW->pImeWndProc; winproc_array[WINPROC_DESKTOP].procA = client_procsA->pDesktopWndProc; winproc_array[WINPROC_DESKTOP].procW = client_procsW->pDesktopWndProc; winproc_array[WINPROC_ICONTITLE].procA = client_procsA->pIconTitleWndProc; winproc_array[WINPROC_ICONTITLE].procW = client_procsW->pIconTitleWndProc; winproc_array[WINPROC_MENU].procA = client_procsA->pPopupMenuWndProc; winproc_array[WINPROC_MENU].procW = client_procsW->pPopupMenuWndProc; winproc_array[WINPROC_MESSAGE].procA = client_procsA->pMessageWndProc; winproc_array[WINPROC_MESSAGE].procW = client_procsW->pMessageWndProc; return STATUS_SUCCESS; } /*********************************************************************** * get_class_ptr */ static CLASS *get_class_ptr( HWND hwnd, BOOL write_access ) { WND *ptr = get_win_ptr( hwnd ); if (ptr) { if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class; if (!write_access) return OBJ_OTHER_PROCESS; /* modifying classes in other processes is not allowed */ if (ptr == WND_DESKTOP || is_window( hwnd )) { SetLastError( ERROR_ACCESS_DENIED ); return NULL; } } SetLastError( ERROR_INVALID_WINDOW_HANDLE ); return NULL; } /*********************************************************************** * release_class_ptr */ static inline void release_class_ptr( CLASS *ptr ) { user_unlock(); } /*********************************************************************** * NtUserGetAtomName (win32u.@) */ ULONG WINAPI NtUserGetAtomName( ATOM atom, UNICODE_STRING *name ) { char buf[sizeof(ATOM_BASIC_INFORMATION) + MAX_ATOM_LEN * sizeof(WCHAR)]; ATOM_BASIC_INFORMATION *abi = (ATOM_BASIC_INFORMATION *)buf; UINT size; if (!set_ntstatus( NtQueryInformationAtom( atom, AtomBasicInformation, buf, sizeof(buf), NULL ))) return 0; if (name->MaximumLength < sizeof(WCHAR)) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); return 0; } size = min( abi->NameLength, name->MaximumLength - sizeof(WCHAR) ); if (size) memcpy( name->Buffer, abi->Name, size ); name->Buffer[size / sizeof(WCHAR)] = 0; return size / sizeof(WCHAR); } /*********************************************************************** * NtUserGetClassName (win32u.@) */ INT WINAPI NtUserGetClassName( HWND hwnd, BOOL real, UNICODE_STRING *name ) { CLASS *class; int ret; TRACE( "%p %x %p\n", hwnd, real, name ); if (name->MaximumLength <= sizeof(WCHAR)) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); return 0; } if (!(class = get_class_ptr( hwnd, FALSE ))) return 0; if (class == OBJ_OTHER_PROCESS) { ATOM atom = 0; SERVER_START_REQ( set_class_info ) { req->window = wine_server_user_handle( hwnd ); req->flags = 0; req->extra_offset = -1; req->extra_size = 0; if (!wine_server_call_err( req )) atom = reply->base_atom; } SERVER_END_REQ; return NtUserGetAtomName( atom, name ); } ret = min( name->MaximumLength / sizeof(WCHAR) - 1, lstrlenW(class->basename) ); if (ret) memcpy( name->Buffer, class->basename, ret * sizeof(WCHAR) ); name->Buffer[ret] = 0; release_class_ptr( class ); return ret; }