diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e766d704e5b..575c2a71b04 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2525,6 +2525,7 @@ struct create_window_request user_handle_t parent; user_handle_t owner; atom_t atom; + int extra; }; struct create_window_reply { @@ -2603,6 +2604,8 @@ struct set_window_info_request unsigned int id; void* instance; void* user_data; + int extra_offset; + unsigned int extra_value; }; struct set_window_info_reply { @@ -2612,12 +2615,15 @@ struct set_window_info_reply unsigned int old_id; void* old_instance; void* old_user_data; + unsigned int old_extra_value; }; #define SET_WIN_STYLE 0x01 #define SET_WIN_EXSTYLE 0x02 #define SET_WIN_ID 0x04 #define SET_WIN_INSTANCE 0x08 #define SET_WIN_USERDATA 0x10 +#define SET_WIN_EXTRAWORD 0x20 +#define SET_WIN_EXTRALONG 0x40 @@ -3667,6 +3673,6 @@ union generic_reply struct set_global_windows_reply set_global_windows_reply; }; -#define SERVER_PROTOCOL_VERSION 126 +#define SERVER_PROTOCOL_VERSION 127 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 384eb24418f..69004f7369b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1780,6 +1780,7 @@ enum message_type user_handle_t parent; /* parent window */ user_handle_t owner; /* owner window */ atom_t atom; /* class atom */ + int extra; /* number of extra bytes */ @REPLY user_handle_t handle; /* created window */ @END @@ -1832,18 +1833,23 @@ enum message_type unsigned int id; /* window id */ void* instance; /* creator instance */ void* user_data; /* user-specific data */ + int extra_offset; /* offset to set in extra bytes */ + unsigned int extra_value; /* value to set in extra bytes */ @REPLY unsigned int old_style; /* old window style */ unsigned int old_ex_style; /* old window extended style */ unsigned int old_id; /* old window id */ void* old_instance; /* old creator instance */ void* old_user_data; /* old user-specific data */ + unsigned int old_extra_value; /* old value in extra bytes */ @END #define SET_WIN_STYLE 0x01 #define SET_WIN_EXSTYLE 0x02 #define SET_WIN_ID 0x04 #define SET_WIN_INSTANCE 0x08 #define SET_WIN_USERDATA 0x10 +#define SET_WIN_EXTRAWORD 0x20 +#define SET_WIN_EXTRALONG 0x40 /* Get a list of the window parents, up to the root of the tree */ diff --git a/server/trace.c b/server/trace.c index fb93e53a479..a73d34c3d12 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2095,7 +2095,8 @@ static void dump_create_window_request( const struct create_window_request *req { fprintf( stderr, " parent=%p,", req->parent ); fprintf( stderr, " owner=%p,", req->owner ); - fprintf( stderr, " atom=%04x", req->atom ); + fprintf( stderr, " atom=%04x,", req->atom ); + fprintf( stderr, " extra=%d", req->extra ); } static void dump_create_window_reply( const struct create_window_reply *req ) @@ -2154,7 +2155,9 @@ static void dump_set_window_info_request( const struct set_window_info_request * fprintf( stderr, " ex_style=%08x,", req->ex_style ); fprintf( stderr, " id=%08x,", req->id ); fprintf( stderr, " instance=%p,", req->instance ); - fprintf( stderr, " user_data=%p", req->user_data ); + fprintf( stderr, " user_data=%p,", req->user_data ); + fprintf( stderr, " extra_offset=%d,", req->extra_offset ); + fprintf( stderr, " extra_value=%08x", req->extra_value ); } static void dump_set_window_info_reply( const struct set_window_info_reply *req ) @@ -2163,7 +2166,8 @@ static void dump_set_window_info_reply( const struct set_window_info_reply *req fprintf( stderr, " old_ex_style=%08x,", req->old_ex_style ); fprintf( stderr, " old_id=%08x,", req->old_id ); fprintf( stderr, " old_instance=%p,", req->old_instance ); - fprintf( stderr, " old_user_data=%p", req->old_user_data ); + fprintf( stderr, " old_user_data=%p,", req->old_user_data ); + fprintf( stderr, " old_extra_value=%08x", req->old_extra_value ); } static void dump_get_window_parents_request( const struct get_window_parents_request *req ) diff --git a/server/window.c b/server/window.c index a13c7343c42..ff16793e209 100644 --- a/server/window.c +++ b/server/window.c @@ -77,6 +77,8 @@ struct window int prop_inuse; /* number of in-use window properties */ int prop_alloc; /* number of allocated window properties */ struct property *properties; /* window properties array */ + int nb_extra_bytes; /* number of extra bytes */ + char extra_bytes[1]; /* extra bytes storage */ }; static struct window *top_window; /* top-level (desktop) window */ @@ -264,9 +266,10 @@ static void destroy_window( struct window *win ) } /* create a new window structure (note: the window is not linked in the window tree) */ -static struct window *create_window( struct window *parent, struct window *owner, atom_t atom ) +static struct window *create_window( struct window *parent, struct window *owner, atom_t atom, + int extra_bytes ) { - struct window *win = mem_alloc( sizeof(*win) ); + struct window *win = mem_alloc( sizeof(*win) + extra_bytes - 1 ); if (!win) return NULL; if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) @@ -292,6 +295,8 @@ static struct window *create_window( struct window *parent, struct window *owner win->prop_inuse = 0; win->prop_alloc = 0; win->properties = NULL; + win->nb_extra_bytes = extra_bytes; + memset( win->extra_bytes, 0, extra_bytes ); if (parent) /* put it on parent unlinked list */ { @@ -448,11 +453,16 @@ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *threa DECL_HANDLER(create_window) { reply->handle = 0; + if (req->extra < 0 || req->extra > 4096) /* don't allow stupid values here */ + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } if (!req->parent) /* return desktop window */ { if (!top_window) { - if (!(top_window = create_window( NULL, NULL, req->atom ))) return; + if (!(top_window = create_window( NULL, NULL, req->atom, req->extra ))) return; top_window->thread = NULL; /* no thread owns the desktop */ top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; } @@ -471,7 +481,7 @@ DECL_HANDLER(create_window) set_error( STATUS_ACCESS_DENIED ); return; } - if (!(win = create_window( parent, owner, req->atom ))) return; + if (!(win = create_window( parent, owner, req->atom, req->extra ))) return; reply->handle = win->handle; } } @@ -576,6 +586,22 @@ DECL_HANDLER(set_window_info) set_error( STATUS_ACCESS_DENIED ); return; } + if (req->extra_offset < -1 || req->extra_offset >= win->nb_extra_bytes) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (req->extra_offset != -1) + { + memcpy( &reply->old_extra_value, win->extra_bytes + req->extra_offset, + min( sizeof(reply->old_extra_value), + (size_t)(win->nb_extra_bytes - req->extra_offset) )); + } + else if (req->flags & (SET_WIN_EXTRAWORD|SET_WIN_EXTRALONG)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } reply->old_style = win->style; reply->old_ex_style = win->ex_style; reply->old_id = win->id; @@ -586,6 +612,12 @@ DECL_HANDLER(set_window_info) if (req->flags & SET_WIN_ID) win->id = req->id; if (req->flags & SET_WIN_INSTANCE) win->instance = req->instance; if (req->flags & SET_WIN_USERDATA) win->user_data = req->user_data; + if (req->flags & (SET_WIN_EXTRAWORD|SET_WIN_EXTRALONG)) + { + const int len = (req->flags & SET_WIN_EXTRALONG) ? sizeof(int) : sizeof(short); + memcpy( win->extra_bytes + req->extra_offset, &req->extra_value, + min( len, win->nb_extra_bytes - req->extra_offset )); + } } diff --git a/windows/win.c b/windows/win.c index cb8246d2369..0e9ce70f843 100644 --- a/windows/win.c +++ b/windows/win.c @@ -62,12 +62,12 @@ static void *user_handles[NB_USER_HANDLES]; * * Create a window handle with the server. */ -static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size ) +static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, unsigned int extra_bytes ) { BOOL res; user_handle_t handle = 0; WORD index; - WND *win = HeapAlloc( GetProcessHeap(), 0, size ); + WND *win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) ); if (!win) return NULL; @@ -76,8 +76,9 @@ static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size ) SERVER_START_REQ( create_window ) { req->parent = parent; - req->owner = owner; - req->atom = atom; + req->owner = owner; + req->atom = atom; + req->extra = extra_bytes; if ((res = !wine_server_call_err( req ))) handle = reply->handle; } SERVER_END_REQ; @@ -459,6 +460,7 @@ LONG WIN_SetStyle( HWND hwnd, LONG style ) req->handle = hwnd; req->flags = SET_WIN_STYLE; req->style = style; + req->extra_offset = -1; if ((ok = !wine_server_call( req ))) { ret = reply->old_style; @@ -499,6 +501,7 @@ LONG WIN_SetExStyle( HWND hwnd, LONG style ) req->handle = hwnd; req->flags = SET_WIN_EXSTYLE; req->ex_style = style; + req->extra_offset = -1; if (!wine_server_call( req )) { ret = reply->old_ex_style; @@ -718,8 +721,7 @@ BOOL WIN_CreateDesktopWindow(void) &wndExtra, &winproc, &clsStyle, &dce ))) return FALSE; - pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), - sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) ); + pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), wndExtra ); if (!pWndDesktop) return FALSE; hwndDesktop = pWndDesktop->hwndSelf; @@ -759,6 +761,7 @@ BOOL WIN_CreateDesktopWindow(void) { req->handle = hwndDesktop; req->flags = 0; /* don't set anything, just retrieve */ + req->extra_offset = -1; wine_server_call( req ); pWndDesktop->dwStyle = reply->old_style; pWndDesktop->dwExStyle = reply->old_ex_style; @@ -1049,8 +1052,7 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, /* Create the window structure */ - if (!(wndPtr = create_window_handle( parent, owner, classAtom, - sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) ))) + if (!(wndPtr = create_window_handle( parent, owner, classAtom, wndExtra ))) { TRACE("out of memory\n" ); return 0; @@ -1100,6 +1102,7 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, req->style = wndPtr->dwStyle; req->ex_style = wndPtr->dwExStyle; req->instance = (void *)wndPtr->hInstance; + req->extra_offset = -1; wine_server_call( req ); } SERVER_END_REQ; @@ -1788,7 +1791,7 @@ WORD WINAPI GetWindowWord( HWND hwnd, INT offset ) */ WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval ) { - WORD *ptr, retval; + WORD retval = 0; WND * wndPtr; switch(offset) @@ -1827,10 +1830,22 @@ WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval ) SetLastError( ERROR_INVALID_INDEX ); return 0; } - ptr = (WORD *)(((char *)wndPtr->wExtra) + offset); - retval = *ptr; - *ptr = newval; - WIN_ReleasePtr(wndPtr); + + SERVER_START_REQ( set_window_info ) + { + req->handle = hwnd; + req->flags = SET_WIN_EXTRAWORD; + req->extra_offset = offset; + req->extra_value = newval; + if (!wine_server_call_err( req )) + { + WORD *ptr = (WORD *)(((char *)wndPtr->wExtra) + offset); + retval = *ptr; + *ptr = newval; + } + } + SERVER_END_REQ; + WIN_ReleasePtr( wndPtr ); return retval; } @@ -1860,13 +1875,6 @@ static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type ) if (wndPtr == WND_OTHER_PROCESS) { - if (offset >= 0) - { - if (IsWindow(hwnd)) - FIXME( "(%d) not supported on other process window %p\n", offset, hwnd ); - SetLastError( ERROR_INVALID_WINDOW_HANDLE ); - return 0; - } if (offset == GWL_WNDPROC) { SetLastError( ERROR_ACCESS_DENIED ); @@ -1876,6 +1884,7 @@ static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type ) { req->handle = hwnd; req->flags = 0; /* don't set anything, just retrieve */ + req->extra_offset = (offset >= 0) ? offset : -1; if (!wine_server_call_err( req )) { switch(offset) @@ -1886,10 +1895,13 @@ static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type ) case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break; case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break; default: - SetLastError( ERROR_INVALID_INDEX ); + if (offset >= 0) retvalue = reply->old_extra_value; + else SetLastError( ERROR_INVALID_INDEX ); break; } } + else if (offset >= 0 && GetLastError() == ERROR_INVALID_PARAMETER) + SetLastError( ERROR_INVALID_INDEX ); } SERVER_END_REQ; return retvalue; @@ -1961,6 +1973,8 @@ static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type ) static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval, WINDOWPROCTYPE type ) { + STYLESTRUCT style; + BOOL ok; LONG retval = 0; WND *wndPtr; @@ -1990,138 +2004,145 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval, return 0; } - if (offset >= 0) + /* first some special cases */ + switch( offset ) { - LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset); - if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG))) + case GWL_STYLE: + case GWL_EXSTYLE: + style.styleOld = + offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle; + style.styleNew = newval; + WIN_ReleasePtr( wndPtr ); + SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style ); + if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0; + newval = style.styleNew; + break; + case GWL_HWNDPARENT: + if (wndPtr->parent == GetDesktopWindow()) + { + WIN_ReleasePtr( wndPtr ); + return (LONG)WIN_SetOwner( hwnd, (HWND)newval ); + } + else + { + WIN_ReleasePtr( wndPtr ); + return (LONG)SetParent( hwnd, (HWND)newval ); + } + case GWL_WNDPROC: + retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); + WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW ); + WIN_ReleasePtr( wndPtr ); + return retval; + case GWL_ID: + case GWL_HINSTANCE: + case GWL_USERDATA: + break; + case DWL_DLGPROC: + if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG)) + { + WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC); + retval = (LONG)WINPROC_GetProc( *ptr, type ); + WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW ); + WIN_ReleasePtr( wndPtr ); + return retval; + } + /* fall through */ + default: + if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG))) { WARN("Invalid offset %d\n", offset ); WIN_ReleasePtr( wndPtr ); SetLastError( ERROR_INVALID_INDEX ); return 0; } - /* Special case for dialog window procedure */ - if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG)) + else { - retval = (LONG)WINPROC_GetProc( (WNDPROC)*ptr, type ); - WINPROC_SetProc( (WNDPROC *)ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW ); - WIN_ReleasePtr( wndPtr ); - return retval; + LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset); + if (*ptr == newval) /* already set to the same value */ + { + WIN_ReleasePtr( wndPtr ); + return newval; + } } - retval = *ptr; - *ptr = newval; - WIN_ReleasePtr( wndPtr ); + break; } - else - { - STYLESTRUCT style; - BOOL ok; - /* first some special cases */ - switch( offset ) + SERVER_START_REQ( set_window_info ) + { + req->handle = hwnd; + req->extra_offset = -1; + switch(offset) { case GWL_STYLE: - case GWL_EXSTYLE: - style.styleOld = - offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle; - style.styleNew = newval; - WIN_ReleasePtr( wndPtr ); - SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style ); - if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0; - newval = style.styleNew; + req->flags = SET_WIN_STYLE; + req->style = newval; + break; + case GWL_EXSTYLE: + req->flags = SET_WIN_EXSTYLE; + req->ex_style = newval; break; - case GWL_HWNDPARENT: - if (wndPtr->parent == GetDesktopWindow()) - { - WIN_ReleasePtr( wndPtr ); - return (LONG)WIN_SetOwner( hwnd, (HWND)newval ); - } - else - { - WIN_ReleasePtr( wndPtr ); - return (LONG)SetParent( hwnd, (HWND)newval ); - } - case GWL_WNDPROC: - retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); - WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW ); - WIN_ReleasePtr( wndPtr ); - return retval; case GWL_ID: + req->flags = SET_WIN_ID; + req->id = newval; + break; case GWL_HINSTANCE: + req->flags = SET_WIN_INSTANCE; + req->instance = (void *)newval; + break; case GWL_USERDATA: + req->flags = SET_WIN_USERDATA; + req->user_data = (void *)newval; break; default: - WIN_ReleasePtr( wndPtr ); - WARN("Invalid offset %d\n", offset ); - SetLastError( ERROR_INVALID_INDEX ); - return 0; + req->flags = SET_WIN_EXTRALONG; + req->extra_offset = offset; + req->extra_value = newval; } - - SERVER_START_REQ( set_window_info ) + if ((ok = !wine_server_call_err( req ))) { - req->handle = hwnd; switch(offset) { case GWL_STYLE: - req->flags = SET_WIN_STYLE; - req->style = newval; + wndPtr->dwStyle = newval; + retval = reply->old_style; break; case GWL_EXSTYLE: - req->flags = SET_WIN_EXSTYLE; - req->ex_style = newval; + wndPtr->dwExStyle = newval; + retval = reply->old_ex_style; break; case GWL_ID: - req->flags = SET_WIN_ID; - req->id = newval; + wndPtr->wIDmenu = newval; + retval = reply->old_id; break; case GWL_HINSTANCE: - req->flags = SET_WIN_INSTANCE; - req->instance = (void *)newval; + wndPtr->hInstance = (HINSTANCE)newval; + retval = (ULONG_PTR)reply->old_instance; break; case GWL_USERDATA: - req->flags = SET_WIN_USERDATA; - req->user_data = (void *)newval; + wndPtr->userdata = newval; + retval = (ULONG_PTR)reply->old_user_data; + break; + default: + { + LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset); + retval = *ptr; + *ptr = newval; + } break; } - if ((ok = !wine_server_call_err( req ))) - { - switch(offset) - { - case GWL_STYLE: - wndPtr->dwStyle = newval; - retval = reply->old_style; - break; - case GWL_EXSTYLE: - wndPtr->dwExStyle = newval; - retval = reply->old_ex_style; - break; - case GWL_ID: - wndPtr->wIDmenu = newval; - retval = reply->old_id; - break; - case GWL_HINSTANCE: - wndPtr->hInstance = (HINSTANCE)newval; - retval = (ULONG_PTR)reply->old_instance; - break; - case GWL_USERDATA: - wndPtr->userdata = newval; - retval = (ULONG_PTR)reply->old_user_data; - break; - } - } } - SERVER_END_REQ; - WIN_ReleasePtr( wndPtr ); - - if (!ok) return 0; - - if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle) - USER_Driver.pSetWindowStyle( hwnd, retval ); - - if (offset == GWL_STYLE || offset == GWL_EXSTYLE) - SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style ); - } + SERVER_END_REQ; + WIN_ReleasePtr( wndPtr ); + + if (!ok) return 0; + + if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle) + USER_Driver.pSetWindowStyle( hwnd, retval ); + + if (offset == GWL_STYLE || offset == GWL_EXSTYLE) + SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style ); + return retval; }