2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
31 #include "wine/server.h"
32 #include "wine/unicode.h"
34 #include "user_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(win);
41 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
42 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
44 static DWORD process_layout = ~0u;
46 /**********************************************************************/
48 /* helper for Get/SetWindowLong */
49 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 if (size == sizeof(WORD))
54 memcpy( &ret, ptr, sizeof(ret) );
57 else if (size == sizeof(DWORD))
60 memcpy( &ret, ptr, sizeof(ret) );
66 memcpy( &ret, ptr, sizeof(ret) );
71 /* helper for Get/SetWindowLong */
72 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 if (size == sizeof(WORD))
77 memcpy( ptr, &newval, sizeof(newval) );
79 else if (size == sizeof(DWORD))
82 memcpy( ptr, &newval, sizeof(newval) );
86 memcpy( ptr, &val, sizeof(val) );
91 static void *user_handles[NB_USER_HANDLES];
93 /***********************************************************************
96 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
100 SERVER_START_REQ( alloc_user_handle )
102 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
108 UINT index = USER_HANDLE_TO_INDEX( handle );
110 assert( index < NB_USER_HANDLES );
111 ptr->handle = handle;
113 InterlockedExchangePointer( &user_handles[index], ptr );
119 /***********************************************************************
120 * get_user_handle_ptr
122 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
124 struct user_object *ptr;
125 WORD index = USER_HANDLE_TO_INDEX( handle );
127 if (index >= NB_USER_HANDLES) return NULL;
130 if ((ptr = user_handles[index]))
132 if (ptr->type == type &&
133 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
134 !HIWORD(handle) || HIWORD(handle) == 0xffff))
138 else ptr = OBJ_OTHER_PROCESS;
144 /***********************************************************************
145 * release_user_handle_ptr
147 void release_user_handle_ptr( void *ptr )
149 assert( ptr && ptr != OBJ_OTHER_PROCESS );
154 /***********************************************************************
157 void *free_user_handle( HANDLE handle, enum user_obj_type type )
159 struct user_object *ptr;
160 WORD index = USER_HANDLE_TO_INDEX( handle );
162 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
164 SERVER_START_REQ( free_user_handle )
166 req->handle = wine_server_user_handle( handle );
167 if (wine_server_call( req )) ptr = NULL;
168 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
171 release_user_handle_ptr( ptr );
177 /***********************************************************************
178 * create_window_handle
180 * Create a window handle with the server.
182 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
183 HINSTANCE instance, BOOL unicode )
187 HWND handle = 0, full_parent = 0, full_owner = 0;
188 struct tagCLASS *class = NULL;
191 SERVER_START_REQ( create_window )
193 req->parent = wine_server_user_handle( parent );
194 req->owner = wine_server_user_handle( owner );
195 req->instance = wine_server_client_ptr( instance );
196 if (!(req->atom = get_int_atom_value( name )) && name)
197 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
198 if (!wine_server_call_err( req ))
200 handle = wine_server_ptr_handle( reply->handle );
201 full_parent = wine_server_ptr_handle( reply->parent );
202 full_owner = wine_server_ptr_handle( reply->owner );
203 extra_bytes = reply->extra;
204 class = wine_server_get_ptr( reply->class_ptr );
211 WARN( "error %d creating window\n", GetLastError() );
215 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
216 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
218 SERVER_START_REQ( destroy_window )
220 req->handle = wine_server_user_handle( handle );
221 wine_server_call( req );
224 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
228 if (!parent) /* if parent is 0 we don't have a desktop window yet */
230 struct user_thread_info *thread_info = get_user_thread_info();
232 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
234 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
235 else assert( full_parent == thread_info->top_window );
236 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
237 ERR( "failed to create desktop window\n" );
239 else /* HWND_MESSAGE parent */
241 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
247 index = USER_HANDLE_TO_INDEX(handle);
248 assert( index < NB_USER_HANDLES );
249 win->obj.handle = handle;
250 win->obj.type = USER_WINDOW;
251 win->parent = full_parent;
252 win->owner = full_owner;
254 win->winproc = get_class_winproc( class );
255 win->cbWndExtra = extra_bytes;
256 InterlockedExchangePointer( &user_handles[index], win );
257 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
262 /***********************************************************************
265 * Free a window handle.
267 static void free_window_handle( HWND hwnd )
269 struct user_object *ptr;
270 WORD index = USER_HANDLE_TO_INDEX(hwnd);
272 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
274 SERVER_START_REQ( destroy_window )
276 req->handle = wine_server_user_handle( hwnd );
277 if (wine_server_call_err( req )) ptr = NULL;
278 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
281 release_user_handle_ptr( ptr );
282 HeapFree( GetProcessHeap(), 0, ptr );
287 /*******************************************************************
288 * list_window_children
290 * Build an array of the children of a given window. The array must be
291 * freed with HeapFree. Returns NULL when no windows are found.
293 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
297 ATOM atom = get_int_atom_value( class );
299 /* empty class is not the same as NULL class */
300 if (!atom && class && !class[0]) return NULL;
306 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
308 SERVER_START_REQ( get_window_children )
310 req->desktop = wine_server_obj_handle( desktop );
311 req->parent = wine_server_user_handle( hwnd );
314 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
315 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
316 if (!wine_server_call( req )) count = reply->count;
319 if (count && count < size)
321 /* start from the end since HWND is potentially larger than user_handle_t */
322 for (i = count - 1; i >= 0; i--)
323 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
327 HeapFree( GetProcessHeap(), 0, list );
329 size = count + 1; /* restart with a large enough buffer */
335 /*******************************************************************
336 * list_window_parents
338 * Build an array of all parents of a given window, starting with
339 * the immediate parent. The array must be freed with HeapFree.
341 static HWND *list_window_parents( HWND hwnd )
345 int i, pos = 0, size = 16, count = 0;
347 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
352 if (!(win = WIN_GetPtr( current ))) goto empty;
353 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
354 if (win == WND_DESKTOP)
356 if (!pos) goto empty;
360 list[pos] = current = win->parent;
361 WIN_ReleasePtr( win );
362 if (!current) return list;
363 if (++pos == size - 1)
365 /* need to grow the list */
366 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
367 if (!new_list) goto empty;
373 /* at least one parent belongs to another process, have to query the server */
378 SERVER_START_REQ( get_window_parents )
380 req->handle = wine_server_user_handle( hwnd );
381 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
382 if (!wine_server_call( req )) count = reply->count;
385 if (!count) goto empty;
388 /* start from the end since HWND is potentially larger than user_handle_t */
389 for (i = count - 1; i >= 0; i--)
390 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
394 HeapFree( GetProcessHeap(), 0, list );
396 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
400 HeapFree( GetProcessHeap(), 0, list );
405 /*******************************************************************
408 static void send_parent_notify( HWND hwnd, UINT msg )
410 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
411 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
413 HWND parent = GetParent(hwnd);
414 if (parent && parent != GetDesktopWindow())
415 SendMessageW( parent, WM_PARENTNOTIFY,
416 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
421 /*******************************************************************
422 * get_server_window_text
424 * Retrieve the window text from the server.
426 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
430 SERVER_START_REQ( get_window_text )
432 req->handle = wine_server_user_handle( hwnd );
433 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
434 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
437 text[len / sizeof(WCHAR)] = 0;
441 /*******************************************************************
442 * get_hwnd_message_parent
444 * Return the parent for HWND_MESSAGE windows.
446 HWND get_hwnd_message_parent(void)
448 struct user_thread_info *thread_info = get_user_thread_info();
450 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
451 return thread_info->msg_window;
455 /*******************************************************************
458 * Check if window is the desktop or the HWND_MESSAGE top parent.
460 BOOL is_desktop_window( HWND hwnd )
462 struct user_thread_info *thread_info = get_user_thread_info();
464 if (!hwnd) return FALSE;
465 if (hwnd == thread_info->top_window) return TRUE;
466 if (hwnd == thread_info->msg_window) return TRUE;
468 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
470 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
471 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
477 /***********************************************************************
480 * Return a pointer to the WND structure if local to the process,
481 * or WND_OTHER_PROCESS if handle may be valid in other process.
482 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
484 WND *WIN_GetPtr( HWND hwnd )
488 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
490 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
496 /***********************************************************************
497 * WIN_IsCurrentProcess
499 * Check whether a given window belongs to the current process (and return the full handle).
501 HWND WIN_IsCurrentProcess( HWND hwnd )
506 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
507 ret = ptr->obj.handle;
508 WIN_ReleasePtr( ptr );
513 /***********************************************************************
514 * WIN_IsCurrentThread
516 * Check whether a given window belongs to the current thread (and return the full handle).
518 HWND WIN_IsCurrentThread( HWND hwnd )
523 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
524 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
525 WIN_ReleasePtr( ptr );
530 /***********************************************************************
533 * Convert a possibly truncated window handle to a full 32-bit handle.
535 HWND WIN_GetFullHandle( HWND hwnd )
539 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
540 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
541 /* do sign extension for -2 and -3 */
542 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
544 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
546 if (ptr == WND_DESKTOP)
548 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
549 else return get_hwnd_message_parent();
552 if (ptr != WND_OTHER_PROCESS)
554 hwnd = ptr->obj.handle;
555 WIN_ReleasePtr( ptr );
557 else /* may belong to another process */
559 SERVER_START_REQ( get_window_info )
561 req->handle = wine_server_user_handle( hwnd );
562 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
570 /***********************************************************************
573 * Change the owner of a window.
575 HWND WIN_SetOwner( HWND hwnd, HWND owner )
577 WND *win = WIN_GetPtr( hwnd );
580 if (!win || win == WND_DESKTOP) return 0;
581 if (win == WND_OTHER_PROCESS)
583 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
586 SERVER_START_REQ( set_window_owner )
588 req->handle = wine_server_user_handle( hwnd );
589 req->owner = wine_server_user_handle( owner );
590 if (!wine_server_call( req ))
592 win->owner = wine_server_ptr_handle( reply->full_owner );
593 ret = wine_server_ptr_handle( reply->prev_owner );
597 WIN_ReleasePtr( win );
602 /***********************************************************************
605 * Change the style of a window.
607 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
609 BOOL ok, needs_show = FALSE;
611 WND *win = WIN_GetPtr( hwnd );
613 if (!win || win == WND_DESKTOP) return 0;
614 if (win == WND_OTHER_PROCESS)
617 ERR( "cannot set style %x/%x on other process window %p\n",
618 set_bits, clear_bits, hwnd );
621 style.styleOld = win->dwStyle;
622 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
623 if (style.styleNew == style.styleOld)
625 WIN_ReleasePtr( win );
626 return style.styleNew;
628 SERVER_START_REQ( set_window_info )
630 req->handle = wine_server_user_handle( hwnd );
631 req->flags = SET_WIN_STYLE;
632 req->style = style.styleNew;
633 req->extra_offset = -1;
634 if ((ok = !wine_server_call( req )))
636 style.styleOld = reply->old_style;
637 win->dwStyle = style.styleNew;
642 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
644 /* Some apps try to make their window visible through WM_SETREDRAW.
645 * Only do that if the window was never explicitly hidden,
646 * because Steam messes with WM_SETREDRAW after hiding its windows. */
647 needs_show = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
648 invalidate_dce( win, NULL );
650 WIN_ReleasePtr( win );
656 RECT window_rect, client_rect;
657 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
658 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
659 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
660 &window_rect, &client_rect, NULL );
663 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
664 return style.styleOld;
668 /***********************************************************************
671 * Get the window and client rectangles.
673 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
675 WND *win = WIN_GetPtr( hwnd );
680 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
683 if (win == WND_DESKTOP)
686 rect.left = rect.top = 0;
687 if (hwnd == get_hwnd_message_parent())
694 rect.right = GetSystemMetrics(SM_CXSCREEN);
695 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
697 if (rectWindow) *rectWindow = rect;
698 if (rectClient) *rectClient = rect;
701 if (win != WND_OTHER_PROCESS)
703 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
708 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
709 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
710 if (win->dwExStyle & WS_EX_LAYOUTRTL)
711 mirror_rect( &win->rectClient, &window_rect );
714 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
715 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
716 if (win->dwExStyle & WS_EX_LAYOUTRTL)
717 mirror_rect( &win->rectWindow, &client_rect );
722 WND *parent = WIN_GetPtr( win->parent );
723 if (parent == WND_DESKTOP) break;
724 if (!parent || parent == WND_OTHER_PROCESS)
726 WIN_ReleasePtr( win );
729 if (parent->flags & WIN_CHILDREN_MOVED)
731 WIN_ReleasePtr( parent );
732 WIN_ReleasePtr( win );
735 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
737 mirror_rect( &parent->rectClient, &window_rect );
738 mirror_rect( &parent->rectClient, &client_rect );
740 WIN_ReleasePtr( parent );
746 WND *parent = WIN_GetPtr( win->parent );
747 if (parent == WND_DESKTOP) break;
748 if (!parent || parent == WND_OTHER_PROCESS)
750 WIN_ReleasePtr( win );
753 WIN_ReleasePtr( win );
754 if (parent->flags & WIN_CHILDREN_MOVED)
756 WIN_ReleasePtr( parent );
762 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
763 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
768 if (rectWindow) *rectWindow = window_rect;
769 if (rectClient) *rectClient = client_rect;
770 WIN_ReleasePtr( win );
775 SERVER_START_REQ( get_window_rectangles )
777 req->handle = wine_server_user_handle( hwnd );
778 req->relative = relative;
779 if ((ret = !wine_server_call_err( req )))
783 rectWindow->left = reply->window.left;
784 rectWindow->top = reply->window.top;
785 rectWindow->right = reply->window.right;
786 rectWindow->bottom = reply->window.bottom;
790 rectClient->left = reply->client.left;
791 rectClient->top = reply->client.top;
792 rectClient->right = reply->client.right;
793 rectClient->bottom = reply->client.bottom;
802 /***********************************************************************
805 * Destroy storage associated to a window. "Internals" p.358
807 LRESULT WIN_DestroyWindow( HWND hwnd )
811 HMENU menu = 0, sys_menu;
814 TRACE("%p\n", hwnd );
816 /* free child windows */
817 if ((list = WIN_ListChildren( hwnd )))
820 for (i = 0; list[i]; i++)
822 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
823 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
825 HeapFree( GetProcessHeap(), 0, list );
828 /* Unlink now so we won't bother with the children later on */
829 SERVER_START_REQ( set_parent )
831 req->handle = wine_server_user_handle( hwnd );
833 wine_server_call( req );
838 * Send the WM_NCDESTROY to the window being destroyed.
840 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
842 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
844 /* free resources associated with the window */
846 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
847 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
848 menu = (HMENU)wndPtr->wIDmenu;
849 sys_menu = wndPtr->hSysMenu;
850 free_dce( wndPtr->dce, hwnd );
852 icon_title = wndPtr->icon_title;
853 HeapFree( GetProcessHeap(), 0, wndPtr->text );
855 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
856 wndPtr->pScroll = NULL;
857 WIN_ReleasePtr( wndPtr );
859 if (icon_title) DestroyWindow( icon_title );
860 if (menu) DestroyMenu( menu );
861 if (sys_menu) DestroyMenu( sys_menu );
863 USER_Driver->pDestroyWindow( hwnd );
865 free_window_handle( hwnd );
870 /***********************************************************************
871 * destroy_thread_window
873 * Destroy a window upon exit of its thread.
875 static void destroy_thread_window( HWND hwnd )
879 HMENU menu = 0, sys_menu = 0;
882 /* free child windows */
884 if ((list = WIN_ListChildren( hwnd )))
887 for (i = 0; list[i]; i++)
889 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
890 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
892 HeapFree( GetProcessHeap(), 0, list );
895 /* destroy the client-side storage */
897 index = USER_HANDLE_TO_INDEX(hwnd);
898 if (index >= NB_USER_HANDLES) return;
900 if ((wndPtr = user_handles[index]))
902 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
903 sys_menu = wndPtr->hSysMenu;
904 free_dce( wndPtr->dce, hwnd );
905 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
909 HeapFree( GetProcessHeap(), 0, wndPtr );
910 if (menu) DestroyMenu( menu );
911 if (sys_menu) DestroyMenu( sys_menu );
915 /***********************************************************************
916 * destroy_thread_child_windows
918 * Destroy child windows upon exit of its thread.
920 static void destroy_thread_child_windows( HWND hwnd )
925 if (WIN_IsCurrentThread( hwnd ))
927 destroy_thread_window( hwnd );
929 else if ((list = WIN_ListChildren( hwnd )))
931 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
932 HeapFree( GetProcessHeap(), 0, list );
937 /***********************************************************************
938 * WIN_DestroyThreadWindows
940 * Destroy all children of 'wnd' owned by the current thread.
942 void WIN_DestroyThreadWindows( HWND hwnd )
947 if (!(list = WIN_ListChildren( hwnd ))) return;
949 /* reset owners of top-level windows */
950 for (i = 0; list[i]; i++)
952 if (!WIN_IsCurrentThread( list[i] ))
954 HWND owner = GetWindow( list[i], GW_OWNER );
955 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
959 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
960 HeapFree( GetProcessHeap(), 0, list );
964 /***********************************************************************
967 * Fix the coordinates - Helper for WIN_CreateWindowEx.
968 * returns default show mode in sw.
970 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
972 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
975 if (cs->dwExStyle & WS_EX_MDICHILD)
979 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
980 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
982 TRACE("MDI child id %04x\n", id);
985 if (cs->style & (WS_CHILD | WS_POPUP))
987 if (cs->dwExStyle & WS_EX_MDICHILD)
989 if (IS_DEFAULT(cs->x))
994 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
995 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
999 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1000 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1003 else /* overlapped window */
1006 MONITORINFO mon_info;
1009 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1011 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1012 mon_info.cbSize = sizeof(mon_info);
1013 GetMonitorInfoW( monitor, &mon_info );
1014 GetStartupInfoW( &info );
1016 if (IS_DEFAULT(cs->x))
1018 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1019 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1020 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1023 if (IS_DEFAULT(cs->cx))
1025 if (info.dwFlags & STARTF_USESIZE)
1027 cs->cx = info.dwXSize;
1028 cs->cy = info.dwYSize;
1032 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1033 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1036 /* neither x nor cx are default. Check the y values .
1037 * In the trace we see Outlook and Outlook Express using
1038 * cy set to CW_USEDEFAULT when opening the address book.
1040 else if (IS_DEFAULT(cs->cy))
1042 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1043 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1049 /***********************************************************************
1050 * dump_window_styles
1052 static void dump_window_styles( DWORD style, DWORD exstyle )
1055 if(style & WS_POPUP) TRACE(" WS_POPUP");
1056 if(style & WS_CHILD) TRACE(" WS_CHILD");
1057 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1058 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1059 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1060 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1061 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1062 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1063 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1066 if(style & WS_BORDER) TRACE(" WS_BORDER");
1067 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1069 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1070 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1071 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1072 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1073 if (style & WS_CHILD)
1075 if(style & WS_GROUP) TRACE(" WS_GROUP");
1076 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1080 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1081 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1084 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1085 #define DUMPED_STYLES \
1086 ((DWORD)(WS_POPUP | \
1105 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1107 #undef DUMPED_STYLES
1109 TRACE( "exstyle:" );
1110 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1111 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1112 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1113 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1114 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1115 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1116 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1117 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1118 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1119 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1120 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1121 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1122 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1123 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1124 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1125 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1126 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1127 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1128 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1130 #define DUMPED_EX_STYLES \
1131 ((DWORD)(WS_EX_DLGMODALFRAME | \
1132 WS_EX_DRAGDETECT | \
1133 WS_EX_NOPARENTNOTIFY | \
1135 WS_EX_ACCEPTFILES | \
1136 WS_EX_TRANSPARENT | \
1138 WS_EX_TOOLWINDOW | \
1139 WS_EX_WINDOWEDGE | \
1140 WS_EX_CLIENTEDGE | \
1141 WS_EX_CONTEXTHELP | \
1143 WS_EX_RTLREADING | \
1144 WS_EX_LEFTSCROLLBAR | \
1145 WS_EX_CONTROLPARENT | \
1146 WS_EX_STATICEDGE | \
1151 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1153 #undef DUMPED_EX_STYLES
1157 /***********************************************************************
1158 * WIN_CreateWindowEx
1160 * Implementation of CreateWindowEx().
1162 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1164 INT cx, cy, style, sw = SW_SHOW;
1168 HWND hwnd, parent, owner, top_child = 0;
1169 MDICREATESTRUCTW mdi_cs;
1170 CBT_CREATEWNDW cbtc;
1173 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1174 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1175 debugstr_w(className),
1176 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1177 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1178 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1180 /* Fix the styles for MDI children */
1181 if (cs->dwExStyle & WS_EX_MDICHILD)
1185 wndPtr = WIN_GetPtr(cs->hwndParent);
1186 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1188 flags = wndPtr->flags;
1189 WIN_ReleasePtr(wndPtr);
1192 if (!(flags & WIN_ISMDICLIENT))
1194 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1198 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1199 * MDICREATESTRUCT members have the originally passed values.
1201 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1202 * have the same layout.
1204 mdi_cs.szClass = cs->lpszClass;
1205 mdi_cs.szTitle = cs->lpszName;
1206 mdi_cs.hOwner = cs->hInstance;
1211 mdi_cs.style = cs->style;
1212 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1214 cs->lpCreateParams = &mdi_cs;
1216 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1218 if (cs->style & WS_POPUP)
1220 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1223 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1227 cs->style &= ~WS_POPUP;
1228 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1229 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1232 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1236 /* Restore current maximized child */
1237 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1239 TRACE("Restoring current maximized child %p\n", top_child);
1240 if (cs->style & WS_MAXIMIZE)
1242 /* if the new window is maximized don't bother repainting */
1243 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1244 ShowWindow( top_child, SW_SHOWNORMAL );
1245 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1247 else ShowWindow( top_child, SW_SHOWNORMAL );
1252 /* Find the parent window */
1254 parent = cs->hwndParent;
1257 if (cs->hwndParent == HWND_MESSAGE)
1259 cs->hwndParent = parent = get_hwnd_message_parent();
1261 else if (cs->hwndParent)
1263 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1265 parent = GetDesktopWindow();
1266 owner = cs->hwndParent;
1270 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1271 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1272 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1277 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1279 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1281 WARN("No parent for child window\n" );
1282 SetLastError(ERROR_TLW_WITH_WSCHILD);
1283 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1285 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1286 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1287 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1290 GetProcessDefaultLayout( &layout );
1291 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1292 parent = GetDesktopWindow();
1296 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1298 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1299 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1300 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1301 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1303 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1305 /* Create the window structure */
1307 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1309 hwnd = wndPtr->obj.handle;
1311 /* Fill the window structure */
1313 wndPtr->tid = GetCurrentThreadId();
1314 wndPtr->hInstance = cs->hInstance;
1315 wndPtr->text = NULL;
1316 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1317 wndPtr->dwExStyle = cs->dwExStyle;
1318 wndPtr->wIDmenu = 0;
1319 wndPtr->helpContext = 0;
1320 wndPtr->pScroll = NULL;
1321 wndPtr->userdata = 0;
1323 wndPtr->hIconSmall = 0;
1324 wndPtr->hSysMenu = 0;
1326 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1327 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1329 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1332 * Correct the window styles.
1334 * It affects only the style loaded into the WIN structure.
1337 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1339 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1340 if (!(wndPtr->dwStyle & WS_POPUP))
1341 wndPtr->dwStyle |= WS_CAPTION;
1344 /* WS_EX_WINDOWEDGE depends on some other styles */
1345 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1346 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1347 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1349 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1350 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1351 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1354 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1356 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1357 wndPtr->flags |= WIN_NEED_SIZE;
1359 SERVER_START_REQ( set_window_info )
1361 req->handle = wine_server_user_handle( hwnd );
1362 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1363 req->style = wndPtr->dwStyle;
1364 req->ex_style = wndPtr->dwExStyle;
1365 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1366 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1367 req->extra_offset = -1;
1368 wine_server_call( req );
1372 /* Set the window menu */
1374 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1378 if (!MENU_SetMenu(hwnd, cs->hMenu))
1380 WIN_ReleasePtr( wndPtr );
1381 free_window_handle( hwnd );
1387 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1390 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1391 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1395 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1397 /* call the WH_CBT hook */
1399 /* the window style passed to the hook must be the real window style,
1400 * rather than just the window style that the caller to CreateWindowEx
1401 * passed in, so we have to copy the original CREATESTRUCT and get the
1402 * the real style. */
1404 cbcs.style = wndPtr->dwStyle;
1406 cbtc.hwndInsertAfter = HWND_TOP;
1407 WIN_ReleasePtr( wndPtr );
1408 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1410 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1414 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1416 POINT maxSize, maxPos, minTrack, maxTrack;
1417 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1418 if (maxTrack.x < cx) cx = maxTrack.x;
1419 if (maxTrack.y < cy) cy = maxTrack.y;
1420 if (minTrack.x > cx) cx = minTrack.x;
1421 if (minTrack.y > cy) cy = minTrack.y;
1426 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1427 /* check for wraparound */
1428 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1429 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1430 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1432 /* send WM_NCCREATE */
1434 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1436 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1438 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1441 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1445 /* send WM_NCCALCSIZE */
1447 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1449 /* yes, even if the CBT hook was called with HWND_TOP */
1450 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1451 RECT client_rect = rect;
1453 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1454 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1455 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1456 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1457 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1461 /* send WM_CREATE */
1464 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1466 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1467 if (result == -1) goto failed;
1469 /* call the driver */
1471 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1473 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1475 /* send the size messages */
1477 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1478 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1479 if (!(wndPtr->flags & WIN_NEED_SIZE))
1481 WIN_ReleasePtr( wndPtr );
1482 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1483 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1484 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1485 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1487 else WIN_ReleasePtr( wndPtr );
1489 /* Show the window, maximizing or minimizing if needed */
1491 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1492 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1495 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1497 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1498 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1499 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1500 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1501 newPos.bottom - newPos.top, swFlag );
1504 /* Notify the parent window only */
1506 send_parent_notify( hwnd, WM_CREATE );
1507 if (!IsWindow( hwnd )) return 0;
1509 if (cs->style & WS_VISIBLE)
1511 if (cs->style & WS_MAXIMIZE)
1513 else if (cs->style & WS_MINIMIZE)
1514 sw = SW_SHOWMINIMIZED;
1516 ShowWindow( hwnd, sw );
1517 if (cs->dwExStyle & WS_EX_MDICHILD)
1519 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1520 /* ShowWindow won't activate child windows */
1521 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1525 /* Call WH_SHELL hook */
1527 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1528 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1530 TRACE("created window %p\n", hwnd);
1534 WIN_DestroyWindow( hwnd );
1539 /***********************************************************************
1540 * CreateWindowExA (USER32.@)
1542 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1543 LPCSTR windowName, DWORD style, INT x,
1544 INT y, INT width, INT height,
1545 HWND parent, HMENU menu,
1546 HINSTANCE instance, LPVOID data )
1550 cs.lpCreateParams = data;
1551 cs.hInstance = instance;
1553 cs.hwndParent = parent;
1559 cs.lpszName = windowName;
1560 cs.lpszClass = className;
1561 cs.dwExStyle = exStyle;
1563 if (!IS_INTRESOURCE(className))
1566 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1568 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1570 /* Note: we rely on the fact that CREATESTRUCTA and */
1571 /* CREATESTRUCTW have the same layout. */
1572 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1576 /***********************************************************************
1577 * CreateWindowExW (USER32.@)
1579 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1580 LPCWSTR windowName, DWORD style, INT x,
1581 INT y, INT width, INT height,
1582 HWND parent, HMENU menu,
1583 HINSTANCE instance, LPVOID data )
1587 cs.lpCreateParams = data;
1588 cs.hInstance = instance;
1590 cs.hwndParent = parent;
1596 cs.lpszName = windowName;
1597 cs.lpszClass = className;
1598 cs.dwExStyle = exStyle;
1600 return wow_handlers.create_window( &cs, className, instance, TRUE );
1604 /***********************************************************************
1605 * WIN_SendDestroyMsg
1607 static void WIN_SendDestroyMsg( HWND hwnd )
1611 info.cbSize = sizeof(info);
1612 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1614 if (hwnd == info.hwndCaret) DestroyCaret();
1615 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1619 * Send the WM_DESTROY to the window.
1621 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1624 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1625 * make sure that the window still exists when we come back.
1632 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1634 for (i = 0; pWndArray[i]; i++)
1636 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1638 HeapFree( GetProcessHeap(), 0, pWndArray );
1641 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1645 /***********************************************************************
1646 * DestroyWindow (USER32.@)
1648 BOOL WINAPI DestroyWindow( HWND hwnd )
1652 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1654 SetLastError( ERROR_ACCESS_DENIED );
1658 TRACE("(%p)\n", hwnd);
1662 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1664 if (MENU_IsMenuActive() == hwnd)
1667 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1671 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1672 send_parent_notify( hwnd, WM_DESTROY );
1674 else if (!GetWindow( hwnd, GW_OWNER ))
1676 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1677 /* FIXME: clean up palette - see "Internals" p.352 */
1680 if (!IsWindow(hwnd)) return TRUE;
1682 /* Hide the window */
1683 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1685 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1687 ShowWindow( hwnd, SW_HIDE );
1689 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1690 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1693 if (!IsWindow(hwnd)) return TRUE;
1695 /* Recursively destroy owned windows */
1702 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1705 for (i = 0; list[i]; i++)
1707 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1708 if (WIN_IsCurrentThread( list[i] ))
1710 DestroyWindow( list[i] );
1714 WIN_SetOwner( list[i], 0 );
1716 HeapFree( GetProcessHeap(), 0, list );
1718 if (!got_one) break;
1722 /* Send destroy messages */
1724 WIN_SendDestroyMsg( hwnd );
1725 if (!IsWindow( hwnd )) return TRUE;
1727 if (GetClipboardOwner() == hwnd)
1728 CLIPBOARD_ReleaseOwner();
1730 /* Destroy the window storage */
1732 WIN_DestroyWindow( hwnd );
1737 /***********************************************************************
1738 * CloseWindow (USER32.@)
1740 BOOL WINAPI CloseWindow( HWND hwnd )
1742 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1743 ShowWindow( hwnd, SW_MINIMIZE );
1748 /***********************************************************************
1749 * OpenIcon (USER32.@)
1751 BOOL WINAPI OpenIcon( HWND hwnd )
1753 if (!IsIconic( hwnd )) return FALSE;
1754 ShowWindow( hwnd, SW_SHOWNORMAL );
1759 /***********************************************************************
1760 * FindWindowExW (USER32.@)
1762 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1767 WCHAR *buffer = NULL;
1769 if (!parent && child) parent = GetDesktopWindow();
1770 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1774 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1775 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1778 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1782 child = WIN_GetFullHandle( child );
1783 while (list[i] && list[i] != child) i++;
1784 if (!list[i]) goto done;
1785 i++; /* start from next window */
1792 if (GetWindowTextW( list[i], buffer, len + 1 ))
1794 if (!strcmpiW( buffer, title )) break;
1798 if (!title[0]) break;
1806 HeapFree( GetProcessHeap(), 0, list );
1807 HeapFree( GetProcessHeap(), 0, buffer );
1813 /***********************************************************************
1814 * FindWindowA (USER32.@)
1816 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1818 HWND ret = FindWindowExA( 0, 0, className, title );
1819 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1824 /***********************************************************************
1825 * FindWindowExA (USER32.@)
1827 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1829 LPWSTR titleW = NULL;
1834 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1835 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1836 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1839 if (!IS_INTRESOURCE(className))
1842 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1843 hwnd = FindWindowExW( parent, child, classW, titleW );
1847 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1850 HeapFree( GetProcessHeap(), 0, titleW );
1855 /***********************************************************************
1856 * FindWindowW (USER32.@)
1858 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1860 return FindWindowExW( 0, 0, className, title );
1864 /**********************************************************************
1865 * GetDesktopWindow (USER32.@)
1867 HWND WINAPI GetDesktopWindow(void)
1869 struct user_thread_info *thread_info = get_user_thread_info();
1871 if (thread_info->top_window) return thread_info->top_window;
1873 SERVER_START_REQ( get_desktop_window )
1876 if (!wine_server_call( req ))
1878 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1879 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1884 if (!thread_info->top_window)
1886 USEROBJECTFLAGS flags;
1887 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1888 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1890 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1891 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1893 PROCESS_INFORMATION pi;
1894 WCHAR windir[MAX_PATH];
1895 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1896 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1899 memset( &si, 0, sizeof(si) );
1901 si.dwFlags = STARTF_USESTDHANDLES;
1904 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1906 GetSystemDirectoryW( windir, MAX_PATH );
1907 strcpyW( app, windir );
1908 strcatW( app, explorer );
1909 strcpyW( cmdline, app );
1910 strcatW( cmdline, args );
1912 Wow64DisableWow64FsRedirection( &redir );
1913 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1914 NULL, windir, &si, &pi ))
1916 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1917 WaitForInputIdle( pi.hProcess, 10000 );
1918 CloseHandle( pi.hThread );
1919 CloseHandle( pi.hProcess );
1921 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1922 Wow64RevertWow64FsRedirection( redir );
1924 else TRACE( "not starting explorer since winstation is not visible\n" );
1926 SERVER_START_REQ( get_desktop_window )
1929 if (!wine_server_call( req ))
1931 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1932 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1938 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1939 ERR( "failed to create desktop window\n" );
1941 return thread_info->top_window;
1945 /*******************************************************************
1946 * EnableWindow (USER32.@)
1948 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1953 if (is_broadcast(hwnd))
1955 SetLastError( ERROR_INVALID_PARAMETER );
1959 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1960 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1964 TRACE("( %p, %d )\n", hwnd, enable);
1966 retvalue = !IsWindowEnabled( hwnd );
1968 if (enable && retvalue)
1970 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1971 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1973 else if (!enable && !retvalue)
1977 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1979 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1981 if (hwnd == GetFocus())
1982 SetFocus( 0 ); /* A disabled window can't have the focus */
1984 capture_wnd = GetCapture();
1985 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1986 ReleaseCapture(); /* A disabled window can't capture the mouse */
1988 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1994 /***********************************************************************
1995 * IsWindowEnabled (USER32.@)
1997 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1999 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2003 /***********************************************************************
2004 * IsWindowUnicode (USER32.@)
2006 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2009 BOOL retvalue = FALSE;
2011 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2013 if (wndPtr == WND_DESKTOP) return TRUE;
2015 if (wndPtr != WND_OTHER_PROCESS)
2017 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2018 WIN_ReleasePtr( wndPtr );
2022 SERVER_START_REQ( get_window_info )
2024 req->handle = wine_server_user_handle( hwnd );
2025 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2033 /**********************************************************************
2036 * Helper function for GetWindowLong().
2038 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2040 LONG_PTR retvalue = 0;
2043 if (offset == GWLP_HWNDPARENT)
2045 HWND parent = GetAncestor( hwnd, GA_PARENT );
2046 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2047 return (ULONG_PTR)parent;
2050 if (!(wndPtr = WIN_GetPtr( hwnd )))
2052 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2056 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2058 if (offset == GWLP_WNDPROC)
2060 SetLastError( ERROR_ACCESS_DENIED );
2063 SERVER_START_REQ( set_window_info )
2065 req->handle = wine_server_user_handle( hwnd );
2066 req->flags = 0; /* don't set anything, just retrieve */
2067 req->extra_offset = (offset >= 0) ? offset : -1;
2068 req->extra_size = (offset >= 0) ? size : 0;
2069 if (!wine_server_call_err( req ))
2073 case GWL_STYLE: retvalue = reply->old_style; break;
2074 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2075 case GWLP_ID: retvalue = reply->old_id; break;
2076 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2077 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2079 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2080 else SetLastError( ERROR_INVALID_INDEX );
2089 /* now we have a valid wndPtr */
2093 if (offset > (int)(wndPtr->cbWndExtra - size))
2095 WARN("Invalid offset %d\n", offset );
2096 WIN_ReleasePtr( wndPtr );
2097 SetLastError( ERROR_INVALID_INDEX );
2100 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2102 /* Special case for dialog window procedure */
2103 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2104 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2105 WIN_ReleasePtr( wndPtr );
2111 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2112 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2113 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2114 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2115 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2117 /* This looks like a hack only for the edit control (see tests). This makes these controls
2118 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2119 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2121 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2122 retvalue = (ULONG_PTR)wndPtr->winproc;
2124 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2127 WARN("Unknown offset %d\n", offset );
2128 SetLastError( ERROR_INVALID_INDEX );
2131 WIN_ReleasePtr(wndPtr);
2136 /**********************************************************************
2139 * Helper function for SetWindowLong().
2141 * 0 is the failure code. However, in the case of failure SetLastError
2142 * must be set to distinguish between a 0 return value and a failure.
2144 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2147 BOOL ok, needs_show = FALSE;
2148 LONG_PTR retval = 0;
2151 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2153 if (is_broadcast(hwnd))
2155 SetLastError( ERROR_INVALID_PARAMETER );
2159 if (!(wndPtr = WIN_GetPtr( hwnd )))
2161 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2164 if (wndPtr == WND_DESKTOP)
2166 /* can't change anything on the desktop window */
2167 SetLastError( ERROR_ACCESS_DENIED );
2170 if (wndPtr == WND_OTHER_PROCESS)
2172 if (offset == GWLP_WNDPROC)
2174 SetLastError( ERROR_ACCESS_DENIED );
2177 if (offset > 32767 || offset < -32767)
2179 SetLastError( ERROR_INVALID_INDEX );
2182 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2185 /* first some special cases */
2189 style.styleOld = wndPtr->dwStyle;
2190 style.styleNew = newval;
2191 WIN_ReleasePtr( wndPtr );
2192 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2193 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2194 newval = style.styleNew;
2195 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2196 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2197 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2198 WS_EX_WINDOWEDGE too */
2201 style.styleOld = wndPtr->dwExStyle;
2202 style.styleNew = newval;
2203 WIN_ReleasePtr( wndPtr );
2204 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2205 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2206 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2207 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2208 /* WS_EX_WINDOWEDGE depends on some other styles */
2209 if (newval & WS_EX_DLGMODALFRAME)
2210 newval |= WS_EX_WINDOWEDGE;
2211 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2212 newval |= WS_EX_WINDOWEDGE;
2214 newval &= ~WS_EX_WINDOWEDGE;
2216 case GWLP_HWNDPARENT:
2217 if (wndPtr->parent == GetDesktopWindow())
2219 WIN_ReleasePtr( wndPtr );
2220 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2224 WIN_ReleasePtr( wndPtr );
2225 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2230 UINT old_flags = wndPtr->flags;
2231 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2232 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2233 if (proc) wndPtr->winproc = proc;
2234 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2235 else wndPtr->flags &= ~WIN_ISUNICODE;
2236 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2238 WIN_ReleasePtr( wndPtr );
2241 /* update is_unicode flag on the server side */
2245 case GWLP_HINSTANCE:
2249 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2250 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2252 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2253 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2254 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2255 WIN_ReleasePtr( wndPtr );
2260 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2262 WARN("Invalid offset %d\n", offset );
2263 WIN_ReleasePtr( wndPtr );
2264 SetLastError( ERROR_INVALID_INDEX );
2267 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2269 /* already set to the same value */
2270 WIN_ReleasePtr( wndPtr );
2276 SERVER_START_REQ( set_window_info )
2278 req->handle = wine_server_user_handle( hwnd );
2279 req->extra_offset = -1;
2283 req->flags = SET_WIN_STYLE;
2284 req->style = newval;
2287 req->flags = SET_WIN_EXSTYLE;
2288 req->ex_style = newval;
2291 req->flags = SET_WIN_ID;
2294 case GWLP_HINSTANCE:
2295 req->flags = SET_WIN_INSTANCE;
2296 req->instance = wine_server_client_ptr( (void *)newval );
2299 req->flags = SET_WIN_UNICODE;
2300 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2303 req->flags = SET_WIN_USERDATA;
2304 req->user_data = newval;
2307 req->flags = SET_WIN_EXTRA;
2308 req->extra_offset = offset;
2309 req->extra_size = size;
2310 set_win_data( &req->extra_value, newval, size );
2312 if ((ok = !wine_server_call_err( req )))
2317 wndPtr->dwStyle = newval;
2318 retval = reply->old_style;
2321 wndPtr->dwExStyle = newval;
2322 retval = reply->old_ex_style;
2325 wndPtr->wIDmenu = newval;
2326 retval = reply->old_id;
2328 case GWLP_HINSTANCE:
2329 wndPtr->hInstance = (HINSTANCE)newval;
2330 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2335 wndPtr->userdata = newval;
2336 retval = reply->old_user_data;
2339 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2340 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2347 if (offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
2349 needs_show = !(wndPtr->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
2350 invalidate_dce( wndPtr, NULL );
2352 WIN_ReleasePtr( wndPtr );
2358 RECT window_rect, client_rect;
2359 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
2360 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
2361 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
2362 &window_rect, &client_rect, NULL );
2364 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2366 style.styleOld = retval;
2367 style.styleNew = newval;
2368 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2369 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2376 /**********************************************************************
2377 * GetWindowWord (USER32.@)
2379 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2384 case GWLP_HINSTANCE:
2385 case GWLP_HWNDPARENT:
2390 WARN("Invalid offset %d\n", offset );
2391 SetLastError( ERROR_INVALID_INDEX );
2396 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2400 /**********************************************************************
2401 * GetWindowLongA (USER32.@)
2403 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2405 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2409 /**********************************************************************
2410 * GetWindowLongW (USER32.@)
2412 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2414 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2418 /**********************************************************************
2419 * SetWindowWord (USER32.@)
2421 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2426 case GWLP_HINSTANCE:
2427 case GWLP_HWNDPARENT:
2432 WARN("Invalid offset %d\n", offset );
2433 SetLastError( ERROR_INVALID_INDEX );
2438 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2442 /**********************************************************************
2443 * SetWindowLongA (USER32.@)
2445 * See SetWindowLongW.
2447 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2449 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2453 /**********************************************************************
2454 * SetWindowLongW (USER32.@) Set window attribute
2456 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2457 * value in a window's extra memory.
2459 * The _hwnd_ parameter specifies the window. is the handle to a
2460 * window that has extra memory. The _newval_ parameter contains the
2461 * new attribute or extra memory value. If positive, the _offset_
2462 * parameter is the byte-addressed location in the window's extra
2463 * memory to set. If negative, _offset_ specifies the window
2464 * attribute to set, and should be one of the following values:
2466 * GWL_EXSTYLE The window's extended window style
2468 * GWL_STYLE The window's window style.
2470 * GWLP_WNDPROC Pointer to the window's window procedure.
2472 * GWLP_HINSTANCE The window's pplication instance handle.
2474 * GWLP_ID The window's identifier.
2476 * GWLP_USERDATA The window's user-specified data.
2478 * If the window is a dialog box, the _offset_ parameter can be one of
2479 * the following values:
2481 * DWLP_DLGPROC The address of the window's dialog box procedure.
2483 * DWLP_MSGRESULT The return value of a message
2484 * that the dialog box procedure processed.
2486 * DWLP_USER Application specific information.
2490 * If successful, returns the previous value located at _offset_. Otherwise,
2495 * Extra memory for a window class is specified by a nonzero cbWndExtra
2496 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2497 * time of class creation.
2499 * Using GWL_WNDPROC to set a new window procedure effectively creates
2500 * a window subclass. Use CallWindowProc() in the new windows procedure
2501 * to pass messages to the superclass's window procedure.
2503 * The user data is reserved for use by the application which created
2506 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2507 * instead, call the EnableWindow() function to change the window's
2510 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2511 * SetParent() instead.
2514 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2515 * it sends WM_STYLECHANGING before changing the settings
2516 * and WM_STYLECHANGED afterwards.
2517 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2519 LONG WINAPI SetWindowLongW(
2520 HWND hwnd, /* [in] window to alter */
2521 INT offset, /* [in] offset, in bytes, of location to alter */
2522 LONG newval /* [in] new value of location */
2524 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2528 /*******************************************************************
2529 * GetWindowTextA (USER32.@)
2531 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2535 if (!lpString) return 0;
2537 if (WIN_IsCurrentProcess( hwnd ))
2538 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2540 /* when window belongs to other process, don't send a message */
2541 if (nMaxCount <= 0) return 0;
2542 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2543 get_server_window_text( hwnd, buffer, nMaxCount );
2544 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2545 lpString[nMaxCount-1] = 0;
2546 HeapFree( GetProcessHeap(), 0, buffer );
2547 return strlen(lpString);
2551 /*******************************************************************
2552 * InternalGetWindowText (USER32.@)
2554 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2558 if (nMaxCount <= 0) return 0;
2559 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2560 if (win == WND_DESKTOP) lpString[0] = 0;
2561 else if (win != WND_OTHER_PROCESS)
2563 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2564 else lpString[0] = 0;
2565 WIN_ReleasePtr( win );
2569 get_server_window_text( hwnd, lpString, nMaxCount );
2571 return strlenW(lpString);
2575 /*******************************************************************
2576 * GetWindowTextW (USER32.@)
2578 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2580 if (!lpString) return 0;
2582 if (WIN_IsCurrentProcess( hwnd ))
2583 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2585 /* when window belongs to other process, don't send a message */
2586 if (nMaxCount <= 0) return 0;
2587 get_server_window_text( hwnd, lpString, nMaxCount );
2588 return strlenW(lpString);
2592 /*******************************************************************
2593 * SetWindowTextA (USER32.@)
2594 * SetWindowText (USER32.@)
2596 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2598 if (is_broadcast(hwnd))
2600 SetLastError( ERROR_INVALID_PARAMETER );
2603 if (!WIN_IsCurrentProcess( hwnd ))
2604 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2605 debugstr_a(lpString), hwnd );
2606 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2610 /*******************************************************************
2611 * SetWindowTextW (USER32.@)
2613 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2615 if (is_broadcast(hwnd))
2617 SetLastError( ERROR_INVALID_PARAMETER );
2620 if (!WIN_IsCurrentProcess( hwnd ))
2621 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2622 debugstr_w(lpString), hwnd );
2623 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2627 /*******************************************************************
2628 * GetWindowTextLengthA (USER32.@)
2630 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2632 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2635 /*******************************************************************
2636 * GetWindowTextLengthW (USER32.@)
2638 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2640 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2644 /*******************************************************************
2645 * IsWindow (USER32.@)
2647 BOOL WINAPI IsWindow( HWND hwnd )
2652 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2653 if (ptr == WND_DESKTOP) return TRUE;
2655 if (ptr != WND_OTHER_PROCESS)
2657 WIN_ReleasePtr( ptr );
2661 /* check other processes */
2662 SERVER_START_REQ( get_window_info )
2664 req->handle = wine_server_user_handle( hwnd );
2665 ret = !wine_server_call_err( req );
2672 /***********************************************************************
2673 * GetWindowThreadProcessId (USER32.@)
2675 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2680 if (!(ptr = WIN_GetPtr( hwnd )))
2682 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2686 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2688 /* got a valid window */
2690 if (process) *process = GetCurrentProcessId();
2691 WIN_ReleasePtr( ptr );
2695 /* check other processes */
2696 SERVER_START_REQ( get_window_info )
2698 req->handle = wine_server_user_handle( hwnd );
2699 if (!wine_server_call_err( req ))
2701 tid = (DWORD)reply->tid;
2702 if (process) *process = (DWORD)reply->pid;
2710 /*****************************************************************
2711 * GetParent (USER32.@)
2713 HWND WINAPI GetParent( HWND hwnd )
2718 if (!(wndPtr = WIN_GetPtr( hwnd )))
2720 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2723 if (wndPtr == WND_DESKTOP) return 0;
2724 if (wndPtr == WND_OTHER_PROCESS)
2726 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2727 if (style & (WS_POPUP | WS_CHILD))
2729 SERVER_START_REQ( get_window_tree )
2731 req->handle = wine_server_user_handle( hwnd );
2732 if (!wine_server_call_err( req ))
2734 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2735 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2743 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2744 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2745 WIN_ReleasePtr( wndPtr );
2751 /*****************************************************************
2752 * GetAncestor (USER32.@)
2754 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2757 HWND *list, ret = 0;
2762 if (!(win = WIN_GetPtr( hwnd )))
2764 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2767 if (win == WND_DESKTOP) return 0;
2768 if (win != WND_OTHER_PROCESS)
2771 WIN_ReleasePtr( win );
2773 else /* need to query the server */
2775 SERVER_START_REQ( get_window_tree )
2777 req->handle = wine_server_user_handle( hwnd );
2778 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2785 if (!(list = list_window_parents( hwnd ))) return 0;
2787 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2791 while (list[count]) count++;
2792 ret = list[count - 2]; /* get the one before the desktop */
2794 HeapFree( GetProcessHeap(), 0, list );
2798 if (is_desktop_window( hwnd )) return 0;
2799 ret = WIN_GetFullHandle( hwnd );
2802 HWND parent = GetParent( ret );
2812 /*****************************************************************
2813 * SetParent (USER32.@)
2815 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2818 HWND old_parent = 0;
2824 if (is_broadcast(hwnd) || is_broadcast(parent))
2826 SetLastError(ERROR_INVALID_PARAMETER);
2830 if (!parent) parent = GetDesktopWindow();
2831 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2832 else parent = WIN_GetFullHandle( parent );
2834 if (!IsWindow( parent ))
2836 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2840 /* Some applications try to set a child as a parent */
2841 if (IsChild(hwnd, parent))
2843 SetLastError( ERROR_INVALID_PARAMETER );
2847 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2848 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2850 if (full_handle == parent)
2852 SetLastError( ERROR_INVALID_PARAMETER );
2856 /* Windows hides the window first, then shows it again
2857 * including the WM_SHOWWINDOW messages and all */
2858 was_visible = ShowWindow( hwnd, SW_HIDE );
2860 wndPtr = WIN_GetPtr( hwnd );
2861 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2863 pt.x = wndPtr->rectWindow.left;
2864 pt.y = wndPtr->rectWindow.top;
2866 SERVER_START_REQ( set_parent )
2868 req->handle = wine_server_user_handle( hwnd );
2869 req->parent = wine_server_user_handle( parent );
2870 if ((ret = !wine_server_call( req )))
2872 old_parent = wine_server_ptr_handle( reply->old_parent );
2873 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2878 WIN_ReleasePtr( wndPtr );
2881 USER_Driver->pSetParent( full_handle, parent, old_parent );
2883 /* SetParent additionally needs to make hwnd the topmost window
2884 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2885 WM_WINDOWPOSCHANGED notification messages.
2887 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
2889 if (was_visible) ShowWindow( hwnd, SW_SHOW );
2895 /*******************************************************************
2896 * IsChild (USER32.@)
2898 BOOL WINAPI IsChild( HWND parent, HWND child )
2900 HWND *list = list_window_parents( child );
2904 if (!list) return FALSE;
2905 parent = WIN_GetFullHandle( parent );
2906 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2907 ret = list[i] && list[i+1];
2908 HeapFree( GetProcessHeap(), 0, list );
2913 /***********************************************************************
2914 * IsWindowVisible (USER32.@)
2916 BOOL WINAPI IsWindowVisible( HWND hwnd )
2922 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2923 if (!(list = list_window_parents( hwnd ))) return TRUE;
2926 for (i = 0; list[i+1]; i++)
2927 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2928 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2930 HeapFree( GetProcessHeap(), 0, list );
2935 /***********************************************************************
2936 * WIN_IsWindowDrawable
2938 * hwnd is drawable when it is visible, all parents are not
2939 * minimized, and it is itself not minimized unless we are
2940 * trying to draw its default class icon.
2942 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2947 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2949 if (!(style & WS_VISIBLE)) return FALSE;
2950 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2952 if (!(list = list_window_parents( hwnd ))) return TRUE;
2955 for (i = 0; list[i+1]; i++)
2956 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2958 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2960 HeapFree( GetProcessHeap(), 0, list );
2965 /*******************************************************************
2966 * GetTopWindow (USER32.@)
2968 HWND WINAPI GetTopWindow( HWND hwnd )
2970 if (!hwnd) hwnd = GetDesktopWindow();
2971 return GetWindow( hwnd, GW_CHILD );
2975 /*******************************************************************
2976 * GetWindow (USER32.@)
2978 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2982 if (rel == GW_OWNER) /* this one may be available locally */
2984 WND *wndPtr = WIN_GetPtr( hwnd );
2987 SetLastError( ERROR_INVALID_HANDLE );
2990 if (wndPtr == WND_DESKTOP) return 0;
2991 if (wndPtr != WND_OTHER_PROCESS)
2993 retval = wndPtr->owner;
2994 WIN_ReleasePtr( wndPtr );
2997 /* else fall through to server call */
3000 SERVER_START_REQ( get_window_tree )
3002 req->handle = wine_server_user_handle( hwnd );
3003 if (!wine_server_call_err( req ))
3008 retval = wine_server_ptr_handle( reply->first_sibling );
3011 retval = wine_server_ptr_handle( reply->last_sibling );
3014 retval = wine_server_ptr_handle( reply->next_sibling );
3017 retval = wine_server_ptr_handle( reply->prev_sibling );
3020 retval = wine_server_ptr_handle( reply->owner );
3023 retval = wine_server_ptr_handle( reply->first_child );
3033 /*******************************************************************
3034 * ShowOwnedPopups (USER32.@)
3036 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3040 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3042 if (!win_array) return TRUE;
3044 while (win_array[count]) count++;
3045 while (--count >= 0)
3047 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3048 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3049 if (pWnd == WND_OTHER_PROCESS) continue;
3052 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3054 WIN_ReleasePtr( pWnd );
3055 /* In Windows, ShowOwnedPopups(TRUE) generates
3056 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3057 * regardless of the state of the owner
3059 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3065 if (pWnd->dwStyle & WS_VISIBLE)
3067 WIN_ReleasePtr( pWnd );
3068 /* In Windows, ShowOwnedPopups(FALSE) generates
3069 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3070 * regardless of the state of the owner
3072 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3076 WIN_ReleasePtr( pWnd );
3078 HeapFree( GetProcessHeap(), 0, win_array );
3083 /*******************************************************************
3084 * GetLastActivePopup (USER32.@)
3086 HWND WINAPI GetLastActivePopup( HWND hwnd )
3090 SERVER_START_REQ( get_window_info )
3092 req->handle = wine_server_user_handle( hwnd );
3093 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3100 /*******************************************************************
3103 * Build an array of the children of a given window. The array must be
3104 * freed with HeapFree. Returns NULL when no windows are found.
3106 HWND *WIN_ListChildren( HWND hwnd )
3110 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3113 return list_window_children( 0, hwnd, NULL, 0 );
3117 /*******************************************************************
3118 * EnumWindows (USER32.@)
3120 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3126 USER_CheckNotLock();
3128 /* We have to build a list of all windows first, to avoid */
3129 /* unpleasant side-effects, for instance if the callback */
3130 /* function changes the Z-order of the windows. */
3132 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3134 /* Now call the callback function for every window */
3136 for (i = 0; list[i]; i++)
3138 /* Make sure that the window still exists */
3139 if (!IsWindow( list[i] )) continue;
3140 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3142 HeapFree( GetProcessHeap(), 0, list );
3147 /**********************************************************************
3148 * EnumThreadWindows (USER32.@)
3150 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3156 USER_CheckNotLock();
3158 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3160 /* Now call the callback function for every window */
3162 for (i = 0; list[i]; i++)
3163 if (!(ret = func( list[i], lParam ))) break;
3164 HeapFree( GetProcessHeap(), 0, list );
3169 /***********************************************************************
3170 * EnumDesktopWindows (USER32.@)
3172 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3177 USER_CheckNotLock();
3179 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3181 for (i = 0; list[i]; i++)
3182 if (!func( list[i], lparam )) break;
3183 HeapFree( GetProcessHeap(), 0, list );
3188 /**********************************************************************
3189 * WIN_EnumChildWindows
3191 * Helper function for EnumChildWindows().
3193 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3198 for ( ; *list; list++)
3200 /* Make sure that the window still exists */
3201 if (!IsWindow( *list )) continue;
3202 /* Build children list first */
3203 childList = WIN_ListChildren( *list );
3205 ret = func( *list, lParam );
3209 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3210 HeapFree( GetProcessHeap(), 0, childList );
3212 if (!ret) return FALSE;
3218 /**********************************************************************
3219 * EnumChildWindows (USER32.@)
3221 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3226 USER_CheckNotLock();
3228 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3229 ret = WIN_EnumChildWindows( list, func, lParam );
3230 HeapFree( GetProcessHeap(), 0, list );
3235 /*******************************************************************
3236 * AnyPopup (USER32.@)
3238 BOOL WINAPI AnyPopup(void)
3242 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3244 if (!list) return FALSE;
3245 for (i = 0; list[i]; i++)
3247 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3249 retvalue = (list[i] != 0);
3250 HeapFree( GetProcessHeap(), 0, list );
3255 /*******************************************************************
3256 * FlashWindow (USER32.@)
3258 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3262 TRACE("%p\n", hWnd);
3264 if (IsIconic( hWnd ))
3266 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3268 wndPtr = WIN_GetPtr(hWnd);
3269 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3270 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3272 wndPtr->flags |= WIN_NCACTIVATED;
3276 wndPtr->flags &= ~WIN_NCACTIVATED;
3278 WIN_ReleasePtr( wndPtr );
3285 wndPtr = WIN_GetPtr(hWnd);
3286 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3287 hWnd = wndPtr->obj.handle; /* make it a full handle */
3289 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3290 else wparam = (hWnd == GetForegroundWindow());
3292 WIN_ReleasePtr( wndPtr );
3293 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3298 /*******************************************************************
3299 * FlashWindowEx (USER32.@)
3301 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3303 FIXME("%p\n", pfwi);
3307 /*******************************************************************
3308 * GetWindowContextHelpId (USER32.@)
3310 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3313 WND *wnd = WIN_GetPtr( hwnd );
3314 if (!wnd || wnd == WND_DESKTOP) return 0;
3315 if (wnd == WND_OTHER_PROCESS)
3317 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3320 retval = wnd->helpContext;
3321 WIN_ReleasePtr( wnd );
3326 /*******************************************************************
3327 * SetWindowContextHelpId (USER32.@)
3329 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3331 WND *wnd = WIN_GetPtr( hwnd );
3332 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3333 if (wnd == WND_OTHER_PROCESS)
3335 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3338 wnd->helpContext = id;
3339 WIN_ReleasePtr( wnd );
3344 /*******************************************************************
3345 * DragDetect (USER32.@)
3347 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3351 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3352 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3354 rect.left = pt.x - wDragWidth;
3355 rect.right = pt.x + wDragWidth;
3357 rect.top = pt.y - wDragHeight;
3358 rect.bottom = pt.y + wDragHeight;
3364 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3366 if( msg.message == WM_LBUTTONUP )
3371 if( msg.message == WM_MOUSEMOVE )
3374 tmp.x = (short)LOWORD(msg.lParam);
3375 tmp.y = (short)HIWORD(msg.lParam);
3376 if( !PtInRect( &rect, tmp ))
3388 /******************************************************************************
3389 * GetWindowModuleFileNameA (USER32.@)
3391 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3396 TRACE( "%p, %p, %u\n", hwnd, module, size );
3398 win = WIN_GetPtr( hwnd );
3399 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3401 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3404 hinst = win->hInstance;
3405 WIN_ReleasePtr( win );
3407 return GetModuleFileNameA( hinst, module, size );
3410 /******************************************************************************
3411 * GetWindowModuleFileNameW (USER32.@)
3413 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3418 TRACE( "%p, %p, %u\n", hwnd, module, size );
3420 win = WIN_GetPtr( hwnd );
3421 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3423 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3426 hinst = win->hInstance;
3427 WIN_ReleasePtr( win );
3429 return GetModuleFileNameW( hinst, module, size );
3432 /******************************************************************************
3433 * GetWindowInfo (USER32.@)
3435 * Note: tests show that Windows doesn't check cbSize of the structure.
3437 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3439 if (!pwi) return FALSE;
3440 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3442 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3443 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3444 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3446 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3447 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3449 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3450 pwi->wCreatorVersion = 0x0400;
3455 /******************************************************************************
3456 * SwitchDesktop (USER32.@)
3458 * NOTES: Sets the current input or interactive desktop.
3460 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3462 FIXME("(hwnd %p) stub!\n", hDesktop);
3466 /*****************************************************************************
3467 * SetLayeredWindowAttributes (USER32.@)
3469 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3473 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3475 SERVER_START_REQ( set_window_layered_info )
3477 req->handle = wine_server_user_handle( hwnd );
3478 req->color_key = key;
3481 ret = !wine_server_call_err( req );
3485 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3491 /*****************************************************************************
3492 * GetLayeredWindowAttributes (USER32.@)
3494 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3498 SERVER_START_REQ( get_window_layered_info )
3500 req->handle = wine_server_user_handle( hwnd );
3501 if ((ret = !wine_server_call_err( req )))
3503 if (key) *key = reply->color_key;
3504 if (alpha) *alpha = reply->alpha;
3505 if (flags) *flags = reply->flags;
3514 /*****************************************************************************
3515 * UpdateLayeredWindowIndirect (USER32.@)
3517 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3521 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3522 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3524 SetLastError( ERROR_INVALID_PARAMETER );
3528 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3530 int x = 0, y = 0, cx = 0, cy = 0;
3531 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3535 x = info->pptDst->x;
3536 y = info->pptDst->y;
3537 flags &= ~SWP_NOMOVE;
3541 cx = info->psize->cx;
3542 cy = info->psize->cy;
3543 flags &= ~SWP_NOSIZE;
3545 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3546 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3551 HDC hdc = GetWindowDC( hwnd );
3558 GetWindowRect( hwnd, &rect );
3559 OffsetRect( &rect, -rect.left, -rect.top);
3562 x = info->pptSrc->x;
3563 y = info->pptSrc->y;
3566 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3568 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3569 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3570 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3572 ReleaseDC( hwnd, hdc );
3576 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3577 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3578 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3579 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3584 /*****************************************************************************
3585 * UpdateLayeredWindow (USER32.@)
3587 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3588 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3591 UPDATELAYEREDWINDOWINFO info;
3593 info.cbSize = sizeof(info);
3594 info.hdcDst = hdcDst;
3595 info.pptDst = pptDst;
3597 info.hdcSrc = hdcSrc;
3598 info.pptSrc = pptSrc;
3600 info.pblend = pblend;
3601 info.dwFlags = dwFlags;
3602 info.prcDirty = NULL;
3603 return UpdateLayeredWindowIndirect( hwnd, &info );
3607 /******************************************************************************
3608 * GetProcessDefaultLayout [USER32.@]
3610 * Gets the default layout for parentless windows.
3612 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3616 SetLastError( ERROR_NOACCESS );
3619 if (process_layout == ~0u)
3621 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3622 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3623 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3624 '\\','%','0','4','x','%','0','4','x',
3625 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3626 WCHAR *str, buffer[MAX_PATH];
3627 DWORD i, len, version_layout = 0;
3628 DWORD user_lang = GetUserDefaultLangID();
3632 GetModuleFileNameW( 0, buffer, MAX_PATH );
3633 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3634 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3635 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3636 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3638 len /= sizeof(DWORD);
3639 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3640 if (i == len) /* try neutral language */
3641 for (i = 0; i < len; i++)
3642 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3643 if (i == len) i = 0; /* default to the first one */
3645 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3646 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3647 TRACE( "found description %s\n", debugstr_w( str ));
3648 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3651 HeapFree( GetProcessHeap(), 0, data );
3652 process_layout = version_layout;
3654 *layout = process_layout;
3659 /******************************************************************************
3660 * SetProcessDefaultLayout [USER32.@]
3662 * Sets the default layout for parentless windows.
3664 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3666 process_layout = layout;
3671 /* 64bit versions */
3673 #ifdef GetWindowLongPtrW
3674 #undef GetWindowLongPtrW
3677 #ifdef GetWindowLongPtrA
3678 #undef GetWindowLongPtrA
3681 #ifdef SetWindowLongPtrW
3682 #undef SetWindowLongPtrW
3685 #ifdef SetWindowLongPtrA
3686 #undef SetWindowLongPtrA
3689 /*****************************************************************************
3690 * GetWindowLongPtrW (USER32.@)
3692 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3694 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3697 /*****************************************************************************
3698 * GetWindowLongPtrA (USER32.@)
3700 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3702 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3705 /*****************************************************************************
3706 * SetWindowLongPtrW (USER32.@)
3708 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3710 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3713 /*****************************************************************************
3714 * SetWindowLongPtrA (USER32.@)
3716 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3718 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );