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 * Dummy window surface for windows that shouldn't get painted.
493 static void dummy_surface_lock( struct window_surface *window_surface )
498 static void dummy_surface_unlock( struct window_surface *window_surface )
503 static void *dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
505 static DWORD dummy_data;
507 info->bmiHeader.biSize = sizeof( info->bmiHeader );
508 info->bmiHeader.biWidth = dummy_surface.rect.right;
509 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
510 info->bmiHeader.biPlanes = 1;
511 info->bmiHeader.biBitCount = 32;
512 info->bmiHeader.biCompression = BI_RGB;
513 info->bmiHeader.biSizeImage = 0;
514 info->bmiHeader.biXPelsPerMeter = 0;
515 info->bmiHeader.biYPelsPerMeter = 0;
516 info->bmiHeader.biClrUsed = 0;
517 info->bmiHeader.biClrImportant = 0;
521 static RECT *dummy_surface_get_bounds( struct window_surface *window_surface )
523 static RECT dummy_bounds;
524 return &dummy_bounds;
527 static void dummy_surface_flush( struct window_surface *window_surface )
532 static void dummy_surface_destroy( struct window_surface *window_surface )
537 static const struct window_surface_funcs dummy_surface_funcs =
540 dummy_surface_unlock,
541 dummy_surface_get_bitmap_info,
542 dummy_surface_get_bounds,
544 dummy_surface_destroy
547 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
550 /*******************************************************************
551 * register_window_surface
553 * Register a window surface in the global list, possibly replacing another one.
555 void register_window_surface( struct window_surface *old, struct window_surface *new )
557 if (old == new) return;
558 EnterCriticalSection( &surfaces_section );
559 if (old && old != &dummy_surface) list_remove( &old->entry );
560 if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
561 LeaveCriticalSection( &surfaces_section );
565 /*******************************************************************
566 * flush_window_surfaces
568 * Flush pending output from all window surfaces.
570 void flush_window_surfaces( BOOL idle )
572 static DWORD last_idle;
574 struct window_surface *surface;
576 EnterCriticalSection( &surfaces_section );
577 now = GetTickCount();
578 if (idle) last_idle = now;
579 /* if not idle, we only flush if there's evidence that the app never goes idle */
580 else if ((int)(now - last_idle) < 1000) goto done;
582 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
583 surface->funcs->flush( surface );
585 LeaveCriticalSection( &surfaces_section );
589 /***********************************************************************
592 * Return a pointer to the WND structure if local to the process,
593 * or WND_OTHER_PROCESS if handle may be valid in other process.
594 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
596 WND *WIN_GetPtr( HWND hwnd )
600 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
602 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
608 /***********************************************************************
609 * WIN_IsCurrentProcess
611 * Check whether a given window belongs to the current process (and return the full handle).
613 HWND WIN_IsCurrentProcess( HWND hwnd )
618 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
619 ret = ptr->obj.handle;
620 WIN_ReleasePtr( ptr );
625 /***********************************************************************
626 * WIN_IsCurrentThread
628 * Check whether a given window belongs to the current thread (and return the full handle).
630 HWND WIN_IsCurrentThread( HWND hwnd )
635 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
636 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
637 WIN_ReleasePtr( ptr );
642 /***********************************************************************
645 * Convert a possibly truncated window handle to a full 32-bit handle.
647 HWND WIN_GetFullHandle( HWND hwnd )
651 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
652 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
653 /* do sign extension for -2 and -3 */
654 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
656 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
658 if (ptr == WND_DESKTOP)
660 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
661 else return get_hwnd_message_parent();
664 if (ptr != WND_OTHER_PROCESS)
666 hwnd = ptr->obj.handle;
667 WIN_ReleasePtr( ptr );
669 else /* may belong to another process */
671 SERVER_START_REQ( get_window_info )
673 req->handle = wine_server_user_handle( hwnd );
674 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
682 /***********************************************************************
685 * Change the owner of a window.
687 HWND WIN_SetOwner( HWND hwnd, HWND owner )
689 WND *win = WIN_GetPtr( hwnd );
692 if (!win || win == WND_DESKTOP) return 0;
693 if (win == WND_OTHER_PROCESS)
695 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
698 SERVER_START_REQ( set_window_owner )
700 req->handle = wine_server_user_handle( hwnd );
701 req->owner = wine_server_user_handle( owner );
702 if (!wine_server_call( req ))
704 win->owner = wine_server_ptr_handle( reply->full_owner );
705 ret = wine_server_ptr_handle( reply->prev_owner );
709 WIN_ReleasePtr( win );
714 /***********************************************************************
717 * Change the style of a window.
719 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
721 BOOL ok, needs_show = FALSE;
723 WND *win = WIN_GetPtr( hwnd );
725 if (!win || win == WND_DESKTOP) return 0;
726 if (win == WND_OTHER_PROCESS)
729 ERR( "cannot set style %x/%x on other process window %p\n",
730 set_bits, clear_bits, hwnd );
733 style.styleOld = win->dwStyle;
734 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
735 if (style.styleNew == style.styleOld)
737 WIN_ReleasePtr( win );
738 return style.styleNew;
740 SERVER_START_REQ( set_window_info )
742 req->handle = wine_server_user_handle( hwnd );
743 req->flags = SET_WIN_STYLE;
744 req->style = style.styleNew;
745 req->extra_offset = -1;
746 if ((ok = !wine_server_call( req )))
748 style.styleOld = reply->old_style;
749 win->dwStyle = style.styleNew;
754 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
756 /* Some apps try to make their window visible through WM_SETREDRAW.
757 * Only do that if the window was never explicitly hidden,
758 * because Steam messes with WM_SETREDRAW after hiding its windows. */
759 needs_show = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
760 invalidate_dce( win, NULL );
762 WIN_ReleasePtr( win );
768 RECT window_rect, client_rect;
769 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
770 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
771 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
772 &window_rect, &client_rect, NULL );
775 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
776 return style.styleOld;
780 /***********************************************************************
783 * Get the window and client rectangles.
785 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
787 WND *win = WIN_GetPtr( hwnd );
792 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
795 if (win == WND_DESKTOP)
798 rect.left = rect.top = 0;
799 if (hwnd == get_hwnd_message_parent())
806 rect.right = GetSystemMetrics(SM_CXSCREEN);
807 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
809 if (rectWindow) *rectWindow = rect;
810 if (rectClient) *rectClient = rect;
813 if (win != WND_OTHER_PROCESS)
815 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
820 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
821 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
822 if (win->dwExStyle & WS_EX_LAYOUTRTL)
823 mirror_rect( &win->rectClient, &window_rect );
826 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
827 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
828 if (win->dwExStyle & WS_EX_LAYOUTRTL)
829 mirror_rect( &win->rectWindow, &client_rect );
834 WND *parent = WIN_GetPtr( win->parent );
835 if (parent == WND_DESKTOP) break;
836 if (!parent || parent == WND_OTHER_PROCESS)
838 WIN_ReleasePtr( win );
841 if (parent->flags & WIN_CHILDREN_MOVED)
843 WIN_ReleasePtr( parent );
844 WIN_ReleasePtr( win );
847 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
849 mirror_rect( &parent->rectClient, &window_rect );
850 mirror_rect( &parent->rectClient, &client_rect );
852 WIN_ReleasePtr( parent );
858 WND *parent = WIN_GetPtr( win->parent );
859 if (parent == WND_DESKTOP) break;
860 if (!parent || parent == WND_OTHER_PROCESS)
862 WIN_ReleasePtr( win );
865 WIN_ReleasePtr( win );
866 if (parent->flags & WIN_CHILDREN_MOVED)
868 WIN_ReleasePtr( parent );
874 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
875 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
880 if (rectWindow) *rectWindow = window_rect;
881 if (rectClient) *rectClient = client_rect;
882 WIN_ReleasePtr( win );
887 SERVER_START_REQ( get_window_rectangles )
889 req->handle = wine_server_user_handle( hwnd );
890 req->relative = relative;
891 if ((ret = !wine_server_call_err( req )))
895 rectWindow->left = reply->window.left;
896 rectWindow->top = reply->window.top;
897 rectWindow->right = reply->window.right;
898 rectWindow->bottom = reply->window.bottom;
902 rectClient->left = reply->client.left;
903 rectClient->top = reply->client.top;
904 rectClient->right = reply->client.right;
905 rectClient->bottom = reply->client.bottom;
914 /***********************************************************************
917 * Destroy storage associated to a window. "Internals" p.358
919 LRESULT WIN_DestroyWindow( HWND hwnd )
923 HMENU menu = 0, sys_menu;
925 struct window_surface *surface;
927 TRACE("%p\n", hwnd );
929 /* free child windows */
930 if ((list = WIN_ListChildren( hwnd )))
933 for (i = 0; list[i]; i++)
935 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
936 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
938 HeapFree( GetProcessHeap(), 0, list );
941 /* Unlink now so we won't bother with the children later on */
942 SERVER_START_REQ( set_parent )
944 req->handle = wine_server_user_handle( hwnd );
946 wine_server_call( req );
951 * Send the WM_NCDESTROY to the window being destroyed.
953 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
955 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
957 /* free resources associated with the window */
959 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
960 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
961 menu = (HMENU)wndPtr->wIDmenu;
962 sys_menu = wndPtr->hSysMenu;
963 free_dce( wndPtr->dce, hwnd );
965 icon_title = wndPtr->icon_title;
966 HeapFree( GetProcessHeap(), 0, wndPtr->text );
968 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
969 wndPtr->pScroll = NULL;
970 surface = wndPtr->surface;
971 wndPtr->surface = NULL;
972 WIN_ReleasePtr( wndPtr );
974 if (icon_title) DestroyWindow( icon_title );
975 if (menu) DestroyMenu( menu );
976 if (sys_menu) DestroyMenu( sys_menu );
979 register_window_surface( surface, NULL );
980 window_surface_release( surface );
983 USER_Driver->pDestroyWindow( hwnd );
985 free_window_handle( hwnd );
990 /***********************************************************************
991 * destroy_thread_window
993 * Destroy a window upon exit of its thread.
995 static void destroy_thread_window( HWND hwnd )
999 HMENU menu = 0, sys_menu = 0;
1000 struct window_surface *surface = NULL;
1003 /* free child windows */
1005 if ((list = WIN_ListChildren( hwnd )))
1008 for (i = 0; list[i]; i++)
1010 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
1011 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1013 HeapFree( GetProcessHeap(), 0, list );
1016 /* destroy the client-side storage */
1018 index = USER_HANDLE_TO_INDEX(hwnd);
1019 if (index >= NB_USER_HANDLES) return;
1021 if ((wndPtr = user_handles[index]))
1023 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
1024 sys_menu = wndPtr->hSysMenu;
1025 free_dce( wndPtr->dce, hwnd );
1026 surface = wndPtr->surface;
1027 wndPtr->surface = NULL;
1028 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
1032 HeapFree( GetProcessHeap(), 0, wndPtr );
1033 if (menu) DestroyMenu( menu );
1034 if (sys_menu) DestroyMenu( sys_menu );
1037 register_window_surface( surface, NULL );
1038 window_surface_release( surface );
1043 /***********************************************************************
1044 * destroy_thread_child_windows
1046 * Destroy child windows upon exit of its thread.
1048 static void destroy_thread_child_windows( HWND hwnd )
1053 if (WIN_IsCurrentThread( hwnd ))
1055 destroy_thread_window( hwnd );
1057 else if ((list = WIN_ListChildren( hwnd )))
1059 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1060 HeapFree( GetProcessHeap(), 0, list );
1065 /***********************************************************************
1066 * WIN_DestroyThreadWindows
1068 * Destroy all children of 'wnd' owned by the current thread.
1070 void WIN_DestroyThreadWindows( HWND hwnd )
1075 if (!(list = WIN_ListChildren( hwnd ))) return;
1077 /* reset owners of top-level windows */
1078 for (i = 0; list[i]; i++)
1080 if (!WIN_IsCurrentThread( list[i] ))
1082 HWND owner = GetWindow( list[i], GW_OWNER );
1083 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1087 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1088 HeapFree( GetProcessHeap(), 0, list );
1092 /***********************************************************************
1093 * WIN_FixCoordinates
1095 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1096 * returns default show mode in sw.
1098 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1100 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1103 if (cs->dwExStyle & WS_EX_MDICHILD)
1107 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1108 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1110 TRACE("MDI child id %04x\n", id);
1113 if (cs->style & (WS_CHILD | WS_POPUP))
1115 if (cs->dwExStyle & WS_EX_MDICHILD)
1117 if (IS_DEFAULT(cs->x))
1122 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1123 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1127 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1128 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1131 else /* overlapped window */
1134 MONITORINFO mon_info;
1137 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1139 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1140 mon_info.cbSize = sizeof(mon_info);
1141 GetMonitorInfoW( monitor, &mon_info );
1142 GetStartupInfoW( &info );
1144 if (IS_DEFAULT(cs->x))
1146 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1147 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1148 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1151 if (IS_DEFAULT(cs->cx))
1153 if (info.dwFlags & STARTF_USESIZE)
1155 cs->cx = info.dwXSize;
1156 cs->cy = info.dwYSize;
1160 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1161 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1164 /* neither x nor cx are default. Check the y values .
1165 * In the trace we see Outlook and Outlook Express using
1166 * cy set to CW_USEDEFAULT when opening the address book.
1168 else if (IS_DEFAULT(cs->cy))
1170 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1171 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1177 /***********************************************************************
1178 * dump_window_styles
1180 static void dump_window_styles( DWORD style, DWORD exstyle )
1183 if(style & WS_POPUP) TRACE(" WS_POPUP");
1184 if(style & WS_CHILD) TRACE(" WS_CHILD");
1185 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1186 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1187 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1188 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1189 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1190 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1191 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1194 if(style & WS_BORDER) TRACE(" WS_BORDER");
1195 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1197 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1198 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1199 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1200 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1201 if (style & WS_CHILD)
1203 if(style & WS_GROUP) TRACE(" WS_GROUP");
1204 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1208 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1209 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1212 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1213 #define DUMPED_STYLES \
1214 ((DWORD)(WS_POPUP | \
1233 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1235 #undef DUMPED_STYLES
1237 TRACE( "exstyle:" );
1238 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1239 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1240 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1241 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1242 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1243 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1244 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1245 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1246 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1247 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1248 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1249 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1250 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1251 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1252 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1253 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1254 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1255 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1256 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1258 #define DUMPED_EX_STYLES \
1259 ((DWORD)(WS_EX_DLGMODALFRAME | \
1260 WS_EX_DRAGDETECT | \
1261 WS_EX_NOPARENTNOTIFY | \
1263 WS_EX_ACCEPTFILES | \
1264 WS_EX_TRANSPARENT | \
1266 WS_EX_TOOLWINDOW | \
1267 WS_EX_WINDOWEDGE | \
1268 WS_EX_CLIENTEDGE | \
1269 WS_EX_CONTEXTHELP | \
1271 WS_EX_RTLREADING | \
1272 WS_EX_LEFTSCROLLBAR | \
1273 WS_EX_CONTROLPARENT | \
1274 WS_EX_STATICEDGE | \
1279 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1281 #undef DUMPED_EX_STYLES
1285 /***********************************************************************
1286 * WIN_CreateWindowEx
1288 * Implementation of CreateWindowEx().
1290 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1292 INT cx, cy, style, sw = SW_SHOW;
1296 HWND hwnd, parent, owner, top_child = 0;
1297 MDICREATESTRUCTW mdi_cs;
1298 CBT_CREATEWNDW cbtc;
1301 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1302 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1303 debugstr_w(className),
1304 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1305 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1306 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1308 /* Fix the styles for MDI children */
1309 if (cs->dwExStyle & WS_EX_MDICHILD)
1313 wndPtr = WIN_GetPtr(cs->hwndParent);
1314 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1316 flags = wndPtr->flags;
1317 WIN_ReleasePtr(wndPtr);
1320 if (!(flags & WIN_ISMDICLIENT))
1322 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1326 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1327 * MDICREATESTRUCT members have the originally passed values.
1329 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1330 * have the same layout.
1332 mdi_cs.szClass = cs->lpszClass;
1333 mdi_cs.szTitle = cs->lpszName;
1334 mdi_cs.hOwner = cs->hInstance;
1339 mdi_cs.style = cs->style;
1340 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1342 cs->lpCreateParams = &mdi_cs;
1344 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1346 if (cs->style & WS_POPUP)
1348 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1351 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1355 cs->style &= ~WS_POPUP;
1356 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1357 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1360 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1364 /* Restore current maximized child */
1365 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1367 TRACE("Restoring current maximized child %p\n", top_child);
1368 if (cs->style & WS_MAXIMIZE)
1370 /* if the new window is maximized don't bother repainting */
1371 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1372 ShowWindow( top_child, SW_SHOWNORMAL );
1373 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1375 else ShowWindow( top_child, SW_SHOWNORMAL );
1380 /* Find the parent window */
1382 parent = cs->hwndParent;
1385 if (cs->hwndParent == HWND_MESSAGE)
1387 cs->hwndParent = parent = get_hwnd_message_parent();
1389 else if (cs->hwndParent)
1391 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1393 parent = GetDesktopWindow();
1394 owner = cs->hwndParent;
1398 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1399 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1400 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1405 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1407 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1409 WARN("No parent for child window\n" );
1410 SetLastError(ERROR_TLW_WITH_WSCHILD);
1411 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1413 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1414 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1415 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1418 GetProcessDefaultLayout( &layout );
1419 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1420 parent = GetDesktopWindow();
1424 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1426 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1427 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1428 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1429 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1431 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1433 /* Create the window structure */
1435 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1437 hwnd = wndPtr->obj.handle;
1439 /* Fill the window structure */
1441 wndPtr->tid = GetCurrentThreadId();
1442 wndPtr->hInstance = cs->hInstance;
1443 wndPtr->text = NULL;
1444 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1445 wndPtr->dwExStyle = cs->dwExStyle;
1446 wndPtr->wIDmenu = 0;
1447 wndPtr->helpContext = 0;
1448 wndPtr->pScroll = NULL;
1449 wndPtr->userdata = 0;
1451 wndPtr->hIconSmall = 0;
1452 wndPtr->hSysMenu = 0;
1454 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1455 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1457 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1460 * Correct the window styles.
1462 * It affects only the style loaded into the WIN structure.
1465 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1467 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1468 if (!(wndPtr->dwStyle & WS_POPUP))
1469 wndPtr->dwStyle |= WS_CAPTION;
1472 /* WS_EX_WINDOWEDGE depends on some other styles */
1473 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1474 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1475 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1477 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1478 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1479 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1482 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1484 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1485 wndPtr->flags |= WIN_NEED_SIZE;
1487 SERVER_START_REQ( set_window_info )
1489 req->handle = wine_server_user_handle( hwnd );
1490 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1491 req->style = wndPtr->dwStyle;
1492 req->ex_style = wndPtr->dwExStyle;
1493 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1494 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1495 req->extra_offset = -1;
1496 wine_server_call( req );
1500 /* Set the window menu */
1502 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1506 if (!MENU_SetMenu(hwnd, cs->hMenu))
1508 WIN_ReleasePtr( wndPtr );
1509 free_window_handle( hwnd );
1515 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1518 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1519 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1523 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1525 /* call the WH_CBT hook */
1527 /* the window style passed to the hook must be the real window style,
1528 * rather than just the window style that the caller to CreateWindowEx
1529 * passed in, so we have to copy the original CREATESTRUCT and get the
1530 * the real style. */
1532 cbcs.style = wndPtr->dwStyle;
1534 cbtc.hwndInsertAfter = HWND_TOP;
1535 WIN_ReleasePtr( wndPtr );
1536 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1538 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1542 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1544 POINT maxSize, maxPos, minTrack, maxTrack;
1545 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1546 if (maxTrack.x < cx) cx = maxTrack.x;
1547 if (maxTrack.y < cy) cy = maxTrack.y;
1548 if (minTrack.x > cx) cx = minTrack.x;
1549 if (minTrack.y > cy) cy = minTrack.y;
1554 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1555 /* check for wraparound */
1556 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1557 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1558 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1560 /* send WM_NCCREATE */
1562 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1564 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1566 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1569 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1573 /* send WM_NCCALCSIZE */
1575 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1577 /* yes, even if the CBT hook was called with HWND_TOP */
1578 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1579 RECT client_rect = rect;
1581 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1582 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1583 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1584 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1585 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1589 /* send WM_CREATE */
1592 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1594 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1595 if (result == -1) goto failed;
1597 /* call the driver */
1599 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1601 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1603 /* send the size messages */
1605 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1606 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1607 if (!(wndPtr->flags & WIN_NEED_SIZE))
1609 WIN_ReleasePtr( wndPtr );
1610 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1611 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1612 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1613 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1615 else WIN_ReleasePtr( wndPtr );
1617 /* Show the window, maximizing or minimizing if needed */
1619 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1620 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1623 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1625 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1626 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1627 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1628 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1629 newPos.bottom - newPos.top, swFlag );
1632 /* Notify the parent window only */
1634 send_parent_notify( hwnd, WM_CREATE );
1635 if (!IsWindow( hwnd )) return 0;
1637 if (cs->style & WS_VISIBLE)
1639 if (cs->style & WS_MAXIMIZE)
1641 else if (cs->style & WS_MINIMIZE)
1642 sw = SW_SHOWMINIMIZED;
1644 ShowWindow( hwnd, sw );
1645 if (cs->dwExStyle & WS_EX_MDICHILD)
1647 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1648 /* ShowWindow won't activate child windows */
1649 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1653 /* Call WH_SHELL hook */
1655 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1656 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1658 TRACE("created window %p\n", hwnd);
1662 WIN_DestroyWindow( hwnd );
1667 /***********************************************************************
1668 * CreateWindowExA (USER32.@)
1670 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1671 LPCSTR windowName, DWORD style, INT x,
1672 INT y, INT width, INT height,
1673 HWND parent, HMENU menu,
1674 HINSTANCE instance, LPVOID data )
1678 cs.lpCreateParams = data;
1679 cs.hInstance = instance;
1681 cs.hwndParent = parent;
1687 cs.lpszName = windowName;
1688 cs.lpszClass = className;
1689 cs.dwExStyle = exStyle;
1691 if (!IS_INTRESOURCE(className))
1694 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1696 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1698 /* Note: we rely on the fact that CREATESTRUCTA and */
1699 /* CREATESTRUCTW have the same layout. */
1700 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1704 /***********************************************************************
1705 * CreateWindowExW (USER32.@)
1707 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1708 LPCWSTR windowName, DWORD style, INT x,
1709 INT y, INT width, INT height,
1710 HWND parent, HMENU menu,
1711 HINSTANCE instance, LPVOID data )
1715 cs.lpCreateParams = data;
1716 cs.hInstance = instance;
1718 cs.hwndParent = parent;
1724 cs.lpszName = windowName;
1725 cs.lpszClass = className;
1726 cs.dwExStyle = exStyle;
1728 return wow_handlers.create_window( &cs, className, instance, TRUE );
1732 /***********************************************************************
1733 * WIN_SendDestroyMsg
1735 static void WIN_SendDestroyMsg( HWND hwnd )
1739 info.cbSize = sizeof(info);
1740 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1742 if (hwnd == info.hwndCaret) DestroyCaret();
1743 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1747 * Send the WM_DESTROY to the window.
1749 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1752 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1753 * make sure that the window still exists when we come back.
1760 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1762 for (i = 0; pWndArray[i]; i++)
1764 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1766 HeapFree( GetProcessHeap(), 0, pWndArray );
1769 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1773 /***********************************************************************
1774 * DestroyWindow (USER32.@)
1776 BOOL WINAPI DestroyWindow( HWND hwnd )
1780 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1782 SetLastError( ERROR_ACCESS_DENIED );
1786 TRACE("(%p)\n", hwnd);
1790 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1792 if (MENU_IsMenuActive() == hwnd)
1795 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1799 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1800 send_parent_notify( hwnd, WM_DESTROY );
1802 else if (!GetWindow( hwnd, GW_OWNER ))
1804 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1805 /* FIXME: clean up palette - see "Internals" p.352 */
1808 if (!IsWindow(hwnd)) return TRUE;
1810 /* Hide the window */
1811 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1813 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1815 ShowWindow( hwnd, SW_HIDE );
1817 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1818 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1821 if (!IsWindow(hwnd)) return TRUE;
1823 /* Recursively destroy owned windows */
1830 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1833 for (i = 0; list[i]; i++)
1835 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1836 if (WIN_IsCurrentThread( list[i] ))
1838 DestroyWindow( list[i] );
1842 WIN_SetOwner( list[i], 0 );
1844 HeapFree( GetProcessHeap(), 0, list );
1846 if (!got_one) break;
1850 /* Send destroy messages */
1852 WIN_SendDestroyMsg( hwnd );
1853 if (!IsWindow( hwnd )) return TRUE;
1855 if (GetClipboardOwner() == hwnd)
1856 CLIPBOARD_ReleaseOwner();
1858 /* Destroy the window storage */
1860 WIN_DestroyWindow( hwnd );
1865 /***********************************************************************
1866 * CloseWindow (USER32.@)
1868 BOOL WINAPI CloseWindow( HWND hwnd )
1870 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1871 ShowWindow( hwnd, SW_MINIMIZE );
1876 /***********************************************************************
1877 * OpenIcon (USER32.@)
1879 BOOL WINAPI OpenIcon( HWND hwnd )
1881 if (!IsIconic( hwnd )) return FALSE;
1882 ShowWindow( hwnd, SW_SHOWNORMAL );
1887 /***********************************************************************
1888 * FindWindowExW (USER32.@)
1890 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1895 WCHAR *buffer = NULL;
1897 if (!parent && child) parent = GetDesktopWindow();
1898 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1902 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1903 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1906 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1910 child = WIN_GetFullHandle( child );
1911 while (list[i] && list[i] != child) i++;
1912 if (!list[i]) goto done;
1913 i++; /* start from next window */
1920 if (GetWindowTextW( list[i], buffer, len + 1 ))
1922 if (!strcmpiW( buffer, title )) break;
1926 if (!title[0]) break;
1934 HeapFree( GetProcessHeap(), 0, list );
1935 HeapFree( GetProcessHeap(), 0, buffer );
1941 /***********************************************************************
1942 * FindWindowA (USER32.@)
1944 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1946 HWND ret = FindWindowExA( 0, 0, className, title );
1947 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1952 /***********************************************************************
1953 * FindWindowExA (USER32.@)
1955 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1957 LPWSTR titleW = NULL;
1962 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1963 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1964 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1967 if (!IS_INTRESOURCE(className))
1970 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1971 hwnd = FindWindowExW( parent, child, classW, titleW );
1975 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1978 HeapFree( GetProcessHeap(), 0, titleW );
1983 /***********************************************************************
1984 * FindWindowW (USER32.@)
1986 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1988 return FindWindowExW( 0, 0, className, title );
1992 /**********************************************************************
1993 * GetDesktopWindow (USER32.@)
1995 HWND WINAPI GetDesktopWindow(void)
1997 struct user_thread_info *thread_info = get_user_thread_info();
1999 if (thread_info->top_window) return thread_info->top_window;
2001 SERVER_START_REQ( get_desktop_window )
2004 if (!wine_server_call( req ))
2006 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2007 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2012 if (!thread_info->top_window)
2014 USEROBJECTFLAGS flags;
2015 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2016 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2018 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2019 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2021 PROCESS_INFORMATION pi;
2022 WCHAR windir[MAX_PATH];
2023 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2024 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2027 memset( &si, 0, sizeof(si) );
2029 si.dwFlags = STARTF_USESTDHANDLES;
2032 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2034 GetSystemDirectoryW( windir, MAX_PATH );
2035 strcpyW( app, windir );
2036 strcatW( app, explorer );
2037 strcpyW( cmdline, app );
2038 strcatW( cmdline, args );
2040 Wow64DisableWow64FsRedirection( &redir );
2041 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2042 NULL, windir, &si, &pi ))
2044 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2045 WaitForInputIdle( pi.hProcess, 10000 );
2046 CloseHandle( pi.hThread );
2047 CloseHandle( pi.hProcess );
2049 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2050 Wow64RevertWow64FsRedirection( redir );
2052 else TRACE( "not starting explorer since winstation is not visible\n" );
2054 SERVER_START_REQ( get_desktop_window )
2057 if (!wine_server_call( req ))
2059 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2060 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2066 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2067 ERR( "failed to create desktop window\n" );
2069 return thread_info->top_window;
2073 /*******************************************************************
2074 * EnableWindow (USER32.@)
2076 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2081 if (is_broadcast(hwnd))
2083 SetLastError( ERROR_INVALID_PARAMETER );
2087 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2088 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2092 TRACE("( %p, %d )\n", hwnd, enable);
2094 retvalue = !IsWindowEnabled( hwnd );
2096 if (enable && retvalue)
2098 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2099 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2101 else if (!enable && !retvalue)
2105 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2107 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2109 if (hwnd == GetFocus())
2110 SetFocus( 0 ); /* A disabled window can't have the focus */
2112 capture_wnd = GetCapture();
2113 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2114 ReleaseCapture(); /* A disabled window can't capture the mouse */
2116 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2122 /***********************************************************************
2123 * IsWindowEnabled (USER32.@)
2125 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2127 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2131 /***********************************************************************
2132 * IsWindowUnicode (USER32.@)
2134 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2137 BOOL retvalue = FALSE;
2139 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2141 if (wndPtr == WND_DESKTOP) return TRUE;
2143 if (wndPtr != WND_OTHER_PROCESS)
2145 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2146 WIN_ReleasePtr( wndPtr );
2150 SERVER_START_REQ( get_window_info )
2152 req->handle = wine_server_user_handle( hwnd );
2153 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2161 /**********************************************************************
2164 * Helper function for GetWindowLong().
2166 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2168 LONG_PTR retvalue = 0;
2171 if (offset == GWLP_HWNDPARENT)
2173 HWND parent = GetAncestor( hwnd, GA_PARENT );
2174 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2175 return (ULONG_PTR)parent;
2178 if (!(wndPtr = WIN_GetPtr( hwnd )))
2180 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2184 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2186 if (offset == GWLP_WNDPROC)
2188 SetLastError( ERROR_ACCESS_DENIED );
2191 SERVER_START_REQ( set_window_info )
2193 req->handle = wine_server_user_handle( hwnd );
2194 req->flags = 0; /* don't set anything, just retrieve */
2195 req->extra_offset = (offset >= 0) ? offset : -1;
2196 req->extra_size = (offset >= 0) ? size : 0;
2197 if (!wine_server_call_err( req ))
2201 case GWL_STYLE: retvalue = reply->old_style; break;
2202 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2203 case GWLP_ID: retvalue = reply->old_id; break;
2204 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2205 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2207 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2208 else SetLastError( ERROR_INVALID_INDEX );
2217 /* now we have a valid wndPtr */
2221 if (offset > (int)(wndPtr->cbWndExtra - size))
2223 WARN("Invalid offset %d\n", offset );
2224 WIN_ReleasePtr( wndPtr );
2225 SetLastError( ERROR_INVALID_INDEX );
2228 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2230 /* Special case for dialog window procedure */
2231 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2232 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2233 WIN_ReleasePtr( wndPtr );
2239 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2240 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2241 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2242 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2243 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2245 /* This looks like a hack only for the edit control (see tests). This makes these controls
2246 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2247 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2249 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2250 retvalue = (ULONG_PTR)wndPtr->winproc;
2252 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2255 WARN("Unknown offset %d\n", offset );
2256 SetLastError( ERROR_INVALID_INDEX );
2259 WIN_ReleasePtr(wndPtr);
2264 /**********************************************************************
2267 * Helper function for SetWindowLong().
2269 * 0 is the failure code. However, in the case of failure SetLastError
2270 * must be set to distinguish between a 0 return value and a failure.
2272 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2275 BOOL ok, needs_show = FALSE;
2276 LONG_PTR retval = 0;
2279 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2281 if (is_broadcast(hwnd))
2283 SetLastError( ERROR_INVALID_PARAMETER );
2287 if (!(wndPtr = WIN_GetPtr( hwnd )))
2289 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2292 if (wndPtr == WND_DESKTOP)
2294 /* can't change anything on the desktop window */
2295 SetLastError( ERROR_ACCESS_DENIED );
2298 if (wndPtr == WND_OTHER_PROCESS)
2300 if (offset == GWLP_WNDPROC)
2302 SetLastError( ERROR_ACCESS_DENIED );
2305 if (offset > 32767 || offset < -32767)
2307 SetLastError( ERROR_INVALID_INDEX );
2310 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2313 /* first some special cases */
2317 style.styleOld = wndPtr->dwStyle;
2318 style.styleNew = newval;
2319 WIN_ReleasePtr( wndPtr );
2320 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2321 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2322 newval = style.styleNew;
2323 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2324 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2325 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2326 WS_EX_WINDOWEDGE too */
2329 style.styleOld = wndPtr->dwExStyle;
2330 style.styleNew = newval;
2331 WIN_ReleasePtr( wndPtr );
2332 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2333 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2334 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2335 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2336 /* WS_EX_WINDOWEDGE depends on some other styles */
2337 if (newval & WS_EX_DLGMODALFRAME)
2338 newval |= WS_EX_WINDOWEDGE;
2339 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2340 newval |= WS_EX_WINDOWEDGE;
2342 newval &= ~WS_EX_WINDOWEDGE;
2344 case GWLP_HWNDPARENT:
2345 if (wndPtr->parent == GetDesktopWindow())
2347 WIN_ReleasePtr( wndPtr );
2348 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2352 WIN_ReleasePtr( wndPtr );
2353 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2358 UINT old_flags = wndPtr->flags;
2359 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2360 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2361 if (proc) wndPtr->winproc = proc;
2362 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2363 else wndPtr->flags &= ~WIN_ISUNICODE;
2364 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2366 WIN_ReleasePtr( wndPtr );
2369 /* update is_unicode flag on the server side */
2373 case GWLP_HINSTANCE:
2377 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2378 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2380 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2381 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2382 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2383 WIN_ReleasePtr( wndPtr );
2388 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2390 WARN("Invalid offset %d\n", offset );
2391 WIN_ReleasePtr( wndPtr );
2392 SetLastError( ERROR_INVALID_INDEX );
2395 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2397 /* already set to the same value */
2398 WIN_ReleasePtr( wndPtr );
2404 SERVER_START_REQ( set_window_info )
2406 req->handle = wine_server_user_handle( hwnd );
2407 req->extra_offset = -1;
2411 req->flags = SET_WIN_STYLE;
2412 req->style = newval;
2415 req->flags = SET_WIN_EXSTYLE;
2416 req->ex_style = newval;
2419 req->flags = SET_WIN_ID;
2422 case GWLP_HINSTANCE:
2423 req->flags = SET_WIN_INSTANCE;
2424 req->instance = wine_server_client_ptr( (void *)newval );
2427 req->flags = SET_WIN_UNICODE;
2428 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2431 req->flags = SET_WIN_USERDATA;
2432 req->user_data = newval;
2435 req->flags = SET_WIN_EXTRA;
2436 req->extra_offset = offset;
2437 req->extra_size = size;
2438 set_win_data( &req->extra_value, newval, size );
2440 if ((ok = !wine_server_call_err( req )))
2445 wndPtr->dwStyle = newval;
2446 retval = reply->old_style;
2449 wndPtr->dwExStyle = newval;
2450 retval = reply->old_ex_style;
2453 wndPtr->wIDmenu = newval;
2454 retval = reply->old_id;
2456 case GWLP_HINSTANCE:
2457 wndPtr->hInstance = (HINSTANCE)newval;
2458 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2463 wndPtr->userdata = newval;
2464 retval = reply->old_user_data;
2467 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2468 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2475 if (offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
2477 needs_show = !(wndPtr->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
2478 invalidate_dce( wndPtr, NULL );
2480 WIN_ReleasePtr( wndPtr );
2486 RECT window_rect, client_rect;
2487 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
2488 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
2489 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
2490 &window_rect, &client_rect, NULL );
2492 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2494 style.styleOld = retval;
2495 style.styleNew = newval;
2496 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2497 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2504 /**********************************************************************
2505 * GetWindowWord (USER32.@)
2507 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2512 case GWLP_HINSTANCE:
2513 case GWLP_HWNDPARENT:
2518 WARN("Invalid offset %d\n", offset );
2519 SetLastError( ERROR_INVALID_INDEX );
2524 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2528 /**********************************************************************
2529 * GetWindowLongA (USER32.@)
2531 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2533 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2537 /**********************************************************************
2538 * GetWindowLongW (USER32.@)
2540 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2542 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2546 /**********************************************************************
2547 * SetWindowWord (USER32.@)
2549 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2554 case GWLP_HINSTANCE:
2555 case GWLP_HWNDPARENT:
2560 WARN("Invalid offset %d\n", offset );
2561 SetLastError( ERROR_INVALID_INDEX );
2566 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2570 /**********************************************************************
2571 * SetWindowLongA (USER32.@)
2573 * See SetWindowLongW.
2575 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2577 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2581 /**********************************************************************
2582 * SetWindowLongW (USER32.@) Set window attribute
2584 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2585 * value in a window's extra memory.
2587 * The _hwnd_ parameter specifies the window. is the handle to a
2588 * window that has extra memory. The _newval_ parameter contains the
2589 * new attribute or extra memory value. If positive, the _offset_
2590 * parameter is the byte-addressed location in the window's extra
2591 * memory to set. If negative, _offset_ specifies the window
2592 * attribute to set, and should be one of the following values:
2594 * GWL_EXSTYLE The window's extended window style
2596 * GWL_STYLE The window's window style.
2598 * GWLP_WNDPROC Pointer to the window's window procedure.
2600 * GWLP_HINSTANCE The window's pplication instance handle.
2602 * GWLP_ID The window's identifier.
2604 * GWLP_USERDATA The window's user-specified data.
2606 * If the window is a dialog box, the _offset_ parameter can be one of
2607 * the following values:
2609 * DWLP_DLGPROC The address of the window's dialog box procedure.
2611 * DWLP_MSGRESULT The return value of a message
2612 * that the dialog box procedure processed.
2614 * DWLP_USER Application specific information.
2618 * If successful, returns the previous value located at _offset_. Otherwise,
2623 * Extra memory for a window class is specified by a nonzero cbWndExtra
2624 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2625 * time of class creation.
2627 * Using GWL_WNDPROC to set a new window procedure effectively creates
2628 * a window subclass. Use CallWindowProc() in the new windows procedure
2629 * to pass messages to the superclass's window procedure.
2631 * The user data is reserved for use by the application which created
2634 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2635 * instead, call the EnableWindow() function to change the window's
2638 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2639 * SetParent() instead.
2642 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2643 * it sends WM_STYLECHANGING before changing the settings
2644 * and WM_STYLECHANGED afterwards.
2645 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2647 LONG WINAPI SetWindowLongW(
2648 HWND hwnd, /* [in] window to alter */
2649 INT offset, /* [in] offset, in bytes, of location to alter */
2650 LONG newval /* [in] new value of location */
2652 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2656 /*******************************************************************
2657 * GetWindowTextA (USER32.@)
2659 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2663 if (!lpString) return 0;
2665 if (WIN_IsCurrentProcess( hwnd ))
2666 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2668 /* when window belongs to other process, don't send a message */
2669 if (nMaxCount <= 0) return 0;
2670 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2671 get_server_window_text( hwnd, buffer, nMaxCount );
2672 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2673 lpString[nMaxCount-1] = 0;
2674 HeapFree( GetProcessHeap(), 0, buffer );
2675 return strlen(lpString);
2679 /*******************************************************************
2680 * InternalGetWindowText (USER32.@)
2682 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2686 if (nMaxCount <= 0) return 0;
2687 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2688 if (win == WND_DESKTOP) lpString[0] = 0;
2689 else if (win != WND_OTHER_PROCESS)
2691 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2692 else lpString[0] = 0;
2693 WIN_ReleasePtr( win );
2697 get_server_window_text( hwnd, lpString, nMaxCount );
2699 return strlenW(lpString);
2703 /*******************************************************************
2704 * GetWindowTextW (USER32.@)
2706 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2708 if (!lpString) return 0;
2710 if (WIN_IsCurrentProcess( hwnd ))
2711 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2713 /* when window belongs to other process, don't send a message */
2714 if (nMaxCount <= 0) return 0;
2715 get_server_window_text( hwnd, lpString, nMaxCount );
2716 return strlenW(lpString);
2720 /*******************************************************************
2721 * SetWindowTextA (USER32.@)
2722 * SetWindowText (USER32.@)
2724 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2726 if (is_broadcast(hwnd))
2728 SetLastError( ERROR_INVALID_PARAMETER );
2731 if (!WIN_IsCurrentProcess( hwnd ))
2732 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2733 debugstr_a(lpString), hwnd );
2734 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2738 /*******************************************************************
2739 * SetWindowTextW (USER32.@)
2741 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2743 if (is_broadcast(hwnd))
2745 SetLastError( ERROR_INVALID_PARAMETER );
2748 if (!WIN_IsCurrentProcess( hwnd ))
2749 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2750 debugstr_w(lpString), hwnd );
2751 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2755 /*******************************************************************
2756 * GetWindowTextLengthA (USER32.@)
2758 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2760 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2763 /*******************************************************************
2764 * GetWindowTextLengthW (USER32.@)
2766 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2768 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2772 /*******************************************************************
2773 * IsWindow (USER32.@)
2775 BOOL WINAPI IsWindow( HWND hwnd )
2780 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2781 if (ptr == WND_DESKTOP) return TRUE;
2783 if (ptr != WND_OTHER_PROCESS)
2785 WIN_ReleasePtr( ptr );
2789 /* check other processes */
2790 SERVER_START_REQ( get_window_info )
2792 req->handle = wine_server_user_handle( hwnd );
2793 ret = !wine_server_call_err( req );
2800 /***********************************************************************
2801 * GetWindowThreadProcessId (USER32.@)
2803 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2808 if (!(ptr = WIN_GetPtr( hwnd )))
2810 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2814 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2816 /* got a valid window */
2818 if (process) *process = GetCurrentProcessId();
2819 WIN_ReleasePtr( ptr );
2823 /* check other processes */
2824 SERVER_START_REQ( get_window_info )
2826 req->handle = wine_server_user_handle( hwnd );
2827 if (!wine_server_call_err( req ))
2829 tid = (DWORD)reply->tid;
2830 if (process) *process = (DWORD)reply->pid;
2838 /*****************************************************************
2839 * GetParent (USER32.@)
2841 HWND WINAPI GetParent( HWND hwnd )
2846 if (!(wndPtr = WIN_GetPtr( hwnd )))
2848 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2851 if (wndPtr == WND_DESKTOP) return 0;
2852 if (wndPtr == WND_OTHER_PROCESS)
2854 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2855 if (style & (WS_POPUP | WS_CHILD))
2857 SERVER_START_REQ( get_window_tree )
2859 req->handle = wine_server_user_handle( hwnd );
2860 if (!wine_server_call_err( req ))
2862 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2863 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2871 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2872 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2873 WIN_ReleasePtr( wndPtr );
2879 /*****************************************************************
2880 * GetAncestor (USER32.@)
2882 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2885 HWND *list, ret = 0;
2890 if (!(win = WIN_GetPtr( hwnd )))
2892 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2895 if (win == WND_DESKTOP) return 0;
2896 if (win != WND_OTHER_PROCESS)
2899 WIN_ReleasePtr( win );
2901 else /* need to query the server */
2903 SERVER_START_REQ( get_window_tree )
2905 req->handle = wine_server_user_handle( hwnd );
2906 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2913 if (!(list = list_window_parents( hwnd ))) return 0;
2915 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2919 while (list[count]) count++;
2920 ret = list[count - 2]; /* get the one before the desktop */
2922 HeapFree( GetProcessHeap(), 0, list );
2926 if (is_desktop_window( hwnd )) return 0;
2927 ret = WIN_GetFullHandle( hwnd );
2930 HWND parent = GetParent( ret );
2940 /*****************************************************************
2941 * SetParent (USER32.@)
2943 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2946 HWND old_parent = 0;
2952 if (is_broadcast(hwnd) || is_broadcast(parent))
2954 SetLastError(ERROR_INVALID_PARAMETER);
2958 if (!parent) parent = GetDesktopWindow();
2959 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2960 else parent = WIN_GetFullHandle( parent );
2962 if (!IsWindow( parent ))
2964 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2968 /* Some applications try to set a child as a parent */
2969 if (IsChild(hwnd, parent))
2971 SetLastError( ERROR_INVALID_PARAMETER );
2975 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2976 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2978 if (full_handle == parent)
2980 SetLastError( ERROR_INVALID_PARAMETER );
2984 /* Windows hides the window first, then shows it again
2985 * including the WM_SHOWWINDOW messages and all */
2986 was_visible = ShowWindow( hwnd, SW_HIDE );
2988 wndPtr = WIN_GetPtr( hwnd );
2989 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2991 pt.x = wndPtr->rectWindow.left;
2992 pt.y = wndPtr->rectWindow.top;
2994 SERVER_START_REQ( set_parent )
2996 req->handle = wine_server_user_handle( hwnd );
2997 req->parent = wine_server_user_handle( parent );
2998 if ((ret = !wine_server_call( req )))
3000 old_parent = wine_server_ptr_handle( reply->old_parent );
3001 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3006 WIN_ReleasePtr( wndPtr );
3009 USER_Driver->pSetParent( full_handle, parent, old_parent );
3011 /* SetParent additionally needs to make hwnd the topmost window
3012 in the x-order and send the expected WM_WINDOWPOSCHANGING and
3013 WM_WINDOWPOSCHANGED notification messages.
3015 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3017 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3023 /*******************************************************************
3024 * IsChild (USER32.@)
3026 BOOL WINAPI IsChild( HWND parent, HWND child )
3028 HWND *list = list_window_parents( child );
3032 if (!list) return FALSE;
3033 parent = WIN_GetFullHandle( parent );
3034 for (i = 0; list[i]; i++) if (list[i] == parent) break;
3035 ret = list[i] && list[i+1];
3036 HeapFree( GetProcessHeap(), 0, list );
3041 /***********************************************************************
3042 * IsWindowVisible (USER32.@)
3044 BOOL WINAPI IsWindowVisible( HWND hwnd )
3050 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3051 if (!(list = list_window_parents( hwnd ))) return TRUE;
3054 for (i = 0; list[i+1]; i++)
3055 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3056 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3058 HeapFree( GetProcessHeap(), 0, list );
3063 /***********************************************************************
3064 * WIN_IsWindowDrawable
3066 * hwnd is drawable when it is visible, all parents are not
3067 * minimized, and it is itself not minimized unless we are
3068 * trying to draw its default class icon.
3070 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3075 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3077 if (!(style & WS_VISIBLE)) return FALSE;
3078 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3080 if (!(list = list_window_parents( hwnd ))) return TRUE;
3083 for (i = 0; list[i+1]; i++)
3084 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3086 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3088 HeapFree( GetProcessHeap(), 0, list );
3093 /*******************************************************************
3094 * GetTopWindow (USER32.@)
3096 HWND WINAPI GetTopWindow( HWND hwnd )
3098 if (!hwnd) hwnd = GetDesktopWindow();
3099 return GetWindow( hwnd, GW_CHILD );
3103 /*******************************************************************
3104 * GetWindow (USER32.@)
3106 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3110 if (rel == GW_OWNER) /* this one may be available locally */
3112 WND *wndPtr = WIN_GetPtr( hwnd );
3115 SetLastError( ERROR_INVALID_HANDLE );
3118 if (wndPtr == WND_DESKTOP) return 0;
3119 if (wndPtr != WND_OTHER_PROCESS)
3121 retval = wndPtr->owner;
3122 WIN_ReleasePtr( wndPtr );
3125 /* else fall through to server call */
3128 SERVER_START_REQ( get_window_tree )
3130 req->handle = wine_server_user_handle( hwnd );
3131 if (!wine_server_call_err( req ))
3136 retval = wine_server_ptr_handle( reply->first_sibling );
3139 retval = wine_server_ptr_handle( reply->last_sibling );
3142 retval = wine_server_ptr_handle( reply->next_sibling );
3145 retval = wine_server_ptr_handle( reply->prev_sibling );
3148 retval = wine_server_ptr_handle( reply->owner );
3151 retval = wine_server_ptr_handle( reply->first_child );
3161 /*******************************************************************
3162 * ShowOwnedPopups (USER32.@)
3164 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3168 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3170 if (!win_array) return TRUE;
3172 while (win_array[count]) count++;
3173 while (--count >= 0)
3175 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3176 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3177 if (pWnd == WND_OTHER_PROCESS) continue;
3180 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3182 WIN_ReleasePtr( pWnd );
3183 /* In Windows, ShowOwnedPopups(TRUE) generates
3184 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3185 * regardless of the state of the owner
3187 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3193 if (pWnd->dwStyle & WS_VISIBLE)
3195 WIN_ReleasePtr( pWnd );
3196 /* In Windows, ShowOwnedPopups(FALSE) generates
3197 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3198 * regardless of the state of the owner
3200 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3204 WIN_ReleasePtr( pWnd );
3206 HeapFree( GetProcessHeap(), 0, win_array );
3211 /*******************************************************************
3212 * GetLastActivePopup (USER32.@)
3214 HWND WINAPI GetLastActivePopup( HWND hwnd )
3218 SERVER_START_REQ( get_window_info )
3220 req->handle = wine_server_user_handle( hwnd );
3221 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3228 /*******************************************************************
3231 * Build an array of the children of a given window. The array must be
3232 * freed with HeapFree. Returns NULL when no windows are found.
3234 HWND *WIN_ListChildren( HWND hwnd )
3238 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3241 return list_window_children( 0, hwnd, NULL, 0 );
3245 /*******************************************************************
3246 * EnumWindows (USER32.@)
3248 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3254 USER_CheckNotLock();
3256 /* We have to build a list of all windows first, to avoid */
3257 /* unpleasant side-effects, for instance if the callback */
3258 /* function changes the Z-order of the windows. */
3260 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3262 /* Now call the callback function for every window */
3264 for (i = 0; list[i]; i++)
3266 /* Make sure that the window still exists */
3267 if (!IsWindow( list[i] )) continue;
3268 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3270 HeapFree( GetProcessHeap(), 0, list );
3275 /**********************************************************************
3276 * EnumThreadWindows (USER32.@)
3278 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3284 USER_CheckNotLock();
3286 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3288 /* Now call the callback function for every window */
3290 for (i = 0; list[i]; i++)
3291 if (!(ret = func( list[i], lParam ))) break;
3292 HeapFree( GetProcessHeap(), 0, list );
3297 /***********************************************************************
3298 * EnumDesktopWindows (USER32.@)
3300 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3305 USER_CheckNotLock();
3307 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3309 for (i = 0; list[i]; i++)
3310 if (!func( list[i], lparam )) break;
3311 HeapFree( GetProcessHeap(), 0, list );
3316 /**********************************************************************
3317 * WIN_EnumChildWindows
3319 * Helper function for EnumChildWindows().
3321 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3326 for ( ; *list; list++)
3328 /* Make sure that the window still exists */
3329 if (!IsWindow( *list )) continue;
3330 /* Build children list first */
3331 childList = WIN_ListChildren( *list );
3333 ret = func( *list, lParam );
3337 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3338 HeapFree( GetProcessHeap(), 0, childList );
3340 if (!ret) return FALSE;
3346 /**********************************************************************
3347 * EnumChildWindows (USER32.@)
3349 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3354 USER_CheckNotLock();
3356 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3357 ret = WIN_EnumChildWindows( list, func, lParam );
3358 HeapFree( GetProcessHeap(), 0, list );
3363 /*******************************************************************
3364 * AnyPopup (USER32.@)
3366 BOOL WINAPI AnyPopup(void)
3370 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3372 if (!list) return FALSE;
3373 for (i = 0; list[i]; i++)
3375 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3377 retvalue = (list[i] != 0);
3378 HeapFree( GetProcessHeap(), 0, list );
3383 /*******************************************************************
3384 * FlashWindow (USER32.@)
3386 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3390 TRACE("%p\n", hWnd);
3392 if (IsIconic( hWnd ))
3394 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3396 wndPtr = WIN_GetPtr(hWnd);
3397 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3398 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3400 wndPtr->flags |= WIN_NCACTIVATED;
3404 wndPtr->flags &= ~WIN_NCACTIVATED;
3406 WIN_ReleasePtr( wndPtr );
3413 wndPtr = WIN_GetPtr(hWnd);
3414 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3415 hWnd = wndPtr->obj.handle; /* make it a full handle */
3417 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3418 else wparam = (hWnd == GetForegroundWindow());
3420 WIN_ReleasePtr( wndPtr );
3421 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3426 /*******************************************************************
3427 * FlashWindowEx (USER32.@)
3429 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3431 FIXME("%p\n", pfwi);
3435 /*******************************************************************
3436 * GetWindowContextHelpId (USER32.@)
3438 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3441 WND *wnd = WIN_GetPtr( hwnd );
3442 if (!wnd || wnd == WND_DESKTOP) return 0;
3443 if (wnd == WND_OTHER_PROCESS)
3445 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3448 retval = wnd->helpContext;
3449 WIN_ReleasePtr( wnd );
3454 /*******************************************************************
3455 * SetWindowContextHelpId (USER32.@)
3457 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3459 WND *wnd = WIN_GetPtr( hwnd );
3460 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3461 if (wnd == WND_OTHER_PROCESS)
3463 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3466 wnd->helpContext = id;
3467 WIN_ReleasePtr( wnd );
3472 /*******************************************************************
3473 * DragDetect (USER32.@)
3475 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3479 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3480 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3482 rect.left = pt.x - wDragWidth;
3483 rect.right = pt.x + wDragWidth;
3485 rect.top = pt.y - wDragHeight;
3486 rect.bottom = pt.y + wDragHeight;
3492 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3494 if( msg.message == WM_LBUTTONUP )
3499 if( msg.message == WM_MOUSEMOVE )
3502 tmp.x = (short)LOWORD(msg.lParam);
3503 tmp.y = (short)HIWORD(msg.lParam);
3504 if( !PtInRect( &rect, tmp ))
3516 /******************************************************************************
3517 * GetWindowModuleFileNameA (USER32.@)
3519 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3524 TRACE( "%p, %p, %u\n", hwnd, module, size );
3526 win = WIN_GetPtr( hwnd );
3527 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3529 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3532 hinst = win->hInstance;
3533 WIN_ReleasePtr( win );
3535 return GetModuleFileNameA( hinst, module, size );
3538 /******************************************************************************
3539 * GetWindowModuleFileNameW (USER32.@)
3541 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3546 TRACE( "%p, %p, %u\n", hwnd, module, size );
3548 win = WIN_GetPtr( hwnd );
3549 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3551 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3554 hinst = win->hInstance;
3555 WIN_ReleasePtr( win );
3557 return GetModuleFileNameW( hinst, module, size );
3560 /******************************************************************************
3561 * GetWindowInfo (USER32.@)
3563 * Note: tests show that Windows doesn't check cbSize of the structure.
3565 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3567 if (!pwi) return FALSE;
3568 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3570 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3571 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3572 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3574 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3575 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3577 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3578 pwi->wCreatorVersion = 0x0400;
3583 /******************************************************************************
3584 * SwitchDesktop (USER32.@)
3586 * NOTES: Sets the current input or interactive desktop.
3588 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3590 FIXME("(hwnd %p) stub!\n", hDesktop);
3594 /*****************************************************************************
3595 * SetLayeredWindowAttributes (USER32.@)
3597 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3601 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3603 SERVER_START_REQ( set_window_layered_info )
3605 req->handle = wine_server_user_handle( hwnd );
3606 req->color_key = key;
3609 ret = !wine_server_call_err( req );
3613 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3619 /*****************************************************************************
3620 * GetLayeredWindowAttributes (USER32.@)
3622 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3626 SERVER_START_REQ( get_window_layered_info )
3628 req->handle = wine_server_user_handle( hwnd );
3629 if ((ret = !wine_server_call_err( req )))
3631 if (key) *key = reply->color_key;
3632 if (alpha) *alpha = reply->alpha;
3633 if (flags) *flags = reply->flags;
3642 /*****************************************************************************
3643 * UpdateLayeredWindowIndirect (USER32.@)
3645 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3647 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3648 RECT window_rect, client_rect;
3653 info->cbSize != sizeof(*info) ||
3654 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3655 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3656 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3658 SetLastError( ERROR_INVALID_PARAMETER );
3662 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3666 offset.cx = info->pptDst->x - window_rect.left;
3667 offset.cy = info->pptDst->y - window_rect.top;
3668 OffsetRect( &client_rect, offset.cx, offset.cy );
3669 OffsetRect( &window_rect, offset.cx, offset.cy );
3670 flags &= ~SWP_NOMOVE;
3674 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3675 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3676 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3678 SetLastError( ERROR_INVALID_PARAMETER );
3681 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3683 SetLastError( ERROR_INCORRECT_SIZE );
3686 client_rect.right += offset.cx;
3687 client_rect.bottom += offset.cy;
3688 window_rect.right += offset.cx;
3689 window_rect.bottom += offset.cy;
3690 flags &= ~SWP_NOSIZE;
3693 TRACE( "window %p win %s client %s\n", hwnd,
3694 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3695 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3699 HDC hdc = GetWindowDC( hwnd );
3706 GetWindowRect( hwnd, &rect );
3707 OffsetRect( &rect, -rect.left, -rect.top);
3710 x = info->pptSrc->x;
3711 y = info->pptSrc->y;
3714 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3716 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3717 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3718 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3720 ReleaseDC( hwnd, hdc );
3724 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3725 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3726 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3727 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3732 /*****************************************************************************
3733 * UpdateLayeredWindow (USER32.@)
3735 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3736 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3739 UPDATELAYEREDWINDOWINFO info;
3741 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3743 SetLastError( ERROR_INVALID_PARAMETER );
3746 info.cbSize = sizeof(info);
3747 info.hdcDst = hdcDst;
3748 info.pptDst = pptDst;
3750 info.hdcSrc = hdcSrc;
3751 info.pptSrc = pptSrc;
3753 info.pblend = pblend;
3754 info.dwFlags = flags;
3755 info.prcDirty = NULL;
3756 return UpdateLayeredWindowIndirect( hwnd, &info );
3760 /******************************************************************************
3761 * GetProcessDefaultLayout [USER32.@]
3763 * Gets the default layout for parentless windows.
3765 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3769 SetLastError( ERROR_NOACCESS );
3772 if (process_layout == ~0u)
3774 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3775 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3776 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3777 '\\','%','0','4','x','%','0','4','x',
3778 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3779 WCHAR *str, buffer[MAX_PATH];
3780 DWORD i, len, version_layout = 0;
3781 DWORD user_lang = GetUserDefaultLangID();
3785 GetModuleFileNameW( 0, buffer, MAX_PATH );
3786 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3787 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3788 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3789 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3791 len /= sizeof(DWORD);
3792 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3793 if (i == len) /* try neutral language */
3794 for (i = 0; i < len; i++)
3795 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3796 if (i == len) i = 0; /* default to the first one */
3798 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3799 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3800 TRACE( "found description %s\n", debugstr_w( str ));
3801 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3804 HeapFree( GetProcessHeap(), 0, data );
3805 process_layout = version_layout;
3807 *layout = process_layout;
3812 /******************************************************************************
3813 * SetProcessDefaultLayout [USER32.@]
3815 * Sets the default layout for parentless windows.
3817 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3819 process_layout = layout;
3824 /* 64bit versions */
3826 #ifdef GetWindowLongPtrW
3827 #undef GetWindowLongPtrW
3830 #ifdef GetWindowLongPtrA
3831 #undef GetWindowLongPtrA
3834 #ifdef SetWindowLongPtrW
3835 #undef SetWindowLongPtrW
3838 #ifdef SetWindowLongPtrA
3839 #undef SetWindowLongPtrA
3842 /*****************************************************************************
3843 * GetWindowLongPtrW (USER32.@)
3845 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3847 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3850 /*****************************************************************************
3851 * GetWindowLongPtrA (USER32.@)
3853 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3855 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3858 /*****************************************************************************
3859 * SetWindowLongPtrW (USER32.@)
3861 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3863 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3866 /*****************************************************************************
3867 * SetWindowLongPtrA (USER32.@)
3869 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3871 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );