diff --git a/dlls/user32/class.c b/dlls/user32/class.c index b37db675400..c835ae06d41 100644 --- a/dlls/user32/class.c +++ b/dlls/user32/class.c @@ -40,27 +40,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(class); #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */ -typedef struct tagCLASS -{ - struct list entry; /* Entry in class list */ - UINT style; /* Class style */ - BOOL local; /* Local class? */ - WNDPROC winproc; /* Window procedure */ - INT cbClsExtra; /* Class extra bytes */ - INT cbWndExtra; /* Window extra bytes */ - LPWSTR menuName; /* Default menu name (Unicode followed by ASCII) */ - struct dce *dce; /* Opaque pointer to class DCE */ - HINSTANCE hInstance; /* Module that created the task */ - HICON hIcon; /* Default icon */ - HICON hIconSm; /* Default small icon */ - HICON hIconSmIntern; /* Internal small icon, derived from hIcon */ - HCURSOR hCursor; /* Default cursor */ - HBRUSH hbrBackground; /* Default background */ - ATOM atomName; /* Name of the class */ - WCHAR name[MAX_ATOM_LEN + 1]; - WCHAR *basename; /* Base name for redirected classes, pointer within 'name'. */ -} CLASS; - static struct list class_list = LIST_INIT( class_list ); static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; @@ -1212,47 +1191,8 @@ INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count ) */ INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count ) { - CLASS *class; - INT ret; - - TRACE("%p %p %d\n", hwnd, buffer, count); - - if (count <= 0) return 0; - - if (!(class = get_class_ptr( hwnd, FALSE ))) return 0; - - if (class == CLASS_OTHER_PROCESS) - { - WCHAR tmpbuf[MAX_ATOM_LEN + 1]; - 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; - - ret = GlobalGetAtomNameW( atom, tmpbuf, MAX_ATOM_LEN + 1 ); - if (ret) - { - ret = min(count - 1, ret); - memcpy(buffer, tmpbuf, ret * sizeof(WCHAR)); - buffer[ret] = 0; - } - } - else - { - /* Return original name class was registered with. */ - lstrcpynW( buffer, class->basename, count ); - release_class_ptr( class ); - ret = lstrlenW( buffer ); - } - return ret; + UNICODE_STRING name = { .Buffer = buffer, .MaximumLength = count * sizeof(WCHAR) }; + return NtUserGetClassName( hwnd, FALSE, &name ); } diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index b3511f615c6..9b1bb2de623 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -29,8 +29,10 @@ #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 @@ -166,6 +168,38 @@ NTSTATUS WINAPI NtUserInitializeClientPfnArrays( const struct user_client_procs 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.@) */ @@ -190,3 +224,46 @@ ULONG WINAPI NtUserGetAtomName( ATOM atom, UNICODE_STRING *name ) 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; +} diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 2ada1c5b990..a7f05f9c5d2 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -169,6 +169,27 @@ typedef struct tagWINDOWPROC #define MAX_ATOM_LEN 255 +typedef struct tagCLASS +{ + struct list entry; /* Entry in class list */ + UINT style; /* Class style */ + BOOL local; /* Local class? */ + WNDPROC winproc; /* Window procedure */ + INT cbClsExtra; /* Class extra bytes */ + INT cbWndExtra; /* Window extra bytes */ + LPWSTR menuName; /* Default menu name (Unicode followed by ASCII) */ + struct dce *dce; /* Opaque pointer to class DCE */ + HINSTANCE hInstance; /* Module that created the task */ + HICON hIcon; /* Default icon */ + HICON hIconSm; /* Default small icon */ + HICON hIconSmIntern; /* Internal small icon, derived from hIcon */ + HCURSOR hCursor; /* Default cursor */ + HBRUSH hbrBackground; /* Default background */ + ATOM atomName; /* Name of the class */ + WCHAR name[MAX_ATOM_LEN + 1]; + WCHAR *basename; /* Base name for redirected classes, pointer within 'name'. */ +} CLASS; + /* class.c */ WNDPROC alloc_winproc( WNDPROC func, BOOL ansi ) DECLSPEC_HIDDEN; WINDOWPROC *get_winproc_ptr( WNDPROC handle ) DECLSPEC_HIDDEN; @@ -185,4 +206,7 @@ void *free_user_handle( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; void *get_user_handle_ptr( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN; +WND *get_win_ptr( HWND hwnd ) DECLSPEC_HIDDEN; +BOOL is_window( HWND hwnd ) DECLSPEC_HIDDEN; + #endif /* __WINE_NTUSER_PRIVATE_H */ diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 48b5ad3979c..95cb2452f9c 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -113,6 +113,7 @@ static void * const syscalls[] = NtUserDestroyAcceleratorTable, NtUserFindExistingCursorIcon, NtUserGetAtomName, + NtUserGetClassName, NtUserGetClipboardFormatName, NtUserGetClipboardOwner, NtUserGetClipboardSequenceNumber, diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index ef25939d10d..40ea1e58687 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -110,6 +110,7 @@ static void test_class(void) WCHAR buf[64]; WNDCLASSW cls; ATOM class; + HWND hwnd; ULONG ret; memset( &cls, 0, sizeof(cls) ); @@ -123,6 +124,9 @@ static void test_class(void) class = RegisterClassW( &cls ); ok( class, "RegisterClassW failed: %lu\n", GetLastError() ); + hwnd = CreateWindowW( L"test", L"test name", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, NULL, 0 ); + memset( buf, 0xcc, sizeof(buf) ); name.Buffer = buf; name.Length = 0xdead; @@ -151,6 +155,36 @@ static void test_class(void) ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "NtUserGetAtomName returned %lx %lu\n", ret, GetLastError() ); + memset( buf, 0xcc, sizeof(buf) ); + name.Buffer = buf; + name.Length = 0xdead; + name.MaximumLength = sizeof(buf); + ret = NtUserGetClassName( hwnd, FALSE, &name ); + ok( ret == 4, "NtUserGetClassName returned %lu\n", ret ); + ok( name.Length == 0xdead, "Length = %u\n", name.Length ); + ok( name.MaximumLength == sizeof(buf), "MaximumLength = %u\n", name.MaximumLength ); + ok( !wcscmp( buf, L"test" ), "buf = %s\n", debugstr_w(buf) ); + + memset( buf, 0xcc, sizeof(buf) ); + name.Buffer = buf; + name.Length = 0xdead; + name.MaximumLength = 8; + ret = NtUserGetClassName( hwnd, FALSE, &name ); + ok( ret == 3, "NtUserGetClassName returned %lu\n", ret ); + ok( name.Length == 0xdead, "Length = %u\n", name.Length ); + ok( name.MaximumLength == 8, "MaximumLength = %u\n", name.MaximumLength ); + ok( !wcscmp( buf, L"tes" ), "buf = %s\n", debugstr_w(buf) ); + + memset( buf, 0xcc, sizeof(buf) ); + name.Buffer = buf; + name.MaximumLength = 1; + SetLastError( 0xdeadbeef ); + ret = NtUserGetClassName( hwnd, FALSE, &name ); + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "NtUserGetClassName returned %lx %lu\n", ret, GetLastError() ); + + DestroyWindow( hwnd ); + ret = UnregisterClassW( L"test", GetModuleHandleW(NULL) ); ok( ret, "UnregisterClassW failed: %lu\n", GetLastError() ); diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 084c54caf5a..7eed3889224 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -899,7 +899,7 @@ @ stub NtUserGetCaretBlinkTime @ stub NtUserGetCaretPos @ stub NtUserGetClassInfoEx -@ stub NtUserGetClassName +@ stdcall -syscall NtUserGetClassName(long long ptr) @ stub NtUserGetClipCursor @ stub NtUserGetClipboardAccessToken @ stub NtUserGetClipboardData diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 7725ba7bd53..8a7d9879b01 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -219,7 +219,7 @@ static BOOL is_desktop_window( HWND hwnd ) * or WND_OTHER_PROCESS if handle may be valid in other process. * If ret value is a valid pointer, it must be released with WIN_ReleasePtr. */ -static WND *get_win_ptr( HWND hwnd ) +WND *get_win_ptr( HWND hwnd ) { WND *win; @@ -248,7 +248,7 @@ HWND is_current_thread_window( HWND hwnd ) } /* see IsWindow */ -static BOOL is_window( HWND hwnd ) +BOOL is_window( HWND hwnd ) { WND *win; BOOL ret; diff --git a/include/ntuser.h b/include/ntuser.h index 7f4b3db52d2..fc5ca720cf9 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -257,6 +257,7 @@ HICON WINAPI NtUserFindExistingCursorIcon( UNICODE_STRING *module, UNICODE_STR void *desc ); SHORT WINAPI NtUserGetAsyncKeyState( INT key ); ULONG WINAPI NtUserGetAtomName( ATOM atom, UNICODE_STRING *name ); +INT WINAPI NtUserGetClassName( HWND hwnd, BOOL real, UNICODE_STRING *name ); INT WINAPI NtUserGetClipboardFormatName( UINT format, WCHAR *buffer, INT maxlen ); HWND WINAPI NtUserGetClipboardOwner(void); DWORD WINAPI NtUserGetClipboardSequenceNumber(void);