diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 0aa0a0b6f08..8678aa39454 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -2325,131 +2325,6 @@ UINT WINAPI GetDpiForWindow( HWND hwnd ) } -/********************************************************************** - * WIN_GetWindowLong - * - * Helper function for GetWindowLong(). - */ -static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode ) -{ - LONG_PTR retvalue = 0; - WND *wndPtr; - - if (offset == GWLP_HWNDPARENT) - { - HWND parent = GetAncestor( hwnd, GA_PARENT ); - if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER ); - return (ULONG_PTR)parent; - } - - if (!(wndPtr = WIN_GetPtr( hwnd ))) - { - SetLastError( ERROR_INVALID_WINDOW_HANDLE ); - return 0; - } - - if (wndPtr == WND_DESKTOP) - { - switch (offset) - { - case GWL_STYLE: - retvalue = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* message parent is not visible */ - if (WIN_GetFullHandle( hwnd ) == GetDesktopWindow()) - retvalue |= WS_VISIBLE; - return retvalue; - case GWL_EXSTYLE: - case GWLP_USERDATA: - case GWLP_ID: - case GWLP_HINSTANCE: - return 0; - case GWLP_WNDPROC: - SetLastError( ERROR_ACCESS_DENIED ); - return 0; - } - SetLastError( ERROR_INVALID_INDEX ); - return 0; - } - - if (wndPtr == WND_OTHER_PROCESS) - { - if (offset == GWLP_WNDPROC) - { - SetLastError( ERROR_ACCESS_DENIED ); - return 0; - } - SERVER_START_REQ( set_window_info ) - { - req->handle = wine_server_user_handle( hwnd ); - req->flags = 0; /* don't set anything, just retrieve */ - req->extra_offset = (offset >= 0) ? offset : -1; - req->extra_size = (offset >= 0) ? size : 0; - if (!wine_server_call_err( req )) - { - switch(offset) - { - case GWL_STYLE: retvalue = reply->old_style; break; - case GWL_EXSTYLE: retvalue = reply->old_ex_style; break; - case GWLP_ID: retvalue = reply->old_id; break; - case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break; - case GWLP_USERDATA: retvalue = reply->old_user_data; break; - default: - if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size ); - else SetLastError( ERROR_INVALID_INDEX ); - break; - } - } - } - SERVER_END_REQ; - return retvalue; - } - - /* now we have a valid wndPtr */ - - if (offset >= 0) - { - if (offset > (int)(wndPtr->cbWndExtra - size)) - { - WARN("Invalid offset %d\n", offset ); - WIN_ReleasePtr( wndPtr ); - SetLastError( ERROR_INVALID_INDEX ); - return 0; - } - retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size ); - - /* Special case for dialog window procedure */ - if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo) - retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode ); - WIN_ReleasePtr( wndPtr ); - return retvalue; - } - - switch(offset) - { - case GWLP_USERDATA: retvalue = wndPtr->userdata; break; - case GWL_STYLE: retvalue = wndPtr->dwStyle; break; - case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break; - case GWLP_ID: retvalue = wndPtr->wIDmenu; break; - case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break; - case GWLP_WNDPROC: - /* This looks like a hack only for the edit control (see tests). This makes these controls - * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests - * that the hack is in GetWindowLongPtr[AW], not in winprocs. - */ - if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE))) - retvalue = (ULONG_PTR)wndPtr->winproc; - else - retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); - break; - default: - WARN("Unknown offset %d\n", offset ); - SetLastError( ERROR_INVALID_INDEX ); - break; - } - WIN_ReleasePtr(wndPtr); - return retvalue; -} - - /********************************************************************** * WIN_SetWindowLong * @@ -2539,7 +2414,7 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B { WNDPROC proc; UINT old_flags = wndPtr->flags; - retval = WIN_GetWindowLong( hwnd, offset, size, unicode ); + retval = unicode ? GetWindowLongPtrW( hwnd, offset ) : GetWindowLongPtrA( hwnd, offset ); proc = WINPROC_AllocProc( (WNDPROC)newval, unicode ); if (proc) wndPtr->winproc = proc; if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE; @@ -2680,27 +2555,22 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B } +/* FIXME: move to win32u */ +static ULONG_PTR get_hwnd_parent( HWND hwnd ) +{ + HWND parent = GetAncestor( hwnd, GA_PARENT ); + if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER ); + return (ULONG_PTR)parent; +} + + /********************************************************************** * GetWindowWord (USER32.@) */ WORD WINAPI GetWindowWord( HWND hwnd, INT offset ) { - switch(offset) - { - case GWLP_ID: - case GWLP_HINSTANCE: - case GWLP_HWNDPARENT: - break; - default: - if (offset < 0) - { - WARN("Invalid offset %d\n", offset ); - SetLastError( ERROR_INVALID_INDEX ); - return 0; - } - break; - } - return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE ); + if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd ); + return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowWord ); } @@ -2720,7 +2590,8 @@ LONG WINAPI GetWindowLongA( HWND hwnd, INT offset ) return 0; #endif default: - return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE ); + if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd ); + return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongA ); } } @@ -2741,7 +2612,8 @@ LONG WINAPI GetWindowLongW( HWND hwnd, INT offset ) return 0; #endif default: - return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE ); + if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd ); + return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongW ); } } @@ -4075,7 +3947,8 @@ BOOL WINAPI SetProcessDefaultLayout( DWORD layout ) */ LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset ) { - return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE ); + if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd ); + return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongPtrW ); } /***************************************************************************** @@ -4083,7 +3956,8 @@ LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset ) */ LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset ) { - return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE ); + if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd ); + return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongPtrA ); } /***************************************************************************** diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 07e145cdbab..3a1ec75169b 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -33,16 +33,6 @@ struct tagCLASS; struct tagDIALOGINFO; - /* WND flags values */ -#define WIN_RESTORE_MAX 0x0001 /* Maximize when restoring */ -#define WIN_NEED_SIZE 0x0002 /* Internal WM_SIZE is needed */ -#define WIN_NCACTIVATED 0x0004 /* last WM_NCACTIVATE was positive */ -#define WIN_ISMDICLIENT 0x0008 /* Window is an MDIClient */ -#define WIN_ISUNICODE 0x0010 /* Window is Unicode */ -#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ -#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */ -#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */ - /* Window functions */ extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN; extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 36c8c98db5d..2652b908934 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -135,7 +135,7 @@ WNDPROC alloc_winproc( WNDPROC func, BOOL ansi ) } /* Get a window procedure pointer that can be passed to the Windows program. */ -static WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) +WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) { WINDOWPROC *ptr = get_winproc_ptr( proc ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 83a4b9a9889..5f3cf41c1a2 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -91,6 +91,16 @@ typedef struct tagWND DWORD wExtra[1]; /* Window extra bytes */ } WND; +/* WND flags values */ +#define WIN_RESTORE_MAX 0x0001 /* Maximize when restoring */ +#define WIN_NEED_SIZE 0x0002 /* Internal WM_SIZE is needed */ +#define WIN_NCACTIVATED 0x0004 /* last WM_NCACTIVATE was positive */ +#define WIN_ISMDICLIENT 0x0008 /* Window is an MDIClient */ +#define WIN_ISUNICODE 0x0010 /* Window is Unicode */ +#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ +#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */ +#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */ + #define WND_OTHER_PROCESS ((WND *)1) /* returned by WIN_GetPtr on unknown window handles */ #define WND_DESKTOP ((WND *)2) /* returned by WIN_GetPtr on the desktop window */ @@ -207,6 +217,7 @@ WINDOWPROC *get_winproc_ptr( WNDPROC handle ) DECLSPEC_HIDDEN; DWORD get_class_long( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN; ULONG_PTR get_class_long_ptr( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN; WORD get_class_word( HWND hwnd, INT offset ) DECLSPEC_HIDDEN; +WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) DECLSPEC_HIDDEN; /* cursoricon.c */ HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 168195dcd44..86356b609b0 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -154,6 +154,60 @@ WND *next_thread_window_ptr( HWND *hwnd ) return NULL; } +/******************************************************************* + * get_hwnd_message_parent + * + * Return the parent for HWND_MESSAGE windows. + */ +static HWND get_hwnd_message_parent(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + + if (!thread_info->msg_window && user_callbacks) + user_callbacks->pGetDesktopWindow(); /* trigger creation */ + return thread_info->msg_window; +} + +/*********************************************************************** + * get_full_window_handle + * + * Convert a possibly truncated window handle to a full 32-bit handle. + */ +static HWND get_full_window_handle( HWND hwnd ) +{ + WND *win; + + if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd; + if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd; + /* do sign extension for -2 and -3 */ + if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd); + + if (!(win = get_win_ptr( hwnd ))) return hwnd; + + if (win == WND_DESKTOP) + { + if (user_callbacks && LOWORD(hwnd) == LOWORD(user_callbacks->pGetDesktopWindow())) + return user_callbacks->pGetDesktopWindow(); + else return get_hwnd_message_parent(); + } + + if (win != WND_OTHER_PROCESS) + { + hwnd = win->obj.handle; + release_win_ptr( win ); + } + else /* may belong to another process */ + { + SERVER_START_REQ( get_window_info ) + { + req->handle = wine_server_user_handle( hwnd ); + if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle ); + } + SERVER_END_REQ; + } + return hwnd; +} + /******************************************************************* * register_window_surface * @@ -307,6 +361,179 @@ static DWORD get_window_thread( HWND hwnd, DWORD *process ) return tid; } +static LONG_PTR get_win_data( const void *ptr, UINT size ) +{ + if (size == sizeof(WORD)) + { + WORD ret; + memcpy( &ret, ptr, sizeof(ret) ); + return ret; + } + else if (size == sizeof(DWORD)) + { + DWORD ret; + memcpy( &ret, ptr, sizeof(ret) ); + return ret; + } + else + { + LONG_PTR ret; + memcpy( &ret, ptr, sizeof(ret) ); + return ret; + } +} + +static LONG_PTR get_window_long_size( HWND hwnd, INT offset, UINT size, BOOL ansi ) +{ + LONG_PTR retval = 0; + WND *win; + + if (offset == GWLP_HWNDPARENT) + { + FIXME( "GWLP_HWNDPARENT not supported\n" ); + return 0; + } + + if (!(win = get_win_ptr( hwnd ))) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + + if (win == WND_DESKTOP) + { + switch (offset) + { + case GWL_STYLE: + retval = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* message parent is not visible */ + if (user_callbacks && get_full_window_handle( hwnd ) == user_callbacks->pGetDesktopWindow()) + retval |= WS_VISIBLE; + return retval; + case GWL_EXSTYLE: + case GWLP_USERDATA: + case GWLP_ID: + case GWLP_HINSTANCE: + return 0; + case GWLP_WNDPROC: + SetLastError( ERROR_ACCESS_DENIED ); + return 0; + } + SetLastError( ERROR_INVALID_INDEX ); + return 0; + } + + if (win == WND_OTHER_PROCESS) + { + if (offset == GWLP_WNDPROC) + { + SetLastError( ERROR_ACCESS_DENIED ); + return 0; + } + SERVER_START_REQ( set_window_info ) + { + req->handle = wine_server_user_handle( hwnd ); + req->flags = 0; /* don't set anything, just retrieve */ + req->extra_offset = (offset >= 0) ? offset : -1; + req->extra_size = (offset >= 0) ? size : 0; + if (!wine_server_call_err( req )) + { + switch(offset) + { + case GWL_STYLE: retval = reply->old_style; break; + case GWL_EXSTYLE: retval = reply->old_ex_style; break; + case GWLP_ID: retval = reply->old_id; break; + case GWLP_HINSTANCE: retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break; + case GWLP_USERDATA: retval = reply->old_user_data; break; + default: + if (offset >= 0) retval = get_win_data( &reply->old_extra_value, size ); + else SetLastError( ERROR_INVALID_INDEX ); + break; + } + } + } + SERVER_END_REQ; + return retval; + } + + /* now we have a valid win */ + + if (offset >= 0) + { + if (offset > (int)(win->cbWndExtra - size)) + { + WARN("Invalid offset %d\n", offset ); + release_win_ptr( win ); + SetLastError( ERROR_INVALID_INDEX ); + return 0; + } + retval = get_win_data( (char *)win->wExtra + offset, size ); + + /* Special case for dialog window procedure */ + if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && win->dlgInfo) + retval = (LONG_PTR)get_winproc( (WNDPROC)retval, ansi ); + release_win_ptr( win ); + return retval; + } + + switch(offset) + { + case GWLP_USERDATA: retval = win->userdata; break; + case GWL_STYLE: retval = win->dwStyle; break; + case GWL_EXSTYLE: retval = win->dwExStyle; break; + case GWLP_ID: retval = win->wIDmenu; break; + case GWLP_HINSTANCE: retval = (ULONG_PTR)win->hInstance; break; + case GWLP_WNDPROC: + /* This looks like a hack only for the edit control (see tests). This makes these controls + * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests + * that the hack is in GetWindowLongPtr[AW], not in winprocs. + */ + if (win->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!!ansi != !(win->flags & WIN_ISUNICODE))) + retval = (ULONG_PTR)win->winproc; + else + retval = (ULONG_PTR)get_winproc( win->winproc, ansi ); + break; + default: + WARN("Unknown offset %d\n", offset ); + SetLastError( ERROR_INVALID_INDEX ); + break; + } + release_win_ptr( win ); + return retval; +} + +/* see GetWindowLongW */ +static DWORD get_window_long( HWND hwnd, INT offset ) +{ + return get_window_long_size( hwnd, offset, sizeof(LONG), FALSE ); +} + +/* see GetWindowLongPtr */ +static ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi ) +{ + return get_window_long_size( hwnd, offset, sizeof(LONG_PTR), ansi ); +} + +/* see GetWindowWord */ +static WORD get_window_word( HWND hwnd, INT offset ) +{ + switch(offset) + { + case GWLP_ID: + case GWLP_HINSTANCE: + case GWLP_HWNDPARENT: + break; + default: + if (offset < 0) + { + WARN("Invalid offset %d\n", offset ); + SetLastError( ERROR_INVALID_INDEX ); + return 0; + } + break; + } + return get_window_long_size( hwnd, offset, sizeof(WORD), TRUE ); +} + /*********************************************************************** * NtUserGetProp (win32u.@) * @@ -502,8 +729,18 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) return get_class_long_ptr( hwnd, param, FALSE ); case NtUserGetClassWord: return get_class_word( hwnd, param ); + case NtUserGetWindowLongA: + return get_window_long_size( hwnd, param, sizeof(LONG), TRUE ); + case NtUserGetWindowLongW: + return get_window_long( hwnd, param ); + case NtUserGetWindowLongPtrA: + return get_window_long_ptr( hwnd, param, TRUE ); + case NtUserGetWindowLongPtrW: + return get_window_long_ptr( hwnd, param, FALSE ); case NtUserGetWindowThread: return get_window_thread( hwnd, (DWORD *)param ); + case NtUserGetWindowWord: + return get_window_word( hwnd, param ); default: FIXME( "invalid code %u\n", code ); return 0; diff --git a/include/ntuser.h b/include/ntuser.h index ab46a1a5b09..ccdfdb04de5 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -151,7 +151,12 @@ enum NtUserGetClassLongPtrA, NtUserGetClassLongPtrW, NtUserGetClassWord, + NtUserGetWindowLongA, + NtUserGetWindowLongW, + NtUserGetWindowLongPtrA, + NtUserGetWindowLongPtrW, NtUserGetWindowThread, + NtUserGetWindowWord, }; /* color index used to retrieve system 55aa brush */