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/gdi_driver.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
42 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
43 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
45 static DWORD process_layout = ~0u;
47 static struct list window_surfaces = LIST_INIT( window_surfaces );
49 static CRITICAL_SECTION surfaces_section;
50 static CRITICAL_SECTION_DEBUG critsect_debug =
52 0, 0, &surfaces_section,
53 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
54 0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
56 static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };
58 /**********************************************************************/
60 /* helper for Get/SetWindowLong */
61 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
63 if (size == sizeof(WORD))
66 memcpy( &ret, ptr, sizeof(ret) );
69 else if (size == sizeof(DWORD))
72 memcpy( &ret, ptr, sizeof(ret) );
78 memcpy( &ret, ptr, sizeof(ret) );
83 /* helper for Get/SetWindowLong */
84 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
86 if (size == sizeof(WORD))
89 memcpy( ptr, &newval, sizeof(newval) );
91 else if (size == sizeof(DWORD))
94 memcpy( ptr, &newval, sizeof(newval) );
98 memcpy( ptr, &val, sizeof(val) );
103 static void *user_handles[NB_USER_HANDLES];
105 /***********************************************************************
108 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
112 SERVER_START_REQ( alloc_user_handle )
114 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
120 UINT index = USER_HANDLE_TO_INDEX( handle );
122 assert( index < NB_USER_HANDLES );
123 ptr->handle = handle;
125 InterlockedExchangePointer( &user_handles[index], ptr );
131 /***********************************************************************
132 * get_user_handle_ptr
134 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
136 struct user_object *ptr;
137 WORD index = USER_HANDLE_TO_INDEX( handle );
139 if (index >= NB_USER_HANDLES) return NULL;
142 if ((ptr = user_handles[index]))
144 if (ptr->type == type &&
145 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
146 !HIWORD(handle) || HIWORD(handle) == 0xffff))
150 else ptr = OBJ_OTHER_PROCESS;
156 /***********************************************************************
157 * release_user_handle_ptr
159 void release_user_handle_ptr( void *ptr )
161 assert( ptr && ptr != OBJ_OTHER_PROCESS );
166 /***********************************************************************
169 void *free_user_handle( HANDLE handle, enum user_obj_type type )
171 struct user_object *ptr;
172 WORD index = USER_HANDLE_TO_INDEX( handle );
174 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
176 SERVER_START_REQ( free_user_handle )
178 req->handle = wine_server_user_handle( handle );
179 if (wine_server_call( req )) ptr = NULL;
180 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
183 release_user_handle_ptr( ptr );
189 /***********************************************************************
190 * create_window_handle
192 * Create a window handle with the server.
194 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
195 HINSTANCE instance, BOOL unicode )
199 HWND handle = 0, full_parent = 0, full_owner = 0;
200 struct tagCLASS *class = NULL;
203 SERVER_START_REQ( create_window )
205 req->parent = wine_server_user_handle( parent );
206 req->owner = wine_server_user_handle( owner );
207 req->instance = wine_server_client_ptr( instance );
208 if (!(req->atom = get_int_atom_value( name )) && name)
209 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
210 if (!wine_server_call_err( req ))
212 handle = wine_server_ptr_handle( reply->handle );
213 full_parent = wine_server_ptr_handle( reply->parent );
214 full_owner = wine_server_ptr_handle( reply->owner );
215 extra_bytes = reply->extra;
216 class = wine_server_get_ptr( reply->class_ptr );
223 WARN( "error %d creating window\n", GetLastError() );
227 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
228 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
230 SERVER_START_REQ( destroy_window )
232 req->handle = wine_server_user_handle( handle );
233 wine_server_call( req );
236 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
240 if (!parent) /* if parent is 0 we don't have a desktop window yet */
242 struct user_thread_info *thread_info = get_user_thread_info();
244 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
246 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
247 else assert( full_parent == thread_info->top_window );
248 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
249 ERR( "failed to create desktop window\n" );
251 else /* HWND_MESSAGE parent */
253 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
259 index = USER_HANDLE_TO_INDEX(handle);
260 assert( index < NB_USER_HANDLES );
261 win->obj.handle = handle;
262 win->obj.type = USER_WINDOW;
263 win->parent = full_parent;
264 win->owner = full_owner;
266 win->winproc = get_class_winproc( class );
267 win->cbWndExtra = extra_bytes;
268 InterlockedExchangePointer( &user_handles[index], win );
269 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
274 /***********************************************************************
277 * Free a window handle.
279 static void free_window_handle( HWND hwnd )
281 struct user_object *ptr;
282 WORD index = USER_HANDLE_TO_INDEX(hwnd);
284 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
286 SERVER_START_REQ( destroy_window )
288 req->handle = wine_server_user_handle( hwnd );
289 if (wine_server_call_err( req )) ptr = NULL;
290 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
293 release_user_handle_ptr( ptr );
294 HeapFree( GetProcessHeap(), 0, ptr );
299 /*******************************************************************
300 * list_window_children
302 * Build an array of the children of a given window. The array must be
303 * freed with HeapFree. Returns NULL when no windows are found.
305 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
309 ATOM atom = get_int_atom_value( class );
311 /* empty class is not the same as NULL class */
312 if (!atom && class && !class[0]) return NULL;
318 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
320 SERVER_START_REQ( get_window_children )
322 req->desktop = wine_server_obj_handle( desktop );
323 req->parent = wine_server_user_handle( hwnd );
326 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
327 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
328 if (!wine_server_call( req )) count = reply->count;
331 if (count && count < size)
333 /* start from the end since HWND is potentially larger than user_handle_t */
334 for (i = count - 1; i >= 0; i--)
335 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
339 HeapFree( GetProcessHeap(), 0, list );
341 size = count + 1; /* restart with a large enough buffer */
347 /*******************************************************************
348 * list_window_parents
350 * Build an array of all parents of a given window, starting with
351 * the immediate parent. The array must be freed with HeapFree.
353 static HWND *list_window_parents( HWND hwnd )
357 int i, pos = 0, size = 16, count = 0;
359 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
364 if (!(win = WIN_GetPtr( current ))) goto empty;
365 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
366 if (win == WND_DESKTOP)
368 if (!pos) goto empty;
372 list[pos] = current = win->parent;
373 WIN_ReleasePtr( win );
374 if (!current) return list;
375 if (++pos == size - 1)
377 /* need to grow the list */
378 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
379 if (!new_list) goto empty;
385 /* at least one parent belongs to another process, have to query the server */
390 SERVER_START_REQ( get_window_parents )
392 req->handle = wine_server_user_handle( hwnd );
393 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
394 if (!wine_server_call( req )) count = reply->count;
397 if (!count) goto empty;
400 /* start from the end since HWND is potentially larger than user_handle_t */
401 for (i = count - 1; i >= 0; i--)
402 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
406 HeapFree( GetProcessHeap(), 0, list );
408 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
412 HeapFree( GetProcessHeap(), 0, list );
417 /*******************************************************************
420 static void send_parent_notify( HWND hwnd, UINT msg )
422 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
423 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
425 HWND parent = GetParent(hwnd);
426 if (parent && parent != GetDesktopWindow())
427 SendMessageW( parent, WM_PARENTNOTIFY,
428 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
433 /*******************************************************************
434 * get_server_window_text
436 * Retrieve the window text from the server.
438 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
442 SERVER_START_REQ( get_window_text )
444 req->handle = wine_server_user_handle( hwnd );
445 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
446 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
449 text[len / sizeof(WCHAR)] = 0;
453 /*******************************************************************
454 * get_hwnd_message_parent
456 * Return the parent for HWND_MESSAGE windows.
458 HWND get_hwnd_message_parent(void)
460 struct user_thread_info *thread_info = get_user_thread_info();
462 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
463 return thread_info->msg_window;
467 /*******************************************************************
470 * Check if window is the desktop or the HWND_MESSAGE top parent.
472 BOOL is_desktop_window( HWND hwnd )
474 struct user_thread_info *thread_info = get_user_thread_info();
476 if (!hwnd) return FALSE;
477 if (hwnd == thread_info->top_window) return TRUE;
478 if (hwnd == thread_info->msg_window) return TRUE;
480 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
482 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
483 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
489 /*******************************************************************
490 * register_window_surface
492 * Register a window surface in the global list, possibly replacing another one.
494 void register_window_surface( struct window_surface *old, struct window_surface *new )
496 if (old == new) return;
497 EnterCriticalSection( &surfaces_section );
498 if (old) list_remove( &old->entry );
499 if (new) list_add_tail( &window_surfaces, &new->entry );
500 LeaveCriticalSection( &surfaces_section );
504 /*******************************************************************
505 * flush_window_surfaces
507 * Flush pending output from all window surfaces.
509 void flush_window_surfaces( BOOL idle )
511 static DWORD last_idle;
513 struct window_surface *surface;
515 EnterCriticalSection( &surfaces_section );
516 now = GetTickCount();
517 if (idle) last_idle = now;
518 /* if not idle, we only flush if there's evidence that the app never goes idle */
519 else if ((int)(now - last_idle) < 1000) goto done;
521 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
522 surface->funcs->flush( surface );
524 LeaveCriticalSection( &surfaces_section );
528 /***********************************************************************
531 * Return a pointer to the WND structure if local to the process,
532 * or WND_OTHER_PROCESS if handle may be valid in other process.
533 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
535 WND *WIN_GetPtr( HWND hwnd )
539 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
541 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
547 /***********************************************************************
548 * WIN_IsCurrentProcess
550 * Check whether a given window belongs to the current process (and return the full handle).
552 HWND WIN_IsCurrentProcess( HWND hwnd )
557 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
558 ret = ptr->obj.handle;
559 WIN_ReleasePtr( ptr );
564 /***********************************************************************
565 * WIN_IsCurrentThread
567 * Check whether a given window belongs to the current thread (and return the full handle).
569 HWND WIN_IsCurrentThread( HWND hwnd )
574 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
575 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
576 WIN_ReleasePtr( ptr );
581 /***********************************************************************
584 * Convert a possibly truncated window handle to a full 32-bit handle.
586 HWND WIN_GetFullHandle( HWND hwnd )
590 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
591 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
592 /* do sign extension for -2 and -3 */
593 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
595 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
597 if (ptr == WND_DESKTOP)
599 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
600 else return get_hwnd_message_parent();
603 if (ptr != WND_OTHER_PROCESS)
605 hwnd = ptr->obj.handle;
606 WIN_ReleasePtr( ptr );
608 else /* may belong to another process */
610 SERVER_START_REQ( get_window_info )
612 req->handle = wine_server_user_handle( hwnd );
613 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
621 /***********************************************************************
624 * Change the owner of a window.
626 HWND WIN_SetOwner( HWND hwnd, HWND owner )
628 WND *win = WIN_GetPtr( hwnd );
631 if (!win || win == WND_DESKTOP) return 0;
632 if (win == WND_OTHER_PROCESS)
634 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
637 SERVER_START_REQ( set_window_owner )
639 req->handle = wine_server_user_handle( hwnd );
640 req->owner = wine_server_user_handle( owner );
641 if (!wine_server_call( req ))
643 win->owner = wine_server_ptr_handle( reply->full_owner );
644 ret = wine_server_ptr_handle( reply->prev_owner );
648 WIN_ReleasePtr( win );
653 /***********************************************************************
656 * Change the style of a window.
658 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
660 BOOL ok, needs_show = FALSE;
662 WND *win = WIN_GetPtr( hwnd );
664 if (!win || win == WND_DESKTOP) return 0;
665 if (win == WND_OTHER_PROCESS)
668 ERR( "cannot set style %x/%x on other process window %p\n",
669 set_bits, clear_bits, hwnd );
672 style.styleOld = win->dwStyle;
673 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
674 if (style.styleNew == style.styleOld)
676 WIN_ReleasePtr( win );
677 return style.styleNew;
679 SERVER_START_REQ( set_window_info )
681 req->handle = wine_server_user_handle( hwnd );
682 req->flags = SET_WIN_STYLE;
683 req->style = style.styleNew;
684 req->extra_offset = -1;
685 if ((ok = !wine_server_call( req )))
687 style.styleOld = reply->old_style;
688 win->dwStyle = style.styleNew;
693 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
695 /* Some apps try to make their window visible through WM_SETREDRAW.
696 * Only do that if the window was never explicitly hidden,
697 * because Steam messes with WM_SETREDRAW after hiding its windows. */
698 needs_show = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
699 invalidate_dce( win, NULL );
701 WIN_ReleasePtr( win );
707 RECT window_rect, client_rect;
708 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
709 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
710 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
711 &window_rect, &client_rect, NULL );
714 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
715 return style.styleOld;
719 /***********************************************************************
722 * Get the window and client rectangles.
724 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
726 WND *win = WIN_GetPtr( hwnd );
731 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
734 if (win == WND_DESKTOP)
737 rect.left = rect.top = 0;
738 if (hwnd == get_hwnd_message_parent())
745 rect.right = GetSystemMetrics(SM_CXSCREEN);
746 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
748 if (rectWindow) *rectWindow = rect;
749 if (rectClient) *rectClient = rect;
752 if (win != WND_OTHER_PROCESS)
754 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
759 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
760 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
761 if (win->dwExStyle & WS_EX_LAYOUTRTL)
762 mirror_rect( &win->rectClient, &window_rect );
765 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
766 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
767 if (win->dwExStyle & WS_EX_LAYOUTRTL)
768 mirror_rect( &win->rectWindow, &client_rect );
773 WND *parent = WIN_GetPtr( win->parent );
774 if (parent == WND_DESKTOP) break;
775 if (!parent || parent == WND_OTHER_PROCESS)
777 WIN_ReleasePtr( win );
780 if (parent->flags & WIN_CHILDREN_MOVED)
782 WIN_ReleasePtr( parent );
783 WIN_ReleasePtr( win );
786 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
788 mirror_rect( &parent->rectClient, &window_rect );
789 mirror_rect( &parent->rectClient, &client_rect );
791 WIN_ReleasePtr( parent );
797 WND *parent = WIN_GetPtr( win->parent );
798 if (parent == WND_DESKTOP) break;
799 if (!parent || parent == WND_OTHER_PROCESS)
801 WIN_ReleasePtr( win );
804 WIN_ReleasePtr( win );
805 if (parent->flags & WIN_CHILDREN_MOVED)
807 WIN_ReleasePtr( parent );
813 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
814 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
819 if (rectWindow) *rectWindow = window_rect;
820 if (rectClient) *rectClient = client_rect;
821 WIN_ReleasePtr( win );
826 SERVER_START_REQ( get_window_rectangles )
828 req->handle = wine_server_user_handle( hwnd );
829 req->relative = relative;
830 if ((ret = !wine_server_call_err( req )))
834 rectWindow->left = reply->window.left;
835 rectWindow->top = reply->window.top;
836 rectWindow->right = reply->window.right;
837 rectWindow->bottom = reply->window.bottom;
841 rectClient->left = reply->client.left;
842 rectClient->top = reply->client.top;
843 rectClient->right = reply->client.right;
844 rectClient->bottom = reply->client.bottom;
853 /***********************************************************************
856 * Destroy storage associated to a window. "Internals" p.358
858 LRESULT WIN_DestroyWindow( HWND hwnd )
862 HMENU menu = 0, sys_menu;
864 struct window_surface *surface;
866 TRACE("%p\n", hwnd );
868 /* free child windows */
869 if ((list = WIN_ListChildren( hwnd )))
872 for (i = 0; list[i]; i++)
874 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
875 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
877 HeapFree( GetProcessHeap(), 0, list );
880 /* Unlink now so we won't bother with the children later on */
881 SERVER_START_REQ( set_parent )
883 req->handle = wine_server_user_handle( hwnd );
885 wine_server_call( req );
890 * Send the WM_NCDESTROY to the window being destroyed.
892 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
894 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
896 /* free resources associated with the window */
898 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
899 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
900 menu = (HMENU)wndPtr->wIDmenu;
901 sys_menu = wndPtr->hSysMenu;
902 free_dce( wndPtr->dce, hwnd );
904 icon_title = wndPtr->icon_title;
905 HeapFree( GetProcessHeap(), 0, wndPtr->text );
907 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
908 wndPtr->pScroll = NULL;
909 surface = wndPtr->surface;
910 wndPtr->surface = NULL;
911 WIN_ReleasePtr( wndPtr );
913 if (icon_title) DestroyWindow( icon_title );
914 if (menu) DestroyMenu( menu );
915 if (sys_menu) DestroyMenu( sys_menu );
918 register_window_surface( surface, NULL );
919 window_surface_release( surface );
922 USER_Driver->pDestroyWindow( hwnd );
924 free_window_handle( hwnd );
929 /***********************************************************************
930 * destroy_thread_window
932 * Destroy a window upon exit of its thread.
934 static void destroy_thread_window( HWND hwnd )
938 HMENU menu = 0, sys_menu = 0;
939 struct window_surface *surface = NULL;
942 /* free child windows */
944 if ((list = WIN_ListChildren( hwnd )))
947 for (i = 0; list[i]; i++)
949 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
950 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
952 HeapFree( GetProcessHeap(), 0, list );
955 /* destroy the client-side storage */
957 index = USER_HANDLE_TO_INDEX(hwnd);
958 if (index >= NB_USER_HANDLES) return;
960 if ((wndPtr = user_handles[index]))
962 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
963 sys_menu = wndPtr->hSysMenu;
964 free_dce( wndPtr->dce, hwnd );
965 surface = wndPtr->surface;
966 wndPtr->surface = NULL;
967 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
971 HeapFree( GetProcessHeap(), 0, wndPtr );
972 if (menu) DestroyMenu( menu );
973 if (sys_menu) DestroyMenu( sys_menu );
976 register_window_surface( surface, NULL );
977 window_surface_release( surface );
982 /***********************************************************************
983 * destroy_thread_child_windows
985 * Destroy child windows upon exit of its thread.
987 static void destroy_thread_child_windows( HWND hwnd )
992 if (WIN_IsCurrentThread( hwnd ))
994 destroy_thread_window( hwnd );
996 else if ((list = WIN_ListChildren( hwnd )))
998 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
999 HeapFree( GetProcessHeap(), 0, list );
1004 /***********************************************************************
1005 * WIN_DestroyThreadWindows
1007 * Destroy all children of 'wnd' owned by the current thread.
1009 void WIN_DestroyThreadWindows( HWND hwnd )
1014 if (!(list = WIN_ListChildren( hwnd ))) return;
1016 /* reset owners of top-level windows */
1017 for (i = 0; list[i]; i++)
1019 if (!WIN_IsCurrentThread( list[i] ))
1021 HWND owner = GetWindow( list[i], GW_OWNER );
1022 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1026 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1027 HeapFree( GetProcessHeap(), 0, list );
1031 /***********************************************************************
1032 * WIN_FixCoordinates
1034 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1035 * returns default show mode in sw.
1037 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1039 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1042 if (cs->dwExStyle & WS_EX_MDICHILD)
1046 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1047 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1049 TRACE("MDI child id %04x\n", id);
1052 if (cs->style & (WS_CHILD | WS_POPUP))
1054 if (cs->dwExStyle & WS_EX_MDICHILD)
1056 if (IS_DEFAULT(cs->x))
1061 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1062 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1066 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1067 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1070 else /* overlapped window */
1073 MONITORINFO mon_info;
1076 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1078 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1079 mon_info.cbSize = sizeof(mon_info);
1080 GetMonitorInfoW( monitor, &mon_info );
1081 GetStartupInfoW( &info );
1083 if (IS_DEFAULT(cs->x))
1085 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1086 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1087 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1090 if (IS_DEFAULT(cs->cx))
1092 if (info.dwFlags & STARTF_USESIZE)
1094 cs->cx = info.dwXSize;
1095 cs->cy = info.dwYSize;
1099 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1100 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1103 /* neither x nor cx are default. Check the y values .
1104 * In the trace we see Outlook and Outlook Express using
1105 * cy set to CW_USEDEFAULT when opening the address book.
1107 else if (IS_DEFAULT(cs->cy))
1109 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1110 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1116 /***********************************************************************
1117 * dump_window_styles
1119 static void dump_window_styles( DWORD style, DWORD exstyle )
1122 if(style & WS_POPUP) TRACE(" WS_POPUP");
1123 if(style & WS_CHILD) TRACE(" WS_CHILD");
1124 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1125 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1126 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1127 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1128 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1129 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1130 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1133 if(style & WS_BORDER) TRACE(" WS_BORDER");
1134 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1136 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1137 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1138 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1139 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1140 if (style & WS_CHILD)
1142 if(style & WS_GROUP) TRACE(" WS_GROUP");
1143 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1147 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1148 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1151 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1152 #define DUMPED_STYLES \
1153 ((DWORD)(WS_POPUP | \
1172 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1174 #undef DUMPED_STYLES
1176 TRACE( "exstyle:" );
1177 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1178 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1179 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1180 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1181 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1182 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1183 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1184 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1185 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1186 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1187 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1188 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1189 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1190 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1191 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1192 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1193 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1194 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1195 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1197 #define DUMPED_EX_STYLES \
1198 ((DWORD)(WS_EX_DLGMODALFRAME | \
1199 WS_EX_DRAGDETECT | \
1200 WS_EX_NOPARENTNOTIFY | \
1202 WS_EX_ACCEPTFILES | \
1203 WS_EX_TRANSPARENT | \
1205 WS_EX_TOOLWINDOW | \
1206 WS_EX_WINDOWEDGE | \
1207 WS_EX_CLIENTEDGE | \
1208 WS_EX_CONTEXTHELP | \
1210 WS_EX_RTLREADING | \
1211 WS_EX_LEFTSCROLLBAR | \
1212 WS_EX_CONTROLPARENT | \
1213 WS_EX_STATICEDGE | \
1218 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1220 #undef DUMPED_EX_STYLES
1224 /***********************************************************************
1225 * WIN_CreateWindowEx
1227 * Implementation of CreateWindowEx().
1229 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1231 INT cx, cy, style, sw = SW_SHOW;
1235 HWND hwnd, parent, owner, top_child = 0;
1236 MDICREATESTRUCTW mdi_cs;
1237 CBT_CREATEWNDW cbtc;
1240 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1241 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1242 debugstr_w(className),
1243 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1244 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1245 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1247 /* Fix the styles for MDI children */
1248 if (cs->dwExStyle & WS_EX_MDICHILD)
1252 wndPtr = WIN_GetPtr(cs->hwndParent);
1253 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1255 flags = wndPtr->flags;
1256 WIN_ReleasePtr(wndPtr);
1259 if (!(flags & WIN_ISMDICLIENT))
1261 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1265 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1266 * MDICREATESTRUCT members have the originally passed values.
1268 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1269 * have the same layout.
1271 mdi_cs.szClass = cs->lpszClass;
1272 mdi_cs.szTitle = cs->lpszName;
1273 mdi_cs.hOwner = cs->hInstance;
1278 mdi_cs.style = cs->style;
1279 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1281 cs->lpCreateParams = &mdi_cs;
1283 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1285 if (cs->style & WS_POPUP)
1287 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1290 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1294 cs->style &= ~WS_POPUP;
1295 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1296 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1299 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1303 /* Restore current maximized child */
1304 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1306 TRACE("Restoring current maximized child %p\n", top_child);
1307 if (cs->style & WS_MAXIMIZE)
1309 /* if the new window is maximized don't bother repainting */
1310 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1311 ShowWindow( top_child, SW_SHOWNORMAL );
1312 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1314 else ShowWindow( top_child, SW_SHOWNORMAL );
1319 /* Find the parent window */
1321 parent = cs->hwndParent;
1324 if (cs->hwndParent == HWND_MESSAGE)
1326 cs->hwndParent = parent = get_hwnd_message_parent();
1328 else if (cs->hwndParent)
1330 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1332 parent = GetDesktopWindow();
1333 owner = cs->hwndParent;
1337 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1338 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1339 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1344 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1346 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1348 WARN("No parent for child window\n" );
1349 SetLastError(ERROR_TLW_WITH_WSCHILD);
1350 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1352 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1353 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1354 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1357 GetProcessDefaultLayout( &layout );
1358 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1359 parent = GetDesktopWindow();
1363 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1365 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1366 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1367 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1368 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1370 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1372 /* Create the window structure */
1374 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1376 hwnd = wndPtr->obj.handle;
1378 /* Fill the window structure */
1380 wndPtr->tid = GetCurrentThreadId();
1381 wndPtr->hInstance = cs->hInstance;
1382 wndPtr->text = NULL;
1383 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1384 wndPtr->dwExStyle = cs->dwExStyle;
1385 wndPtr->wIDmenu = 0;
1386 wndPtr->helpContext = 0;
1387 wndPtr->pScroll = NULL;
1388 wndPtr->userdata = 0;
1390 wndPtr->hIconSmall = 0;
1391 wndPtr->hSysMenu = 0;
1393 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1394 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1396 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1399 * Correct the window styles.
1401 * It affects only the style loaded into the WIN structure.
1404 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1406 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1407 if (!(wndPtr->dwStyle & WS_POPUP))
1408 wndPtr->dwStyle |= WS_CAPTION;
1411 /* WS_EX_WINDOWEDGE depends on some other styles */
1412 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1413 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1414 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1416 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1417 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1418 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1421 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1423 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1424 wndPtr->flags |= WIN_NEED_SIZE;
1426 SERVER_START_REQ( set_window_info )
1428 req->handle = wine_server_user_handle( hwnd );
1429 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1430 req->style = wndPtr->dwStyle;
1431 req->ex_style = wndPtr->dwExStyle;
1432 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1433 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1434 req->extra_offset = -1;
1435 wine_server_call( req );
1439 /* Set the window menu */
1441 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1445 if (!MENU_SetMenu(hwnd, cs->hMenu))
1447 WIN_ReleasePtr( wndPtr );
1448 free_window_handle( hwnd );
1454 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1457 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1458 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1462 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1464 /* call the WH_CBT hook */
1466 /* the window style passed to the hook must be the real window style,
1467 * rather than just the window style that the caller to CreateWindowEx
1468 * passed in, so we have to copy the original CREATESTRUCT and get the
1469 * the real style. */
1471 cbcs.style = wndPtr->dwStyle;
1473 cbtc.hwndInsertAfter = HWND_TOP;
1474 WIN_ReleasePtr( wndPtr );
1475 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1477 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1481 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1483 POINT maxSize, maxPos, minTrack, maxTrack;
1484 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1485 if (maxTrack.x < cx) cx = maxTrack.x;
1486 if (maxTrack.y < cy) cy = maxTrack.y;
1487 if (minTrack.x > cx) cx = minTrack.x;
1488 if (minTrack.y > cy) cy = minTrack.y;
1493 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1494 /* check for wraparound */
1495 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1496 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1497 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1499 /* send WM_NCCREATE */
1501 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1503 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1505 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1508 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1512 /* send WM_NCCALCSIZE */
1514 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1516 /* yes, even if the CBT hook was called with HWND_TOP */
1517 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1518 RECT client_rect = rect;
1520 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1521 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1522 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1523 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1524 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1528 /* send WM_CREATE */
1531 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1533 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1534 if (result == -1) goto failed;
1536 /* call the driver */
1538 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1540 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1542 /* send the size messages */
1544 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1545 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1546 if (!(wndPtr->flags & WIN_NEED_SIZE))
1548 WIN_ReleasePtr( wndPtr );
1549 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1550 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1551 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1552 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1554 else WIN_ReleasePtr( wndPtr );
1556 /* Show the window, maximizing or minimizing if needed */
1558 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1559 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1562 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1564 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1565 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1566 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1567 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1568 newPos.bottom - newPos.top, swFlag );
1571 /* Notify the parent window only */
1573 send_parent_notify( hwnd, WM_CREATE );
1574 if (!IsWindow( hwnd )) return 0;
1576 if (cs->style & WS_VISIBLE)
1578 if (cs->style & WS_MAXIMIZE)
1580 else if (cs->style & WS_MINIMIZE)
1581 sw = SW_SHOWMINIMIZED;
1583 ShowWindow( hwnd, sw );
1584 if (cs->dwExStyle & WS_EX_MDICHILD)
1586 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1587 /* ShowWindow won't activate child windows */
1588 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1592 /* Call WH_SHELL hook */
1594 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1595 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1597 TRACE("created window %p\n", hwnd);
1601 WIN_DestroyWindow( hwnd );
1606 /***********************************************************************
1607 * CreateWindowExA (USER32.@)
1609 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1610 LPCSTR windowName, DWORD style, INT x,
1611 INT y, INT width, INT height,
1612 HWND parent, HMENU menu,
1613 HINSTANCE instance, LPVOID data )
1617 cs.lpCreateParams = data;
1618 cs.hInstance = instance;
1620 cs.hwndParent = parent;
1626 cs.lpszName = windowName;
1627 cs.lpszClass = className;
1628 cs.dwExStyle = exStyle;
1630 if (!IS_INTRESOURCE(className))
1633 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1635 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1637 /* Note: we rely on the fact that CREATESTRUCTA and */
1638 /* CREATESTRUCTW have the same layout. */
1639 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1643 /***********************************************************************
1644 * CreateWindowExW (USER32.@)
1646 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1647 LPCWSTR windowName, DWORD style, INT x,
1648 INT y, INT width, INT height,
1649 HWND parent, HMENU menu,
1650 HINSTANCE instance, LPVOID data )
1654 cs.lpCreateParams = data;
1655 cs.hInstance = instance;
1657 cs.hwndParent = parent;
1663 cs.lpszName = windowName;
1664 cs.lpszClass = className;
1665 cs.dwExStyle = exStyle;
1667 return wow_handlers.create_window( &cs, className, instance, TRUE );
1671 /***********************************************************************
1672 * WIN_SendDestroyMsg
1674 static void WIN_SendDestroyMsg( HWND hwnd )
1678 info.cbSize = sizeof(info);
1679 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1681 if (hwnd == info.hwndCaret) DestroyCaret();
1682 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1686 * Send the WM_DESTROY to the window.
1688 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1691 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1692 * make sure that the window still exists when we come back.
1699 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1701 for (i = 0; pWndArray[i]; i++)
1703 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1705 HeapFree( GetProcessHeap(), 0, pWndArray );
1708 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1712 /***********************************************************************
1713 * DestroyWindow (USER32.@)
1715 BOOL WINAPI DestroyWindow( HWND hwnd )
1719 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1721 SetLastError( ERROR_ACCESS_DENIED );
1725 TRACE("(%p)\n", hwnd);
1729 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1731 if (MENU_IsMenuActive() == hwnd)
1734 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1738 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1739 send_parent_notify( hwnd, WM_DESTROY );
1741 else if (!GetWindow( hwnd, GW_OWNER ))
1743 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1744 /* FIXME: clean up palette - see "Internals" p.352 */
1747 if (!IsWindow(hwnd)) return TRUE;
1749 /* Hide the window */
1750 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1752 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1754 ShowWindow( hwnd, SW_HIDE );
1756 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1757 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1760 if (!IsWindow(hwnd)) return TRUE;
1762 /* Recursively destroy owned windows */
1769 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1772 for (i = 0; list[i]; i++)
1774 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1775 if (WIN_IsCurrentThread( list[i] ))
1777 DestroyWindow( list[i] );
1781 WIN_SetOwner( list[i], 0 );
1783 HeapFree( GetProcessHeap(), 0, list );
1785 if (!got_one) break;
1789 /* Send destroy messages */
1791 WIN_SendDestroyMsg( hwnd );
1792 if (!IsWindow( hwnd )) return TRUE;
1794 if (GetClipboardOwner() == hwnd)
1795 CLIPBOARD_ReleaseOwner();
1797 /* Destroy the window storage */
1799 WIN_DestroyWindow( hwnd );
1804 /***********************************************************************
1805 * CloseWindow (USER32.@)
1807 BOOL WINAPI CloseWindow( HWND hwnd )
1809 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1810 ShowWindow( hwnd, SW_MINIMIZE );
1815 /***********************************************************************
1816 * OpenIcon (USER32.@)
1818 BOOL WINAPI OpenIcon( HWND hwnd )
1820 if (!IsIconic( hwnd )) return FALSE;
1821 ShowWindow( hwnd, SW_SHOWNORMAL );
1826 /***********************************************************************
1827 * FindWindowExW (USER32.@)
1829 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1834 WCHAR *buffer = NULL;
1836 if (!parent && child) parent = GetDesktopWindow();
1837 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1841 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1842 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1845 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1849 child = WIN_GetFullHandle( child );
1850 while (list[i] && list[i] != child) i++;
1851 if (!list[i]) goto done;
1852 i++; /* start from next window */
1859 if (GetWindowTextW( list[i], buffer, len + 1 ))
1861 if (!strcmpiW( buffer, title )) break;
1865 if (!title[0]) break;
1873 HeapFree( GetProcessHeap(), 0, list );
1874 HeapFree( GetProcessHeap(), 0, buffer );
1880 /***********************************************************************
1881 * FindWindowA (USER32.@)
1883 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1885 HWND ret = FindWindowExA( 0, 0, className, title );
1886 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1891 /***********************************************************************
1892 * FindWindowExA (USER32.@)
1894 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1896 LPWSTR titleW = NULL;
1901 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1902 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1903 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1906 if (!IS_INTRESOURCE(className))
1909 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1910 hwnd = FindWindowExW( parent, child, classW, titleW );
1914 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1917 HeapFree( GetProcessHeap(), 0, titleW );
1922 /***********************************************************************
1923 * FindWindowW (USER32.@)
1925 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1927 return FindWindowExW( 0, 0, className, title );
1931 /**********************************************************************
1932 * GetDesktopWindow (USER32.@)
1934 HWND WINAPI GetDesktopWindow(void)
1936 struct user_thread_info *thread_info = get_user_thread_info();
1938 if (thread_info->top_window) return thread_info->top_window;
1940 SERVER_START_REQ( get_desktop_window )
1943 if (!wine_server_call( req ))
1945 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1946 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1951 if (!thread_info->top_window)
1953 USEROBJECTFLAGS flags;
1954 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1955 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1957 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1958 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1960 PROCESS_INFORMATION pi;
1961 WCHAR windir[MAX_PATH];
1962 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1963 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1966 memset( &si, 0, sizeof(si) );
1968 si.dwFlags = STARTF_USESTDHANDLES;
1971 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1973 GetSystemDirectoryW( windir, MAX_PATH );
1974 strcpyW( app, windir );
1975 strcatW( app, explorer );
1976 strcpyW( cmdline, app );
1977 strcatW( cmdline, args );
1979 Wow64DisableWow64FsRedirection( &redir );
1980 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1981 NULL, windir, &si, &pi ))
1983 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1984 WaitForInputIdle( pi.hProcess, 10000 );
1985 CloseHandle( pi.hThread );
1986 CloseHandle( pi.hProcess );
1988 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1989 Wow64RevertWow64FsRedirection( redir );
1991 else TRACE( "not starting explorer since winstation is not visible\n" );
1993 SERVER_START_REQ( get_desktop_window )
1996 if (!wine_server_call( req ))
1998 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1999 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2005 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2006 ERR( "failed to create desktop window\n" );
2008 return thread_info->top_window;
2012 /*******************************************************************
2013 * EnableWindow (USER32.@)
2015 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2020 if (is_broadcast(hwnd))
2022 SetLastError( ERROR_INVALID_PARAMETER );
2026 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2027 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2031 TRACE("( %p, %d )\n", hwnd, enable);
2033 retvalue = !IsWindowEnabled( hwnd );
2035 if (enable && retvalue)
2037 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2038 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2040 else if (!enable && !retvalue)
2044 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2046 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2048 if (hwnd == GetFocus())
2049 SetFocus( 0 ); /* A disabled window can't have the focus */
2051 capture_wnd = GetCapture();
2052 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2053 ReleaseCapture(); /* A disabled window can't capture the mouse */
2055 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2061 /***********************************************************************
2062 * IsWindowEnabled (USER32.@)
2064 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2066 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2070 /***********************************************************************
2071 * IsWindowUnicode (USER32.@)
2073 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2076 BOOL retvalue = FALSE;
2078 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2080 if (wndPtr == WND_DESKTOP) return TRUE;
2082 if (wndPtr != WND_OTHER_PROCESS)
2084 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2085 WIN_ReleasePtr( wndPtr );
2089 SERVER_START_REQ( get_window_info )
2091 req->handle = wine_server_user_handle( hwnd );
2092 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2100 /**********************************************************************
2103 * Helper function for GetWindowLong().
2105 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2107 LONG_PTR retvalue = 0;
2110 if (offset == GWLP_HWNDPARENT)
2112 HWND parent = GetAncestor( hwnd, GA_PARENT );
2113 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2114 return (ULONG_PTR)parent;
2117 if (!(wndPtr = WIN_GetPtr( hwnd )))
2119 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2123 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2125 if (offset == GWLP_WNDPROC)
2127 SetLastError( ERROR_ACCESS_DENIED );
2130 SERVER_START_REQ( set_window_info )
2132 req->handle = wine_server_user_handle( hwnd );
2133 req->flags = 0; /* don't set anything, just retrieve */
2134 req->extra_offset = (offset >= 0) ? offset : -1;
2135 req->extra_size = (offset >= 0) ? size : 0;
2136 if (!wine_server_call_err( req ))
2140 case GWL_STYLE: retvalue = reply->old_style; break;
2141 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2142 case GWLP_ID: retvalue = reply->old_id; break;
2143 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2144 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2146 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2147 else SetLastError( ERROR_INVALID_INDEX );
2156 /* now we have a valid wndPtr */
2160 if (offset > (int)(wndPtr->cbWndExtra - size))
2162 WARN("Invalid offset %d\n", offset );
2163 WIN_ReleasePtr( wndPtr );
2164 SetLastError( ERROR_INVALID_INDEX );
2167 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2169 /* Special case for dialog window procedure */
2170 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2171 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2172 WIN_ReleasePtr( wndPtr );
2178 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2179 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2180 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2181 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2182 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2184 /* This looks like a hack only for the edit control (see tests). This makes these controls
2185 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2186 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2188 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2189 retvalue = (ULONG_PTR)wndPtr->winproc;
2191 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2194 WARN("Unknown offset %d\n", offset );
2195 SetLastError( ERROR_INVALID_INDEX );
2198 WIN_ReleasePtr(wndPtr);
2203 /**********************************************************************
2206 * Helper function for SetWindowLong().
2208 * 0 is the failure code. However, in the case of failure SetLastError
2209 * must be set to distinguish between a 0 return value and a failure.
2211 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2214 BOOL ok, needs_show = FALSE;
2215 LONG_PTR retval = 0;
2218 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2220 if (is_broadcast(hwnd))
2222 SetLastError( ERROR_INVALID_PARAMETER );
2226 if (!(wndPtr = WIN_GetPtr( hwnd )))
2228 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2231 if (wndPtr == WND_DESKTOP)
2233 /* can't change anything on the desktop window */
2234 SetLastError( ERROR_ACCESS_DENIED );
2237 if (wndPtr == WND_OTHER_PROCESS)
2239 if (offset == GWLP_WNDPROC)
2241 SetLastError( ERROR_ACCESS_DENIED );
2244 if (offset > 32767 || offset < -32767)
2246 SetLastError( ERROR_INVALID_INDEX );
2249 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2252 /* first some special cases */
2256 style.styleOld = wndPtr->dwStyle;
2257 style.styleNew = newval;
2258 WIN_ReleasePtr( wndPtr );
2259 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2260 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2261 newval = style.styleNew;
2262 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2263 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2264 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2265 WS_EX_WINDOWEDGE too */
2268 style.styleOld = wndPtr->dwExStyle;
2269 style.styleNew = newval;
2270 WIN_ReleasePtr( wndPtr );
2271 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2272 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2273 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2274 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2275 /* WS_EX_WINDOWEDGE depends on some other styles */
2276 if (newval & WS_EX_DLGMODALFRAME)
2277 newval |= WS_EX_WINDOWEDGE;
2278 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2279 newval |= WS_EX_WINDOWEDGE;
2281 newval &= ~WS_EX_WINDOWEDGE;
2283 case GWLP_HWNDPARENT:
2284 if (wndPtr->parent == GetDesktopWindow())
2286 WIN_ReleasePtr( wndPtr );
2287 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2291 WIN_ReleasePtr( wndPtr );
2292 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2297 UINT old_flags = wndPtr->flags;
2298 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2299 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2300 if (proc) wndPtr->winproc = proc;
2301 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2302 else wndPtr->flags &= ~WIN_ISUNICODE;
2303 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2305 WIN_ReleasePtr( wndPtr );
2308 /* update is_unicode flag on the server side */
2312 case GWLP_HINSTANCE:
2316 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2317 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2319 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2320 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2321 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2322 WIN_ReleasePtr( wndPtr );
2327 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2329 WARN("Invalid offset %d\n", offset );
2330 WIN_ReleasePtr( wndPtr );
2331 SetLastError( ERROR_INVALID_INDEX );
2334 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2336 /* already set to the same value */
2337 WIN_ReleasePtr( wndPtr );
2343 SERVER_START_REQ( set_window_info )
2345 req->handle = wine_server_user_handle( hwnd );
2346 req->extra_offset = -1;
2350 req->flags = SET_WIN_STYLE;
2351 req->style = newval;
2354 req->flags = SET_WIN_EXSTYLE;
2355 req->ex_style = newval;
2358 req->flags = SET_WIN_ID;
2361 case GWLP_HINSTANCE:
2362 req->flags = SET_WIN_INSTANCE;
2363 req->instance = wine_server_client_ptr( (void *)newval );
2366 req->flags = SET_WIN_UNICODE;
2367 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2370 req->flags = SET_WIN_USERDATA;
2371 req->user_data = newval;
2374 req->flags = SET_WIN_EXTRA;
2375 req->extra_offset = offset;
2376 req->extra_size = size;
2377 set_win_data( &req->extra_value, newval, size );
2379 if ((ok = !wine_server_call_err( req )))
2384 wndPtr->dwStyle = newval;
2385 retval = reply->old_style;
2388 wndPtr->dwExStyle = newval;
2389 retval = reply->old_ex_style;
2392 wndPtr->wIDmenu = newval;
2393 retval = reply->old_id;
2395 case GWLP_HINSTANCE:
2396 wndPtr->hInstance = (HINSTANCE)newval;
2397 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2402 wndPtr->userdata = newval;
2403 retval = reply->old_user_data;
2406 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2407 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2414 if (offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
2416 needs_show = !(wndPtr->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
2417 invalidate_dce( wndPtr, NULL );
2419 WIN_ReleasePtr( wndPtr );
2425 RECT window_rect, client_rect;
2426 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
2427 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
2428 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
2429 &window_rect, &client_rect, NULL );
2431 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2433 style.styleOld = retval;
2434 style.styleNew = newval;
2435 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2436 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2443 /**********************************************************************
2444 * GetWindowWord (USER32.@)
2446 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2451 case GWLP_HINSTANCE:
2452 case GWLP_HWNDPARENT:
2457 WARN("Invalid offset %d\n", offset );
2458 SetLastError( ERROR_INVALID_INDEX );
2463 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2467 /**********************************************************************
2468 * GetWindowLongA (USER32.@)
2470 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2472 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2476 /**********************************************************************
2477 * GetWindowLongW (USER32.@)
2479 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2481 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2485 /**********************************************************************
2486 * SetWindowWord (USER32.@)
2488 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2493 case GWLP_HINSTANCE:
2494 case GWLP_HWNDPARENT:
2499 WARN("Invalid offset %d\n", offset );
2500 SetLastError( ERROR_INVALID_INDEX );
2505 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2509 /**********************************************************************
2510 * SetWindowLongA (USER32.@)
2512 * See SetWindowLongW.
2514 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2516 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2520 /**********************************************************************
2521 * SetWindowLongW (USER32.@) Set window attribute
2523 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2524 * value in a window's extra memory.
2526 * The _hwnd_ parameter specifies the window. is the handle to a
2527 * window that has extra memory. The _newval_ parameter contains the
2528 * new attribute or extra memory value. If positive, the _offset_
2529 * parameter is the byte-addressed location in the window's extra
2530 * memory to set. If negative, _offset_ specifies the window
2531 * attribute to set, and should be one of the following values:
2533 * GWL_EXSTYLE The window's extended window style
2535 * GWL_STYLE The window's window style.
2537 * GWLP_WNDPROC Pointer to the window's window procedure.
2539 * GWLP_HINSTANCE The window's pplication instance handle.
2541 * GWLP_ID The window's identifier.
2543 * GWLP_USERDATA The window's user-specified data.
2545 * If the window is a dialog box, the _offset_ parameter can be one of
2546 * the following values:
2548 * DWLP_DLGPROC The address of the window's dialog box procedure.
2550 * DWLP_MSGRESULT The return value of a message
2551 * that the dialog box procedure processed.
2553 * DWLP_USER Application specific information.
2557 * If successful, returns the previous value located at _offset_. Otherwise,
2562 * Extra memory for a window class is specified by a nonzero cbWndExtra
2563 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2564 * time of class creation.
2566 * Using GWL_WNDPROC to set a new window procedure effectively creates
2567 * a window subclass. Use CallWindowProc() in the new windows procedure
2568 * to pass messages to the superclass's window procedure.
2570 * The user data is reserved for use by the application which created
2573 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2574 * instead, call the EnableWindow() function to change the window's
2577 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2578 * SetParent() instead.
2581 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2582 * it sends WM_STYLECHANGING before changing the settings
2583 * and WM_STYLECHANGED afterwards.
2584 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2586 LONG WINAPI SetWindowLongW(
2587 HWND hwnd, /* [in] window to alter */
2588 INT offset, /* [in] offset, in bytes, of location to alter */
2589 LONG newval /* [in] new value of location */
2591 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2595 /*******************************************************************
2596 * GetWindowTextA (USER32.@)
2598 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2602 if (!lpString) return 0;
2604 if (WIN_IsCurrentProcess( hwnd ))
2605 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2607 /* when window belongs to other process, don't send a message */
2608 if (nMaxCount <= 0) return 0;
2609 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2610 get_server_window_text( hwnd, buffer, nMaxCount );
2611 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2612 lpString[nMaxCount-1] = 0;
2613 HeapFree( GetProcessHeap(), 0, buffer );
2614 return strlen(lpString);
2618 /*******************************************************************
2619 * InternalGetWindowText (USER32.@)
2621 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2625 if (nMaxCount <= 0) return 0;
2626 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2627 if (win == WND_DESKTOP) lpString[0] = 0;
2628 else if (win != WND_OTHER_PROCESS)
2630 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2631 else lpString[0] = 0;
2632 WIN_ReleasePtr( win );
2636 get_server_window_text( hwnd, lpString, nMaxCount );
2638 return strlenW(lpString);
2642 /*******************************************************************
2643 * GetWindowTextW (USER32.@)
2645 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2647 if (!lpString) return 0;
2649 if (WIN_IsCurrentProcess( hwnd ))
2650 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2652 /* when window belongs to other process, don't send a message */
2653 if (nMaxCount <= 0) return 0;
2654 get_server_window_text( hwnd, lpString, nMaxCount );
2655 return strlenW(lpString);
2659 /*******************************************************************
2660 * SetWindowTextA (USER32.@)
2661 * SetWindowText (USER32.@)
2663 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2665 if (is_broadcast(hwnd))
2667 SetLastError( ERROR_INVALID_PARAMETER );
2670 if (!WIN_IsCurrentProcess( hwnd ))
2671 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2672 debugstr_a(lpString), hwnd );
2673 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2677 /*******************************************************************
2678 * SetWindowTextW (USER32.@)
2680 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2682 if (is_broadcast(hwnd))
2684 SetLastError( ERROR_INVALID_PARAMETER );
2687 if (!WIN_IsCurrentProcess( hwnd ))
2688 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2689 debugstr_w(lpString), hwnd );
2690 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2694 /*******************************************************************
2695 * GetWindowTextLengthA (USER32.@)
2697 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2699 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2702 /*******************************************************************
2703 * GetWindowTextLengthW (USER32.@)
2705 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2707 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2711 /*******************************************************************
2712 * IsWindow (USER32.@)
2714 BOOL WINAPI IsWindow( HWND hwnd )
2719 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2720 if (ptr == WND_DESKTOP) return TRUE;
2722 if (ptr != WND_OTHER_PROCESS)
2724 WIN_ReleasePtr( ptr );
2728 /* check other processes */
2729 SERVER_START_REQ( get_window_info )
2731 req->handle = wine_server_user_handle( hwnd );
2732 ret = !wine_server_call_err( req );
2739 /***********************************************************************
2740 * GetWindowThreadProcessId (USER32.@)
2742 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2747 if (!(ptr = WIN_GetPtr( hwnd )))
2749 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2753 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2755 /* got a valid window */
2757 if (process) *process = GetCurrentProcessId();
2758 WIN_ReleasePtr( ptr );
2762 /* check other processes */
2763 SERVER_START_REQ( get_window_info )
2765 req->handle = wine_server_user_handle( hwnd );
2766 if (!wine_server_call_err( req ))
2768 tid = (DWORD)reply->tid;
2769 if (process) *process = (DWORD)reply->pid;
2777 /*****************************************************************
2778 * GetParent (USER32.@)
2780 HWND WINAPI GetParent( HWND hwnd )
2785 if (!(wndPtr = WIN_GetPtr( hwnd )))
2787 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2790 if (wndPtr == WND_DESKTOP) return 0;
2791 if (wndPtr == WND_OTHER_PROCESS)
2793 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2794 if (style & (WS_POPUP | WS_CHILD))
2796 SERVER_START_REQ( get_window_tree )
2798 req->handle = wine_server_user_handle( hwnd );
2799 if (!wine_server_call_err( req ))
2801 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2802 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2810 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2811 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2812 WIN_ReleasePtr( wndPtr );
2818 /*****************************************************************
2819 * GetAncestor (USER32.@)
2821 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2824 HWND *list, ret = 0;
2829 if (!(win = WIN_GetPtr( hwnd )))
2831 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2834 if (win == WND_DESKTOP) return 0;
2835 if (win != WND_OTHER_PROCESS)
2838 WIN_ReleasePtr( win );
2840 else /* need to query the server */
2842 SERVER_START_REQ( get_window_tree )
2844 req->handle = wine_server_user_handle( hwnd );
2845 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2852 if (!(list = list_window_parents( hwnd ))) return 0;
2854 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2858 while (list[count]) count++;
2859 ret = list[count - 2]; /* get the one before the desktop */
2861 HeapFree( GetProcessHeap(), 0, list );
2865 if (is_desktop_window( hwnd )) return 0;
2866 ret = WIN_GetFullHandle( hwnd );
2869 HWND parent = GetParent( ret );
2879 /*****************************************************************
2880 * SetParent (USER32.@)
2882 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2885 HWND old_parent = 0;
2891 if (is_broadcast(hwnd) || is_broadcast(parent))
2893 SetLastError(ERROR_INVALID_PARAMETER);
2897 if (!parent) parent = GetDesktopWindow();
2898 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2899 else parent = WIN_GetFullHandle( parent );
2901 if (!IsWindow( parent ))
2903 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2907 /* Some applications try to set a child as a parent */
2908 if (IsChild(hwnd, parent))
2910 SetLastError( ERROR_INVALID_PARAMETER );
2914 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2915 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2917 if (full_handle == parent)
2919 SetLastError( ERROR_INVALID_PARAMETER );
2923 /* Windows hides the window first, then shows it again
2924 * including the WM_SHOWWINDOW messages and all */
2925 was_visible = ShowWindow( hwnd, SW_HIDE );
2927 wndPtr = WIN_GetPtr( hwnd );
2928 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2930 pt.x = wndPtr->rectWindow.left;
2931 pt.y = wndPtr->rectWindow.top;
2933 SERVER_START_REQ( set_parent )
2935 req->handle = wine_server_user_handle( hwnd );
2936 req->parent = wine_server_user_handle( parent );
2937 if ((ret = !wine_server_call( req )))
2939 old_parent = wine_server_ptr_handle( reply->old_parent );
2940 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2945 WIN_ReleasePtr( wndPtr );
2948 USER_Driver->pSetParent( full_handle, parent, old_parent );
2950 /* SetParent additionally needs to make hwnd the topmost window
2951 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2952 WM_WINDOWPOSCHANGED notification messages.
2954 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
2956 if (was_visible) ShowWindow( hwnd, SW_SHOW );
2962 /*******************************************************************
2963 * IsChild (USER32.@)
2965 BOOL WINAPI IsChild( HWND parent, HWND child )
2967 HWND *list = list_window_parents( child );
2971 if (!list) return FALSE;
2972 parent = WIN_GetFullHandle( parent );
2973 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2974 ret = list[i] && list[i+1];
2975 HeapFree( GetProcessHeap(), 0, list );
2980 /***********************************************************************
2981 * IsWindowVisible (USER32.@)
2983 BOOL WINAPI IsWindowVisible( HWND hwnd )
2989 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2990 if (!(list = list_window_parents( hwnd ))) return TRUE;
2993 for (i = 0; list[i+1]; i++)
2994 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2995 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2997 HeapFree( GetProcessHeap(), 0, list );
3002 /***********************************************************************
3003 * WIN_IsWindowDrawable
3005 * hwnd is drawable when it is visible, all parents are not
3006 * minimized, and it is itself not minimized unless we are
3007 * trying to draw its default class icon.
3009 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3014 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3016 if (!(style & WS_VISIBLE)) return FALSE;
3017 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3019 if (!(list = list_window_parents( hwnd ))) return TRUE;
3022 for (i = 0; list[i+1]; i++)
3023 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3025 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3027 HeapFree( GetProcessHeap(), 0, list );
3032 /*******************************************************************
3033 * GetTopWindow (USER32.@)
3035 HWND WINAPI GetTopWindow( HWND hwnd )
3037 if (!hwnd) hwnd = GetDesktopWindow();
3038 return GetWindow( hwnd, GW_CHILD );
3042 /*******************************************************************
3043 * GetWindow (USER32.@)
3045 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3049 if (rel == GW_OWNER) /* this one may be available locally */
3051 WND *wndPtr = WIN_GetPtr( hwnd );
3054 SetLastError( ERROR_INVALID_HANDLE );
3057 if (wndPtr == WND_DESKTOP) return 0;
3058 if (wndPtr != WND_OTHER_PROCESS)
3060 retval = wndPtr->owner;
3061 WIN_ReleasePtr( wndPtr );
3064 /* else fall through to server call */
3067 SERVER_START_REQ( get_window_tree )
3069 req->handle = wine_server_user_handle( hwnd );
3070 if (!wine_server_call_err( req ))
3075 retval = wine_server_ptr_handle( reply->first_sibling );
3078 retval = wine_server_ptr_handle( reply->last_sibling );
3081 retval = wine_server_ptr_handle( reply->next_sibling );
3084 retval = wine_server_ptr_handle( reply->prev_sibling );
3087 retval = wine_server_ptr_handle( reply->owner );
3090 retval = wine_server_ptr_handle( reply->first_child );
3100 /*******************************************************************
3101 * ShowOwnedPopups (USER32.@)
3103 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3107 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3109 if (!win_array) return TRUE;
3111 while (win_array[count]) count++;
3112 while (--count >= 0)
3114 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3115 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3116 if (pWnd == WND_OTHER_PROCESS) continue;
3119 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3121 WIN_ReleasePtr( pWnd );
3122 /* In Windows, ShowOwnedPopups(TRUE) generates
3123 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3124 * regardless of the state of the owner
3126 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3132 if (pWnd->dwStyle & WS_VISIBLE)
3134 WIN_ReleasePtr( pWnd );
3135 /* In Windows, ShowOwnedPopups(FALSE) generates
3136 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3137 * regardless of the state of the owner
3139 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3143 WIN_ReleasePtr( pWnd );
3145 HeapFree( GetProcessHeap(), 0, win_array );
3150 /*******************************************************************
3151 * GetLastActivePopup (USER32.@)
3153 HWND WINAPI GetLastActivePopup( HWND hwnd )
3157 SERVER_START_REQ( get_window_info )
3159 req->handle = wine_server_user_handle( hwnd );
3160 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3167 /*******************************************************************
3170 * Build an array of the children of a given window. The array must be
3171 * freed with HeapFree. Returns NULL when no windows are found.
3173 HWND *WIN_ListChildren( HWND hwnd )
3177 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3180 return list_window_children( 0, hwnd, NULL, 0 );
3184 /*******************************************************************
3185 * EnumWindows (USER32.@)
3187 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3193 USER_CheckNotLock();
3195 /* We have to build a list of all windows first, to avoid */
3196 /* unpleasant side-effects, for instance if the callback */
3197 /* function changes the Z-order of the windows. */
3199 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3201 /* Now call the callback function for every window */
3203 for (i = 0; list[i]; i++)
3205 /* Make sure that the window still exists */
3206 if (!IsWindow( list[i] )) continue;
3207 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3209 HeapFree( GetProcessHeap(), 0, list );
3214 /**********************************************************************
3215 * EnumThreadWindows (USER32.@)
3217 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3223 USER_CheckNotLock();
3225 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3227 /* Now call the callback function for every window */
3229 for (i = 0; list[i]; i++)
3230 if (!(ret = func( list[i], lParam ))) break;
3231 HeapFree( GetProcessHeap(), 0, list );
3236 /***********************************************************************
3237 * EnumDesktopWindows (USER32.@)
3239 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3244 USER_CheckNotLock();
3246 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3248 for (i = 0; list[i]; i++)
3249 if (!func( list[i], lparam )) break;
3250 HeapFree( GetProcessHeap(), 0, list );
3255 /**********************************************************************
3256 * WIN_EnumChildWindows
3258 * Helper function for EnumChildWindows().
3260 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3265 for ( ; *list; list++)
3267 /* Make sure that the window still exists */
3268 if (!IsWindow( *list )) continue;
3269 /* Build children list first */
3270 childList = WIN_ListChildren( *list );
3272 ret = func( *list, lParam );
3276 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3277 HeapFree( GetProcessHeap(), 0, childList );
3279 if (!ret) return FALSE;
3285 /**********************************************************************
3286 * EnumChildWindows (USER32.@)
3288 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3293 USER_CheckNotLock();
3295 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3296 ret = WIN_EnumChildWindows( list, func, lParam );
3297 HeapFree( GetProcessHeap(), 0, list );
3302 /*******************************************************************
3303 * AnyPopup (USER32.@)
3305 BOOL WINAPI AnyPopup(void)
3309 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3311 if (!list) return FALSE;
3312 for (i = 0; list[i]; i++)
3314 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3316 retvalue = (list[i] != 0);
3317 HeapFree( GetProcessHeap(), 0, list );
3322 /*******************************************************************
3323 * FlashWindow (USER32.@)
3325 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3329 TRACE("%p\n", hWnd);
3331 if (IsIconic( hWnd ))
3333 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3335 wndPtr = WIN_GetPtr(hWnd);
3336 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3337 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3339 wndPtr->flags |= WIN_NCACTIVATED;
3343 wndPtr->flags &= ~WIN_NCACTIVATED;
3345 WIN_ReleasePtr( wndPtr );
3352 wndPtr = WIN_GetPtr(hWnd);
3353 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3354 hWnd = wndPtr->obj.handle; /* make it a full handle */
3356 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3357 else wparam = (hWnd == GetForegroundWindow());
3359 WIN_ReleasePtr( wndPtr );
3360 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3365 /*******************************************************************
3366 * FlashWindowEx (USER32.@)
3368 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3370 FIXME("%p\n", pfwi);
3374 /*******************************************************************
3375 * GetWindowContextHelpId (USER32.@)
3377 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3380 WND *wnd = WIN_GetPtr( hwnd );
3381 if (!wnd || wnd == WND_DESKTOP) return 0;
3382 if (wnd == WND_OTHER_PROCESS)
3384 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3387 retval = wnd->helpContext;
3388 WIN_ReleasePtr( wnd );
3393 /*******************************************************************
3394 * SetWindowContextHelpId (USER32.@)
3396 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3398 WND *wnd = WIN_GetPtr( hwnd );
3399 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3400 if (wnd == WND_OTHER_PROCESS)
3402 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3405 wnd->helpContext = id;
3406 WIN_ReleasePtr( wnd );
3411 /*******************************************************************
3412 * DragDetect (USER32.@)
3414 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3418 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3419 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3421 rect.left = pt.x - wDragWidth;
3422 rect.right = pt.x + wDragWidth;
3424 rect.top = pt.y - wDragHeight;
3425 rect.bottom = pt.y + wDragHeight;
3431 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3433 if( msg.message == WM_LBUTTONUP )
3438 if( msg.message == WM_MOUSEMOVE )
3441 tmp.x = (short)LOWORD(msg.lParam);
3442 tmp.y = (short)HIWORD(msg.lParam);
3443 if( !PtInRect( &rect, tmp ))
3455 /******************************************************************************
3456 * GetWindowModuleFileNameA (USER32.@)
3458 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3463 TRACE( "%p, %p, %u\n", hwnd, module, size );
3465 win = WIN_GetPtr( hwnd );
3466 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3468 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3471 hinst = win->hInstance;
3472 WIN_ReleasePtr( win );
3474 return GetModuleFileNameA( hinst, module, size );
3477 /******************************************************************************
3478 * GetWindowModuleFileNameW (USER32.@)
3480 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3485 TRACE( "%p, %p, %u\n", hwnd, module, size );
3487 win = WIN_GetPtr( hwnd );
3488 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3490 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3493 hinst = win->hInstance;
3494 WIN_ReleasePtr( win );
3496 return GetModuleFileNameW( hinst, module, size );
3499 /******************************************************************************
3500 * GetWindowInfo (USER32.@)
3502 * Note: tests show that Windows doesn't check cbSize of the structure.
3504 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3506 if (!pwi) return FALSE;
3507 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3509 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3510 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3511 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3513 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3514 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3516 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3517 pwi->wCreatorVersion = 0x0400;
3522 /******************************************************************************
3523 * SwitchDesktop (USER32.@)
3525 * NOTES: Sets the current input or interactive desktop.
3527 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3529 FIXME("(hwnd %p) stub!\n", hDesktop);
3533 /*****************************************************************************
3534 * SetLayeredWindowAttributes (USER32.@)
3536 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3540 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3542 SERVER_START_REQ( set_window_layered_info )
3544 req->handle = wine_server_user_handle( hwnd );
3545 req->color_key = key;
3548 ret = !wine_server_call_err( req );
3552 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3558 /*****************************************************************************
3559 * GetLayeredWindowAttributes (USER32.@)
3561 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3565 SERVER_START_REQ( get_window_layered_info )
3567 req->handle = wine_server_user_handle( hwnd );
3568 if ((ret = !wine_server_call_err( req )))
3570 if (key) *key = reply->color_key;
3571 if (alpha) *alpha = reply->alpha;
3572 if (flags) *flags = reply->flags;
3581 /*****************************************************************************
3582 * UpdateLayeredWindowIndirect (USER32.@)
3584 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3588 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3589 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3591 SetLastError( ERROR_INVALID_PARAMETER );
3595 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3597 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE;
3598 RECT window_rect, client_rect;
3601 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3605 offset.cx = info->pptDst->x - window_rect.left;
3606 offset.cy = info->pptDst->y - window_rect.top;
3607 OffsetRect( &client_rect, offset.cx, offset.cy );
3608 OffsetRect( &window_rect, offset.cx, offset.cy );
3609 flags &= ~SWP_NOMOVE;
3613 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3615 SetLastError( ERROR_INVALID_PARAMETER );
3618 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3619 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3620 client_rect.right += offset.cx;
3621 client_rect.bottom += offset.cy;
3622 window_rect.right += offset.cx;
3623 window_rect.bottom += offset.cy;
3624 flags &= ~SWP_NOSIZE;
3626 TRACE( "moving window %p win %s client %s\n", hwnd,
3627 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3628 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3633 HDC hdc = GetWindowDC( hwnd );
3640 GetWindowRect( hwnd, &rect );
3641 OffsetRect( &rect, -rect.left, -rect.top);
3644 x = info->pptSrc->x;
3645 y = info->pptSrc->y;
3648 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3650 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3651 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3652 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3654 ReleaseDC( hwnd, hdc );
3658 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3659 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3660 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3661 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3666 /*****************************************************************************
3667 * UpdateLayeredWindow (USER32.@)
3669 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3670 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3673 UPDATELAYEREDWINDOWINFO info;
3675 info.cbSize = sizeof(info);
3676 info.hdcDst = hdcDst;
3677 info.pptDst = pptDst;
3679 info.hdcSrc = hdcSrc;
3680 info.pptSrc = pptSrc;
3682 info.pblend = pblend;
3683 info.dwFlags = dwFlags;
3684 info.prcDirty = NULL;
3685 return UpdateLayeredWindowIndirect( hwnd, &info );
3689 /******************************************************************************
3690 * GetProcessDefaultLayout [USER32.@]
3692 * Gets the default layout for parentless windows.
3694 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3698 SetLastError( ERROR_NOACCESS );
3701 if (process_layout == ~0u)
3703 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3704 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3705 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3706 '\\','%','0','4','x','%','0','4','x',
3707 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3708 WCHAR *str, buffer[MAX_PATH];
3709 DWORD i, len, version_layout = 0;
3710 DWORD user_lang = GetUserDefaultLangID();
3714 GetModuleFileNameW( 0, buffer, MAX_PATH );
3715 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3716 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3717 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3718 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3720 len /= sizeof(DWORD);
3721 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3722 if (i == len) /* try neutral language */
3723 for (i = 0; i < len; i++)
3724 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3725 if (i == len) i = 0; /* default to the first one */
3727 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3728 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3729 TRACE( "found description %s\n", debugstr_w( str ));
3730 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3733 HeapFree( GetProcessHeap(), 0, data );
3734 process_layout = version_layout;
3736 *layout = process_layout;
3741 /******************************************************************************
3742 * SetProcessDefaultLayout [USER32.@]
3744 * Sets the default layout for parentless windows.
3746 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3748 process_layout = layout;
3753 /* 64bit versions */
3755 #ifdef GetWindowLongPtrW
3756 #undef GetWindowLongPtrW
3759 #ifdef GetWindowLongPtrA
3760 #undef GetWindowLongPtrA
3763 #ifdef SetWindowLongPtrW
3764 #undef SetWindowLongPtrW
3767 #ifdef SetWindowLongPtrA
3768 #undef SetWindowLongPtrA
3771 /*****************************************************************************
3772 * GetWindowLongPtrW (USER32.@)
3774 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3776 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3779 /*****************************************************************************
3780 * GetWindowLongPtrA (USER32.@)
3782 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3784 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3787 /*****************************************************************************
3788 * SetWindowLongPtrW (USER32.@)
3790 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3792 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3795 /*****************************************************************************
3796 * SetWindowLongPtrA (USER32.@)
3798 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3800 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );