2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
31 #include "wine/server.h"
32 #include "wine/unicode.h"
34 #include "user_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(win);
41 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
42 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
44 static DWORD process_layout = ~0u;
46 /**********************************************************************/
48 /* helper for Get/SetWindowLong */
49 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 if (size == sizeof(WORD))
54 memcpy( &ret, ptr, sizeof(ret) );
57 else if (size == sizeof(DWORD))
60 memcpy( &ret, ptr, sizeof(ret) );
66 memcpy( &ret, ptr, sizeof(ret) );
71 /* helper for Get/SetWindowLong */
72 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 if (size == sizeof(WORD))
77 memcpy( ptr, &newval, sizeof(newval) );
79 else if (size == sizeof(DWORD))
82 memcpy( ptr, &newval, sizeof(newval) );
86 memcpy( ptr, &val, sizeof(val) );
91 static void *user_handles[NB_USER_HANDLES];
93 /***********************************************************************
96 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
100 SERVER_START_REQ( alloc_user_handle )
102 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
108 UINT index = USER_HANDLE_TO_INDEX( handle );
110 assert( index < NB_USER_HANDLES );
111 ptr->handle = handle;
113 InterlockedExchangePointer( &user_handles[index], ptr );
119 /***********************************************************************
120 * get_user_handle_ptr
122 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
124 struct user_object *ptr;
125 WORD index = USER_HANDLE_TO_INDEX( handle );
127 if (index >= NB_USER_HANDLES) return NULL;
130 if ((ptr = user_handles[index]))
132 if (ptr->type == type &&
133 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
134 !HIWORD(handle) || HIWORD(handle) == 0xffff))
138 else ptr = OBJ_OTHER_PROCESS;
144 /***********************************************************************
145 * release_user_handle_ptr
147 void release_user_handle_ptr( void *ptr )
149 assert( ptr && ptr != OBJ_OTHER_PROCESS );
154 /***********************************************************************
157 void *free_user_handle( HANDLE handle, enum user_obj_type type )
159 struct user_object *ptr;
160 WORD index = USER_HANDLE_TO_INDEX( handle );
162 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
164 SERVER_START_REQ( free_user_handle )
166 req->handle = wine_server_user_handle( handle );
167 if (wine_server_call( req )) ptr = NULL;
168 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
171 release_user_handle_ptr( ptr );
177 /***********************************************************************
178 * create_window_handle
180 * Create a window handle with the server.
182 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
183 HINSTANCE instance, BOOL unicode )
187 HWND handle = 0, full_parent = 0, full_owner = 0;
188 struct tagCLASS *class = NULL;
191 SERVER_START_REQ( create_window )
193 req->parent = wine_server_user_handle( parent );
194 req->owner = wine_server_user_handle( owner );
195 req->instance = wine_server_client_ptr( instance );
196 if (!(req->atom = get_int_atom_value( name )) && name)
197 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
198 if (!wine_server_call_err( req ))
200 handle = wine_server_ptr_handle( reply->handle );
201 full_parent = wine_server_ptr_handle( reply->parent );
202 full_owner = wine_server_ptr_handle( reply->owner );
203 extra_bytes = reply->extra;
204 class = wine_server_get_ptr( reply->class_ptr );
211 WARN( "error %d creating window\n", GetLastError() );
215 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
216 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
218 SERVER_START_REQ( destroy_window )
220 req->handle = wine_server_user_handle( handle );
221 wine_server_call( req );
224 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
228 if (!parent) /* if parent is 0 we don't have a desktop window yet */
230 struct user_thread_info *thread_info = get_user_thread_info();
232 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
234 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
235 else assert( full_parent == thread_info->top_window );
236 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
237 ERR( "failed to create desktop window\n" );
239 else /* HWND_MESSAGE parent */
241 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
247 index = USER_HANDLE_TO_INDEX(handle);
248 assert( index < NB_USER_HANDLES );
249 win->obj.handle = handle;
250 win->obj.type = USER_WINDOW;
251 win->parent = full_parent;
252 win->owner = full_owner;
254 win->winproc = get_class_winproc( class );
255 win->cbWndExtra = extra_bytes;
256 InterlockedExchangePointer( &user_handles[index], win );
257 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
262 /***********************************************************************
265 * Free a window handle.
267 static void free_window_handle( HWND hwnd )
269 struct user_object *ptr;
270 WORD index = USER_HANDLE_TO_INDEX(hwnd);
272 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
274 SERVER_START_REQ( destroy_window )
276 req->handle = wine_server_user_handle( hwnd );
277 if (wine_server_call_err( req )) ptr = NULL;
278 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
281 release_user_handle_ptr( ptr );
282 HeapFree( GetProcessHeap(), 0, ptr );
287 /*******************************************************************
288 * list_window_children
290 * Build an array of the children of a given window. The array must be
291 * freed with HeapFree. Returns NULL when no windows are found.
293 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
297 ATOM atom = get_int_atom_value( class );
299 /* empty class is not the same as NULL class */
300 if (!atom && class && !class[0]) return NULL;
306 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
308 SERVER_START_REQ( get_window_children )
310 req->desktop = wine_server_obj_handle( desktop );
311 req->parent = wine_server_user_handle( hwnd );
314 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
315 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
316 if (!wine_server_call( req )) count = reply->count;
319 if (count && count < size)
321 /* start from the end since HWND is potentially larger than user_handle_t */
322 for (i = count - 1; i >= 0; i--)
323 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
327 HeapFree( GetProcessHeap(), 0, list );
329 size = count + 1; /* restart with a large enough buffer */
335 /*******************************************************************
336 * list_window_parents
338 * Build an array of all parents of a given window, starting with
339 * the immediate parent. The array must be freed with HeapFree.
341 static HWND *list_window_parents( HWND hwnd )
345 int i, pos = 0, size = 16, count = 0;
347 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
352 if (!(win = WIN_GetPtr( current ))) goto empty;
353 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
354 if (win == WND_DESKTOP)
356 if (!pos) goto empty;
360 list[pos] = current = win->parent;
361 WIN_ReleasePtr( win );
362 if (!current) return list;
363 if (++pos == size - 1)
365 /* need to grow the list */
366 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
367 if (!new_list) goto empty;
373 /* at least one parent belongs to another process, have to query the server */
378 SERVER_START_REQ( get_window_parents )
380 req->handle = wine_server_user_handle( hwnd );
381 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
382 if (!wine_server_call( req )) count = reply->count;
385 if (!count) goto empty;
388 /* start from the end since HWND is potentially larger than user_handle_t */
389 for (i = count - 1; i >= 0; i--)
390 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
394 HeapFree( GetProcessHeap(), 0, list );
396 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
400 HeapFree( GetProcessHeap(), 0, list );
405 /*******************************************************************
408 static void send_parent_notify( HWND hwnd, UINT msg )
410 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
411 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
413 HWND parent = GetParent(hwnd);
414 if (parent && parent != GetDesktopWindow())
415 SendMessageW( parent, WM_PARENTNOTIFY,
416 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
421 /*******************************************************************
422 * get_server_window_text
424 * Retrieve the window text from the server.
426 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
430 SERVER_START_REQ( get_window_text )
432 req->handle = wine_server_user_handle( hwnd );
433 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
434 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
437 text[len / sizeof(WCHAR)] = 0;
441 /*******************************************************************
442 * get_hwnd_message_parent
444 * Return the parent for HWND_MESSAGE windows.
446 HWND get_hwnd_message_parent(void)
448 struct user_thread_info *thread_info = get_user_thread_info();
450 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
451 return thread_info->msg_window;
455 /*******************************************************************
458 * Check if window is the desktop or the HWND_MESSAGE top parent.
460 BOOL is_desktop_window( HWND hwnd )
462 struct user_thread_info *thread_info = get_user_thread_info();
464 if (!hwnd) return FALSE;
465 if (hwnd == thread_info->top_window) return TRUE;
466 if (hwnd == thread_info->msg_window) return TRUE;
468 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
470 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
471 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
477 /***********************************************************************
480 * Return a pointer to the WND structure if local to the process,
481 * or WND_OTHER_PROCESS if handle may be valid in other process.
482 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
484 WND *WIN_GetPtr( HWND hwnd )
488 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
490 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
496 /***********************************************************************
497 * WIN_IsCurrentProcess
499 * Check whether a given window belongs to the current process (and return the full handle).
501 HWND WIN_IsCurrentProcess( HWND hwnd )
506 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
507 ret = ptr->obj.handle;
508 WIN_ReleasePtr( ptr );
513 /***********************************************************************
514 * WIN_IsCurrentThread
516 * Check whether a given window belongs to the current thread (and return the full handle).
518 HWND WIN_IsCurrentThread( HWND hwnd )
523 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
524 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
525 WIN_ReleasePtr( ptr );
530 /***********************************************************************
533 * Convert a possibly truncated window handle to a full 32-bit handle.
535 HWND WIN_GetFullHandle( HWND hwnd )
539 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
540 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
541 /* do sign extension for -2 and -3 */
542 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
544 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
546 if (ptr == WND_DESKTOP)
548 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
549 else return get_hwnd_message_parent();
552 if (ptr != WND_OTHER_PROCESS)
554 hwnd = ptr->obj.handle;
555 WIN_ReleasePtr( ptr );
557 else /* may belong to another process */
559 SERVER_START_REQ( get_window_info )
561 req->handle = wine_server_user_handle( hwnd );
562 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
570 /***********************************************************************
573 * Change the owner of a window.
575 HWND WIN_SetOwner( HWND hwnd, HWND owner )
577 WND *win = WIN_GetPtr( hwnd );
580 if (!win || win == WND_DESKTOP) return 0;
581 if (win == WND_OTHER_PROCESS)
583 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
586 SERVER_START_REQ( set_window_owner )
588 req->handle = wine_server_user_handle( hwnd );
589 req->owner = wine_server_user_handle( owner );
590 if (!wine_server_call( req ))
592 win->owner = wine_server_ptr_handle( reply->full_owner );
593 ret = wine_server_ptr_handle( reply->prev_owner );
597 WIN_ReleasePtr( win );
602 /***********************************************************************
605 * Change the style of a window.
607 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
611 WND *win = WIN_GetPtr( hwnd );
613 if (!win || win == WND_DESKTOP) return 0;
614 if (win == WND_OTHER_PROCESS)
617 ERR( "cannot set style %x/%x on other process window %p\n",
618 set_bits, clear_bits, hwnd );
621 style.styleOld = win->dwStyle;
622 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
623 if (style.styleNew == style.styleOld)
625 WIN_ReleasePtr( win );
626 return style.styleNew;
628 SERVER_START_REQ( set_window_info )
630 req->handle = wine_server_user_handle( hwnd );
631 req->flags = SET_WIN_STYLE;
632 req->style = style.styleNew;
633 req->extra_offset = -1;
634 if ((ok = !wine_server_call( req )))
636 style.styleOld = reply->old_style;
637 win->dwStyle = style.styleNew;
641 WIN_ReleasePtr( win );
644 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
645 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
647 return style.styleOld;
651 /***********************************************************************
654 * Get the window and client rectangles.
656 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
658 WND *win = WIN_GetPtr( hwnd );
663 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
666 if (win == WND_DESKTOP)
669 rect.left = rect.top = 0;
670 if (hwnd == get_hwnd_message_parent())
677 rect.right = GetSystemMetrics(SM_CXSCREEN);
678 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
680 if (rectWindow) *rectWindow = rect;
681 if (rectClient) *rectClient = rect;
684 if (win != WND_OTHER_PROCESS)
686 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
691 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
692 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
693 if (win->dwExStyle & WS_EX_LAYOUTRTL)
694 mirror_rect( &win->rectClient, &window_rect );
697 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
698 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
699 if (win->dwExStyle & WS_EX_LAYOUTRTL)
700 mirror_rect( &win->rectWindow, &client_rect );
705 WND *parent = WIN_GetPtr( win->parent );
706 if (parent == WND_DESKTOP) break;
707 if (!parent || parent == WND_OTHER_PROCESS)
709 WIN_ReleasePtr( win );
712 if (parent->flags & WIN_CHILDREN_MOVED)
714 WIN_ReleasePtr( parent );
715 WIN_ReleasePtr( win );
718 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
720 mirror_rect( &parent->rectClient, &window_rect );
721 mirror_rect( &parent->rectClient, &client_rect );
723 WIN_ReleasePtr( parent );
729 WND *parent = WIN_GetPtr( win->parent );
730 if (parent == WND_DESKTOP) break;
731 if (!parent || parent == WND_OTHER_PROCESS)
733 WIN_ReleasePtr( win );
736 WIN_ReleasePtr( win );
737 if (parent->flags & WIN_CHILDREN_MOVED)
739 WIN_ReleasePtr( parent );
743 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
744 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
748 if (rectWindow) *rectWindow = window_rect;
749 if (rectClient) *rectClient = client_rect;
750 WIN_ReleasePtr( win );
755 SERVER_START_REQ( get_window_rectangles )
757 req->handle = wine_server_user_handle( hwnd );
758 req->relative = relative;
759 if ((ret = !wine_server_call_err( req )))
763 rectWindow->left = reply->window.left;
764 rectWindow->top = reply->window.top;
765 rectWindow->right = reply->window.right;
766 rectWindow->bottom = reply->window.bottom;
770 rectClient->left = reply->client.left;
771 rectClient->top = reply->client.top;
772 rectClient->right = reply->client.right;
773 rectClient->bottom = reply->client.bottom;
782 /***********************************************************************
785 * Destroy storage associated to a window. "Internals" p.358
787 LRESULT WIN_DestroyWindow( HWND hwnd )
791 HMENU menu = 0, sys_menu;
794 TRACE("%p\n", hwnd );
796 /* free child windows */
797 if ((list = WIN_ListChildren( hwnd )))
800 for (i = 0; list[i]; i++)
802 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
803 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
805 HeapFree( GetProcessHeap(), 0, list );
808 /* Unlink now so we won't bother with the children later on */
809 SERVER_START_REQ( set_parent )
811 req->handle = wine_server_user_handle( hwnd );
813 wine_server_call( req );
818 * Send the WM_NCDESTROY to the window being destroyed.
820 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
822 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
824 /* free resources associated with the window */
826 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
827 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
828 menu = (HMENU)wndPtr->wIDmenu;
829 sys_menu = wndPtr->hSysMenu;
830 free_dce( wndPtr->dce, hwnd );
832 icon_title = wndPtr->icon_title;
833 HeapFree( GetProcessHeap(), 0, wndPtr->text );
835 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
836 wndPtr->pScroll = NULL;
837 WIN_ReleasePtr( wndPtr );
839 if (icon_title) DestroyWindow( icon_title );
840 if (menu) DestroyMenu( menu );
841 if (sys_menu) DestroyMenu( sys_menu );
843 USER_Driver->pDestroyWindow( hwnd );
845 free_window_handle( hwnd );
850 /***********************************************************************
851 * destroy_thread_window
853 * Destroy a window upon exit of its thread.
855 static void destroy_thread_window( HWND hwnd )
859 HMENU menu = 0, sys_menu = 0;
862 /* free child windows */
864 if ((list = WIN_ListChildren( hwnd )))
867 for (i = 0; list[i]; i++)
869 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
870 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
872 HeapFree( GetProcessHeap(), 0, list );
875 /* destroy the client-side storage */
877 index = USER_HANDLE_TO_INDEX(hwnd);
878 if (index >= NB_USER_HANDLES) return;
880 if ((wndPtr = user_handles[index]))
882 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
883 sys_menu = wndPtr->hSysMenu;
884 free_dce( wndPtr->dce, hwnd );
885 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
889 HeapFree( GetProcessHeap(), 0, wndPtr );
890 if (menu) DestroyMenu( menu );
891 if (sys_menu) DestroyMenu( sys_menu );
895 /***********************************************************************
896 * destroy_thread_child_windows
898 * Destroy child windows upon exit of its thread.
900 static void destroy_thread_child_windows( HWND hwnd )
905 if (WIN_IsCurrentThread( hwnd ))
907 destroy_thread_window( hwnd );
909 else if ((list = WIN_ListChildren( hwnd )))
911 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
912 HeapFree( GetProcessHeap(), 0, list );
917 /***********************************************************************
918 * WIN_DestroyThreadWindows
920 * Destroy all children of 'wnd' owned by the current thread.
922 void WIN_DestroyThreadWindows( HWND hwnd )
927 if (!(list = WIN_ListChildren( hwnd ))) return;
929 /* reset owners of top-level windows */
930 for (i = 0; list[i]; i++)
932 if (!WIN_IsCurrentThread( list[i] ))
934 HWND owner = GetWindow( list[i], GW_OWNER );
935 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
939 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
940 HeapFree( GetProcessHeap(), 0, list );
944 /***********************************************************************
947 * Fix the coordinates - Helper for WIN_CreateWindowEx.
948 * returns default show mode in sw.
950 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
952 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
955 if (cs->dwExStyle & WS_EX_MDICHILD)
959 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
960 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
962 TRACE("MDI child id %04x\n", id);
965 if (cs->style & (WS_CHILD | WS_POPUP))
967 if (cs->dwExStyle & WS_EX_MDICHILD)
969 if (IS_DEFAULT(cs->x))
974 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
975 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
979 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
980 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
983 else /* overlapped window */
986 MONITORINFO mon_info;
989 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
991 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
992 mon_info.cbSize = sizeof(mon_info);
993 GetMonitorInfoW( monitor, &mon_info );
994 GetStartupInfoW( &info );
996 if (IS_DEFAULT(cs->x))
998 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
999 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1000 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1003 if (IS_DEFAULT(cs->cx))
1005 if (info.dwFlags & STARTF_USESIZE)
1007 cs->cx = info.dwXSize;
1008 cs->cy = info.dwYSize;
1012 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1013 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1016 /* neither x nor cx are default. Check the y values .
1017 * In the trace we see Outlook and Outlook Express using
1018 * cy set to CW_USEDEFAULT when opening the address book.
1020 else if (IS_DEFAULT(cs->cy))
1022 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1023 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1029 /***********************************************************************
1030 * dump_window_styles
1032 static void dump_window_styles( DWORD style, DWORD exstyle )
1035 if(style & WS_POPUP) TRACE(" WS_POPUP");
1036 if(style & WS_CHILD) TRACE(" WS_CHILD");
1037 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1038 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1039 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1040 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1041 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1042 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1043 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1046 if(style & WS_BORDER) TRACE(" WS_BORDER");
1047 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1049 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1050 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1051 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1052 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1053 if (style & WS_CHILD)
1055 if(style & WS_GROUP) TRACE(" WS_GROUP");
1056 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1060 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1061 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1064 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1065 #define DUMPED_STYLES \
1085 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1087 #undef DUMPED_STYLES
1089 TRACE( "exstyle:" );
1090 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1091 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1092 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1093 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1094 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1095 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1096 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1097 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1098 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1099 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1100 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1101 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1102 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1103 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1104 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1105 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1106 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1107 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1108 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1110 #define DUMPED_EX_STYLES \
1111 (WS_EX_DLGMODALFRAME | \
1112 WS_EX_DRAGDETECT | \
1113 WS_EX_NOPARENTNOTIFY | \
1115 WS_EX_ACCEPTFILES | \
1116 WS_EX_TRANSPARENT | \
1118 WS_EX_TOOLWINDOW | \
1119 WS_EX_WINDOWEDGE | \
1120 WS_EX_CLIENTEDGE | \
1121 WS_EX_CONTEXTHELP | \
1123 WS_EX_RTLREADING | \
1124 WS_EX_LEFTSCROLLBAR | \
1125 WS_EX_CONTROLPARENT | \
1126 WS_EX_STATICEDGE | \
1131 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1133 #undef DUMPED_EX_STYLES
1137 /***********************************************************************
1138 * WIN_CreateWindowEx
1140 * Implementation of CreateWindowEx().
1142 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1144 INT cx, cy, style, sw = SW_SHOW;
1148 HWND hwnd, parent, owner, top_child = 0;
1149 MDICREATESTRUCTW mdi_cs;
1150 CBT_CREATEWNDW cbtc;
1153 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1154 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1155 debugstr_w(className),
1156 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1157 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1158 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1160 /* Fix the styles for MDI children */
1161 if (cs->dwExStyle & WS_EX_MDICHILD)
1165 wndPtr = WIN_GetPtr(cs->hwndParent);
1166 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1168 flags = wndPtr->flags;
1169 WIN_ReleasePtr(wndPtr);
1172 if (!(flags & WIN_ISMDICLIENT))
1174 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1178 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1179 * MDICREATESTRUCT members have the originally passed values.
1181 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1182 * have the same layout.
1184 mdi_cs.szClass = cs->lpszClass;
1185 mdi_cs.szTitle = cs->lpszName;
1186 mdi_cs.hOwner = cs->hInstance;
1191 mdi_cs.style = cs->style;
1192 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1194 cs->lpCreateParams = &mdi_cs;
1196 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1198 if (cs->style & WS_POPUP)
1200 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1203 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1207 cs->style &= ~WS_POPUP;
1208 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1209 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1212 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1216 /* Restore current maximized child */
1217 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1219 TRACE("Restoring current maximized child %p\n", top_child);
1220 if (cs->style & WS_MAXIMIZE)
1222 /* if the new window is maximized don't bother repainting */
1223 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1224 ShowWindow( top_child, SW_SHOWNORMAL );
1225 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1227 else ShowWindow( top_child, SW_SHOWNORMAL );
1232 /* Find the parent window */
1234 parent = cs->hwndParent;
1237 if (cs->hwndParent == HWND_MESSAGE)
1239 cs->hwndParent = parent = get_hwnd_message_parent();
1241 else if (cs->hwndParent)
1243 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1245 parent = GetDesktopWindow();
1246 owner = cs->hwndParent;
1250 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1251 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1252 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1257 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1259 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1261 WARN("No parent for child window\n" );
1262 SetLastError(ERROR_TLW_WITH_WSCHILD);
1263 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1265 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1266 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1267 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1270 GetProcessDefaultLayout( &layout );
1271 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1272 parent = GetDesktopWindow();
1276 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1278 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1279 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1280 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1281 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1283 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1285 /* Create the window structure */
1287 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1289 hwnd = wndPtr->obj.handle;
1291 /* Fill the window structure */
1293 wndPtr->tid = GetCurrentThreadId();
1294 wndPtr->hInstance = cs->hInstance;
1295 wndPtr->text = NULL;
1296 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1297 wndPtr->dwExStyle = cs->dwExStyle;
1298 wndPtr->wIDmenu = 0;
1299 wndPtr->helpContext = 0;
1300 wndPtr->pScroll = NULL;
1301 wndPtr->userdata = 0;
1303 wndPtr->hIconSmall = 0;
1304 wndPtr->hSysMenu = 0;
1306 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1307 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1309 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1312 * Correct the window styles.
1314 * It affects only the style loaded into the WIN structure.
1317 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1319 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1320 if (!(wndPtr->dwStyle & WS_POPUP))
1321 wndPtr->dwStyle |= WS_CAPTION;
1325 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1326 * why does the user get to set it?
1329 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1330 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1331 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1333 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1335 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1336 wndPtr->flags |= WIN_NEED_SIZE;
1338 SERVER_START_REQ( set_window_info )
1340 req->handle = wine_server_user_handle( hwnd );
1341 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1342 req->style = wndPtr->dwStyle;
1343 req->ex_style = wndPtr->dwExStyle;
1344 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1345 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1346 req->extra_offset = -1;
1347 wine_server_call( req );
1351 /* Set the window menu */
1353 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1357 if (!MENU_SetMenu(hwnd, cs->hMenu))
1359 WIN_ReleasePtr( wndPtr );
1360 free_window_handle( hwnd );
1366 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1369 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1370 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1374 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1376 /* call the WH_CBT hook */
1378 /* the window style passed to the hook must be the real window style,
1379 * rather than just the window style that the caller to CreateWindowEx
1380 * passed in, so we have to copy the original CREATESTRUCT and get the
1381 * the real style. */
1383 cbcs.style = wndPtr->dwStyle;
1385 cbtc.hwndInsertAfter = HWND_TOP;
1386 WIN_ReleasePtr( wndPtr );
1387 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1389 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1393 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1395 POINT maxSize, maxPos, minTrack, maxTrack;
1396 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1397 if (maxTrack.x < cx) cx = maxTrack.x;
1398 if (maxTrack.y < cy) cy = maxTrack.y;
1399 if (minTrack.x > cx) cx = minTrack.x;
1400 if (minTrack.y > cy) cy = minTrack.y;
1405 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1406 /* check for wraparound */
1407 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1408 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1409 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1411 /* send WM_NCCREATE */
1413 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1415 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1417 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1420 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1424 /* send WM_NCCALCSIZE */
1426 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1428 /* yes, even if the CBT hook was called with HWND_TOP */
1429 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1430 RECT client_rect = rect;
1432 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1433 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1434 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1435 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1436 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1440 /* send WM_CREATE */
1443 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1445 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1446 if (result == -1) goto failed;
1448 /* call the driver */
1450 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1452 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1454 /* send the size messages */
1456 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1457 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1458 if (!(wndPtr->flags & WIN_NEED_SIZE))
1460 WIN_ReleasePtr( wndPtr );
1461 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1462 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1463 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1464 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1466 else WIN_ReleasePtr( wndPtr );
1468 /* Show the window, maximizing or minimizing if needed */
1470 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1471 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1474 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1476 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1477 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1478 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1479 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1480 newPos.bottom - newPos.top, swFlag );
1483 /* Notify the parent window only */
1485 send_parent_notify( hwnd, WM_CREATE );
1486 if (!IsWindow( hwnd )) return 0;
1488 if (cs->style & WS_VISIBLE)
1490 if (cs->style & WS_MAXIMIZE)
1492 else if (cs->style & WS_MINIMIZE)
1493 sw = SW_SHOWMINIMIZED;
1495 ShowWindow( hwnd, sw );
1496 if (cs->dwExStyle & WS_EX_MDICHILD)
1498 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1499 /* ShowWindow won't activate child windows */
1500 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1504 /* Call WH_SHELL hook */
1506 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1507 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1509 TRACE("created window %p\n", hwnd);
1513 WIN_DestroyWindow( hwnd );
1518 /***********************************************************************
1519 * CreateWindowExA (USER32.@)
1521 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1522 LPCSTR windowName, DWORD style, INT x,
1523 INT y, INT width, INT height,
1524 HWND parent, HMENU menu,
1525 HINSTANCE instance, LPVOID data )
1529 cs.lpCreateParams = data;
1530 cs.hInstance = instance;
1532 cs.hwndParent = parent;
1538 cs.lpszName = windowName;
1539 cs.lpszClass = className;
1540 cs.dwExStyle = exStyle;
1542 if (!IS_INTRESOURCE(className))
1545 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1547 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1549 /* Note: we rely on the fact that CREATESTRUCTA and */
1550 /* CREATESTRUCTW have the same layout. */
1551 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1555 /***********************************************************************
1556 * CreateWindowExW (USER32.@)
1558 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1559 LPCWSTR windowName, DWORD style, INT x,
1560 INT y, INT width, INT height,
1561 HWND parent, HMENU menu,
1562 HINSTANCE instance, LPVOID data )
1566 cs.lpCreateParams = data;
1567 cs.hInstance = instance;
1569 cs.hwndParent = parent;
1575 cs.lpszName = windowName;
1576 cs.lpszClass = className;
1577 cs.dwExStyle = exStyle;
1579 return wow_handlers.create_window( &cs, className, instance, TRUE );
1583 /***********************************************************************
1584 * WIN_SendDestroyMsg
1586 static void WIN_SendDestroyMsg( HWND hwnd )
1590 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1592 if (hwnd == info.hwndCaret) DestroyCaret();
1593 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1597 * Send the WM_DESTROY to the window.
1599 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1602 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1603 * make sure that the window still exists when we come back.
1610 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1612 for (i = 0; pWndArray[i]; i++)
1614 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1616 HeapFree( GetProcessHeap(), 0, pWndArray );
1619 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1623 /***********************************************************************
1624 * DestroyWindow (USER32.@)
1626 BOOL WINAPI DestroyWindow( HWND hwnd )
1630 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1632 SetLastError( ERROR_ACCESS_DENIED );
1636 TRACE("(%p)\n", hwnd);
1640 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1642 if (MENU_IsMenuActive() == hwnd)
1645 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1649 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1650 send_parent_notify( hwnd, WM_DESTROY );
1652 else if (!GetWindow( hwnd, GW_OWNER ))
1654 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1655 /* FIXME: clean up palette - see "Internals" p.352 */
1658 if (!IsWindow(hwnd)) return TRUE;
1660 /* Hide the window */
1661 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1663 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1665 ShowWindow( hwnd, SW_HIDE );
1667 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1668 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1671 if (!IsWindow(hwnd)) return TRUE;
1673 /* Recursively destroy owned windows */
1680 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1683 for (i = 0; list[i]; i++)
1685 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1686 if (WIN_IsCurrentThread( list[i] ))
1688 DestroyWindow( list[i] );
1692 WIN_SetOwner( list[i], 0 );
1694 HeapFree( GetProcessHeap(), 0, list );
1696 if (!got_one) break;
1700 /* Send destroy messages */
1702 WIN_SendDestroyMsg( hwnd );
1703 if (!IsWindow( hwnd )) return TRUE;
1705 if (GetClipboardOwner() == hwnd)
1706 CLIPBOARD_ReleaseOwner();
1708 /* Destroy the window storage */
1710 WIN_DestroyWindow( hwnd );
1715 /***********************************************************************
1716 * CloseWindow (USER32.@)
1718 BOOL WINAPI CloseWindow( HWND hwnd )
1720 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1721 ShowWindow( hwnd, SW_MINIMIZE );
1726 /***********************************************************************
1727 * OpenIcon (USER32.@)
1729 BOOL WINAPI OpenIcon( HWND hwnd )
1731 if (!IsIconic( hwnd )) return FALSE;
1732 ShowWindow( hwnd, SW_SHOWNORMAL );
1737 /***********************************************************************
1738 * FindWindowExW (USER32.@)
1740 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1745 WCHAR *buffer = NULL;
1747 if (!parent && child) parent = GetDesktopWindow();
1748 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1752 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1753 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1756 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1760 child = WIN_GetFullHandle( child );
1761 while (list[i] && list[i] != child) i++;
1762 if (!list[i]) goto done;
1763 i++; /* start from next window */
1770 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1777 HeapFree( GetProcessHeap(), 0, list );
1778 HeapFree( GetProcessHeap(), 0, buffer );
1784 /***********************************************************************
1785 * FindWindowA (USER32.@)
1787 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1789 HWND ret = FindWindowExA( 0, 0, className, title );
1790 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1795 /***********************************************************************
1796 * FindWindowExA (USER32.@)
1798 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1800 LPWSTR titleW = NULL;
1805 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1806 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1807 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1810 if (!IS_INTRESOURCE(className))
1813 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1814 hwnd = FindWindowExW( parent, child, classW, titleW );
1818 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1821 HeapFree( GetProcessHeap(), 0, titleW );
1826 /***********************************************************************
1827 * FindWindowW (USER32.@)
1829 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1831 return FindWindowExW( 0, 0, className, title );
1835 /**********************************************************************
1836 * GetDesktopWindow (USER32.@)
1838 HWND WINAPI GetDesktopWindow(void)
1840 struct user_thread_info *thread_info = get_user_thread_info();
1842 if (thread_info->top_window) return thread_info->top_window;
1844 SERVER_START_REQ( get_desktop_window )
1847 if (!wine_server_call( req ))
1849 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1850 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1855 if (!thread_info->top_window)
1857 USEROBJECTFLAGS flags;
1858 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1859 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1861 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1862 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1864 PROCESS_INFORMATION pi;
1865 WCHAR windir[MAX_PATH];
1866 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1867 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1870 memset( &si, 0, sizeof(si) );
1872 si.dwFlags = STARTF_USESTDHANDLES;
1875 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1877 GetSystemDirectoryW( windir, MAX_PATH );
1878 strcpyW( app, windir );
1879 strcatW( app, explorer );
1880 strcpyW( cmdline, app );
1881 strcatW( cmdline, args );
1883 Wow64DisableWow64FsRedirection( &redir );
1884 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1885 NULL, windir, &si, &pi ))
1887 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1888 WaitForInputIdle( pi.hProcess, 10000 );
1889 CloseHandle( pi.hThread );
1890 CloseHandle( pi.hProcess );
1892 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1893 Wow64RevertWow64FsRedirection( redir );
1895 else TRACE( "not starting explorer since winstation is not visible\n" );
1897 SERVER_START_REQ( get_desktop_window )
1900 if (!wine_server_call( req ))
1902 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1903 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1909 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1910 ERR( "failed to create desktop window\n" );
1912 return thread_info->top_window;
1916 /*******************************************************************
1917 * EnableWindow (USER32.@)
1919 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1924 if (is_broadcast(hwnd))
1926 SetLastError( ERROR_INVALID_PARAMETER );
1930 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1931 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1935 TRACE("( %p, %d )\n", hwnd, enable);
1937 retvalue = !IsWindowEnabled( hwnd );
1939 if (enable && retvalue)
1941 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1942 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1944 else if (!enable && !retvalue)
1948 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1950 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1952 if (hwnd == GetFocus())
1953 SetFocus( 0 ); /* A disabled window can't have the focus */
1955 capture_wnd = GetCapture();
1956 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1957 ReleaseCapture(); /* A disabled window can't capture the mouse */
1959 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1965 /***********************************************************************
1966 * IsWindowEnabled (USER32.@)
1968 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1970 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1974 /***********************************************************************
1975 * IsWindowUnicode (USER32.@)
1977 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1980 BOOL retvalue = FALSE;
1982 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1984 if (wndPtr == WND_DESKTOP) return TRUE;
1986 if (wndPtr != WND_OTHER_PROCESS)
1988 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1989 WIN_ReleasePtr( wndPtr );
1993 SERVER_START_REQ( get_window_info )
1995 req->handle = wine_server_user_handle( hwnd );
1996 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2004 /**********************************************************************
2007 * Helper function for GetWindowLong().
2009 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2011 LONG_PTR retvalue = 0;
2014 if (offset == GWLP_HWNDPARENT)
2016 HWND parent = GetAncestor( hwnd, GA_PARENT );
2017 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2018 return (ULONG_PTR)parent;
2021 if (!(wndPtr = WIN_GetPtr( hwnd )))
2023 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2027 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2029 if (offset == GWLP_WNDPROC)
2031 SetLastError( ERROR_ACCESS_DENIED );
2034 SERVER_START_REQ( set_window_info )
2036 req->handle = wine_server_user_handle( hwnd );
2037 req->flags = 0; /* don't set anything, just retrieve */
2038 req->extra_offset = (offset >= 0) ? offset : -1;
2039 req->extra_size = (offset >= 0) ? size : 0;
2040 if (!wine_server_call_err( req ))
2044 case GWL_STYLE: retvalue = reply->old_style; break;
2045 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2046 case GWLP_ID: retvalue = reply->old_id; break;
2047 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2048 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2050 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2051 else SetLastError( ERROR_INVALID_INDEX );
2060 /* now we have a valid wndPtr */
2064 if (offset > (int)(wndPtr->cbWndExtra - size))
2066 WARN("Invalid offset %d\n", offset );
2067 WIN_ReleasePtr( wndPtr );
2068 SetLastError( ERROR_INVALID_INDEX );
2071 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2073 /* Special case for dialog window procedure */
2074 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2075 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2076 WIN_ReleasePtr( wndPtr );
2082 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2083 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2084 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2085 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2086 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2088 /* This looks like a hack only for the edit control (see tests). This makes these controls
2089 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2090 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2092 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2093 retvalue = (ULONG_PTR)wndPtr->winproc;
2095 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2098 WARN("Unknown offset %d\n", offset );
2099 SetLastError( ERROR_INVALID_INDEX );
2102 WIN_ReleasePtr(wndPtr);
2107 /**********************************************************************
2110 * Helper function for SetWindowLong().
2112 * 0 is the failure code. However, in the case of failure SetLastError
2113 * must be set to distinguish between a 0 return value and a failure.
2115 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2119 LONG_PTR retval = 0;
2122 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2124 if (is_broadcast(hwnd))
2126 SetLastError( ERROR_INVALID_PARAMETER );
2130 if (!(wndPtr = WIN_GetPtr( hwnd )))
2132 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2135 if (wndPtr == WND_DESKTOP)
2137 /* can't change anything on the desktop window */
2138 SetLastError( ERROR_ACCESS_DENIED );
2141 if (wndPtr == WND_OTHER_PROCESS)
2143 if (offset == GWLP_WNDPROC)
2145 SetLastError( ERROR_ACCESS_DENIED );
2148 if (offset > 32767 || offset < -32767)
2150 SetLastError( ERROR_INVALID_INDEX );
2153 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2156 /* first some special cases */
2160 style.styleOld = wndPtr->dwStyle;
2161 style.styleNew = newval;
2162 WIN_ReleasePtr( wndPtr );
2163 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2164 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2165 newval = style.styleNew;
2166 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2167 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2170 style.styleOld = wndPtr->dwExStyle;
2171 style.styleNew = newval;
2172 WIN_ReleasePtr( wndPtr );
2173 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2174 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2175 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2176 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2177 /* WS_EX_WINDOWEDGE depends on some other styles */
2178 if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2179 newval |= WS_EX_WINDOWEDGE;
2180 else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2181 newval &= ~WS_EX_WINDOWEDGE;
2183 case GWLP_HWNDPARENT:
2184 if (wndPtr->parent == GetDesktopWindow())
2186 WIN_ReleasePtr( wndPtr );
2187 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2191 WIN_ReleasePtr( wndPtr );
2192 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2197 UINT old_flags = wndPtr->flags;
2198 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2199 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2200 if (proc) wndPtr->winproc = proc;
2201 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2202 else wndPtr->flags &= ~WIN_ISUNICODE;
2203 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2205 WIN_ReleasePtr( wndPtr );
2208 /* update is_unicode flag on the server side */
2212 case GWLP_HINSTANCE:
2216 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2217 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2219 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2220 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2221 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2222 WIN_ReleasePtr( wndPtr );
2227 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2229 WARN("Invalid offset %d\n", offset );
2230 WIN_ReleasePtr( wndPtr );
2231 SetLastError( ERROR_INVALID_INDEX );
2234 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2236 /* already set to the same value */
2237 WIN_ReleasePtr( wndPtr );
2243 SERVER_START_REQ( set_window_info )
2245 req->handle = wine_server_user_handle( hwnd );
2246 req->extra_offset = -1;
2250 req->flags = SET_WIN_STYLE;
2251 req->style = newval;
2254 req->flags = SET_WIN_EXSTYLE;
2255 req->ex_style = newval;
2258 req->flags = SET_WIN_ID;
2261 case GWLP_HINSTANCE:
2262 req->flags = SET_WIN_INSTANCE;
2263 req->instance = wine_server_client_ptr( (void *)newval );
2266 req->flags = SET_WIN_UNICODE;
2267 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2270 req->flags = SET_WIN_USERDATA;
2271 req->user_data = newval;
2274 req->flags = SET_WIN_EXTRA;
2275 req->extra_offset = offset;
2276 req->extra_size = size;
2277 set_win_data( &req->extra_value, newval, size );
2279 if ((ok = !wine_server_call_err( req )))
2284 wndPtr->dwStyle = newval;
2285 retval = reply->old_style;
2288 wndPtr->dwExStyle = newval;
2289 retval = reply->old_ex_style;
2292 wndPtr->wIDmenu = newval;
2293 retval = reply->old_id;
2295 case GWLP_HINSTANCE:
2296 wndPtr->hInstance = (HINSTANCE)newval;
2297 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2302 wndPtr->userdata = newval;
2303 retval = reply->old_user_data;
2306 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2307 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2313 WIN_ReleasePtr( wndPtr );
2317 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2319 style.styleOld = retval;
2320 style.styleNew = newval;
2321 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2322 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2329 /**********************************************************************
2330 * GetWindowWord (USER32.@)
2332 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2337 case GWLP_HINSTANCE:
2338 case GWLP_HWNDPARENT:
2343 WARN("Invalid offset %d\n", offset );
2344 SetLastError( ERROR_INVALID_INDEX );
2349 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2353 /**********************************************************************
2354 * GetWindowLongA (USER32.@)
2356 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2358 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2362 /**********************************************************************
2363 * GetWindowLongW (USER32.@)
2365 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2367 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2371 /**********************************************************************
2372 * SetWindowWord (USER32.@)
2374 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2379 case GWLP_HINSTANCE:
2380 case GWLP_HWNDPARENT:
2385 WARN("Invalid offset %d\n", offset );
2386 SetLastError( ERROR_INVALID_INDEX );
2391 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2395 /**********************************************************************
2396 * SetWindowLongA (USER32.@)
2398 * See SetWindowLongW.
2400 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2402 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2406 /**********************************************************************
2407 * SetWindowLongW (USER32.@) Set window attribute
2409 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2410 * value in a window's extra memory.
2412 * The _hwnd_ parameter specifies the window. is the handle to a
2413 * window that has extra memory. The _newval_ parameter contains the
2414 * new attribute or extra memory value. If positive, the _offset_
2415 * parameter is the byte-addressed location in the window's extra
2416 * memory to set. If negative, _offset_ specifies the window
2417 * attribute to set, and should be one of the following values:
2419 * GWL_EXSTYLE The window's extended window style
2421 * GWL_STYLE The window's window style.
2423 * GWLP_WNDPROC Pointer to the window's window procedure.
2425 * GWLP_HINSTANCE The window's pplication instance handle.
2427 * GWLP_ID The window's identifier.
2429 * GWLP_USERDATA The window's user-specified data.
2431 * If the window is a dialog box, the _offset_ parameter can be one of
2432 * the following values:
2434 * DWLP_DLGPROC The address of the window's dialog box procedure.
2436 * DWLP_MSGRESULT The return value of a message
2437 * that the dialog box procedure processed.
2439 * DWLP_USER Application specific information.
2443 * If successful, returns the previous value located at _offset_. Otherwise,
2448 * Extra memory for a window class is specified by a nonzero cbWndExtra
2449 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2450 * time of class creation.
2452 * Using GWL_WNDPROC to set a new window procedure effectively creates
2453 * a window subclass. Use CallWindowProc() in the new windows procedure
2454 * to pass messages to the superclass's window procedure.
2456 * The user data is reserved for use by the application which created
2459 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2460 * instead, call the EnableWindow() function to change the window's
2463 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2464 * SetParent() instead.
2467 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2468 * it sends WM_STYLECHANGING before changing the settings
2469 * and WM_STYLECHANGED afterwards.
2470 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2472 LONG WINAPI SetWindowLongW(
2473 HWND hwnd, /* [in] window to alter */
2474 INT offset, /* [in] offset, in bytes, of location to alter */
2475 LONG newval /* [in] new value of location */
2477 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2481 /*******************************************************************
2482 * GetWindowTextA (USER32.@)
2484 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2488 if (!lpString) return 0;
2490 if (WIN_IsCurrentProcess( hwnd ))
2491 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2493 /* when window belongs to other process, don't send a message */
2494 if (nMaxCount <= 0) return 0;
2495 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2496 get_server_window_text( hwnd, buffer, nMaxCount );
2497 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2498 lpString[nMaxCount-1] = 0;
2499 HeapFree( GetProcessHeap(), 0, buffer );
2500 return strlen(lpString);
2504 /*******************************************************************
2505 * InternalGetWindowText (USER32.@)
2507 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2511 if (nMaxCount <= 0) return 0;
2512 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2513 if (win == WND_DESKTOP) lpString[0] = 0;
2514 else if (win != WND_OTHER_PROCESS)
2516 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2517 else lpString[0] = 0;
2518 WIN_ReleasePtr( win );
2522 get_server_window_text( hwnd, lpString, nMaxCount );
2524 return strlenW(lpString);
2528 /*******************************************************************
2529 * GetWindowTextW (USER32.@)
2531 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2533 if (!lpString) return 0;
2535 if (WIN_IsCurrentProcess( hwnd ))
2536 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2538 /* when window belongs to other process, don't send a message */
2539 if (nMaxCount <= 0) return 0;
2540 get_server_window_text( hwnd, lpString, nMaxCount );
2541 return strlenW(lpString);
2545 /*******************************************************************
2546 * SetWindowTextA (USER32.@)
2547 * SetWindowText (USER32.@)
2549 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2551 if (is_broadcast(hwnd))
2553 SetLastError( ERROR_INVALID_PARAMETER );
2556 if (!WIN_IsCurrentProcess( hwnd ))
2557 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2558 debugstr_a(lpString), hwnd );
2559 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2563 /*******************************************************************
2564 * SetWindowTextW (USER32.@)
2566 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2568 if (is_broadcast(hwnd))
2570 SetLastError( ERROR_INVALID_PARAMETER );
2573 if (!WIN_IsCurrentProcess( hwnd ))
2574 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2575 debugstr_w(lpString), hwnd );
2576 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2580 /*******************************************************************
2581 * GetWindowTextLengthA (USER32.@)
2583 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2585 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2588 /*******************************************************************
2589 * GetWindowTextLengthW (USER32.@)
2591 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2593 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2597 /*******************************************************************
2598 * IsWindow (USER32.@)
2600 BOOL WINAPI IsWindow( HWND hwnd )
2605 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2606 if (ptr == WND_DESKTOP) return TRUE;
2608 if (ptr != WND_OTHER_PROCESS)
2610 WIN_ReleasePtr( ptr );
2614 /* check other processes */
2615 SERVER_START_REQ( get_window_info )
2617 req->handle = wine_server_user_handle( hwnd );
2618 ret = !wine_server_call_err( req );
2625 /***********************************************************************
2626 * GetWindowThreadProcessId (USER32.@)
2628 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2633 if (!(ptr = WIN_GetPtr( hwnd )))
2635 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2639 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2641 /* got a valid window */
2643 if (process) *process = GetCurrentProcessId();
2644 WIN_ReleasePtr( ptr );
2648 /* check other processes */
2649 SERVER_START_REQ( get_window_info )
2651 req->handle = wine_server_user_handle( hwnd );
2652 if (!wine_server_call_err( req ))
2654 tid = (DWORD)reply->tid;
2655 if (process) *process = (DWORD)reply->pid;
2663 /*****************************************************************
2664 * GetParent (USER32.@)
2666 HWND WINAPI GetParent( HWND hwnd )
2671 if (!(wndPtr = WIN_GetPtr( hwnd )))
2673 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2676 if (wndPtr == WND_DESKTOP) return 0;
2677 if (wndPtr == WND_OTHER_PROCESS)
2679 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2680 if (style & (WS_POPUP | WS_CHILD))
2682 SERVER_START_REQ( get_window_tree )
2684 req->handle = wine_server_user_handle( hwnd );
2685 if (!wine_server_call_err( req ))
2687 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2688 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2696 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2697 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2698 WIN_ReleasePtr( wndPtr );
2704 /*****************************************************************
2705 * GetAncestor (USER32.@)
2707 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2710 HWND *list, ret = 0;
2715 if (!(win = WIN_GetPtr( hwnd )))
2717 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2720 if (win == WND_DESKTOP) return 0;
2721 if (win != WND_OTHER_PROCESS)
2724 WIN_ReleasePtr( win );
2726 else /* need to query the server */
2728 SERVER_START_REQ( get_window_tree )
2730 req->handle = wine_server_user_handle( hwnd );
2731 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2738 if (!(list = list_window_parents( hwnd ))) return 0;
2740 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2744 while (list[count]) count++;
2745 ret = list[count - 2]; /* get the one before the desktop */
2747 HeapFree( GetProcessHeap(), 0, list );
2751 if (is_desktop_window( hwnd )) return 0;
2752 ret = WIN_GetFullHandle( hwnd );
2755 HWND parent = GetParent( ret );
2765 /*****************************************************************
2766 * SetParent (USER32.@)
2768 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2771 HWND old_parent = 0;
2776 if (is_broadcast(hwnd) || is_broadcast(parent))
2778 SetLastError(ERROR_INVALID_PARAMETER);
2782 if (!parent) parent = GetDesktopWindow();
2783 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2784 else parent = WIN_GetFullHandle( parent );
2786 if (!IsWindow( parent ))
2788 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2792 /* Some applications try to set a child as a parent */
2793 if (IsChild(hwnd, parent))
2795 SetLastError( ERROR_INVALID_PARAMETER );
2799 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2800 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2802 if (full_handle == parent)
2804 SetLastError( ERROR_INVALID_PARAMETER );
2808 /* Windows hides the window first, then shows it again
2809 * including the WM_SHOWWINDOW messages and all */
2810 was_visible = ShowWindow( hwnd, SW_HIDE );
2812 wndPtr = WIN_GetPtr( hwnd );
2813 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2815 SERVER_START_REQ( set_parent )
2817 req->handle = wine_server_user_handle( hwnd );
2818 req->parent = wine_server_user_handle( parent );
2819 if ((ret = !wine_server_call( req )))
2821 old_parent = wine_server_ptr_handle( reply->old_parent );
2822 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2827 WIN_ReleasePtr( wndPtr );
2830 USER_Driver->pSetParent( full_handle, parent, old_parent );
2832 /* SetParent additionally needs to make hwnd the topmost window
2833 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2834 WM_WINDOWPOSCHANGED notification messages.
2836 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2837 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2838 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2839 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2845 /*******************************************************************
2846 * IsChild (USER32.@)
2848 BOOL WINAPI IsChild( HWND parent, HWND child )
2850 HWND *list = list_window_parents( child );
2854 if (!list) return FALSE;
2855 parent = WIN_GetFullHandle( parent );
2856 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2857 ret = list[i] && list[i+1];
2858 HeapFree( GetProcessHeap(), 0, list );
2863 /***********************************************************************
2864 * IsWindowVisible (USER32.@)
2866 BOOL WINAPI IsWindowVisible( HWND hwnd )
2872 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2873 if (!(list = list_window_parents( hwnd ))) return TRUE;
2876 for (i = 0; list[i+1]; i++)
2877 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2878 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2880 HeapFree( GetProcessHeap(), 0, list );
2885 /***********************************************************************
2886 * WIN_IsWindowDrawable
2888 * hwnd is drawable when it is visible, all parents are not
2889 * minimized, and it is itself not minimized unless we are
2890 * trying to draw its default class icon.
2892 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2897 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2899 if (!(style & WS_VISIBLE)) return FALSE;
2900 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2902 if (!(list = list_window_parents( hwnd ))) return TRUE;
2905 for (i = 0; list[i+1]; i++)
2906 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2908 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2910 HeapFree( GetProcessHeap(), 0, list );
2915 /*******************************************************************
2916 * GetTopWindow (USER32.@)
2918 HWND WINAPI GetTopWindow( HWND hwnd )
2920 if (!hwnd) hwnd = GetDesktopWindow();
2921 return GetWindow( hwnd, GW_CHILD );
2925 /*******************************************************************
2926 * GetWindow (USER32.@)
2928 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2932 if (rel == GW_OWNER) /* this one may be available locally */
2934 WND *wndPtr = WIN_GetPtr( hwnd );
2937 SetLastError( ERROR_INVALID_HANDLE );
2940 if (wndPtr == WND_DESKTOP) return 0;
2941 if (wndPtr != WND_OTHER_PROCESS)
2943 retval = wndPtr->owner;
2944 WIN_ReleasePtr( wndPtr );
2947 /* else fall through to server call */
2950 SERVER_START_REQ( get_window_tree )
2952 req->handle = wine_server_user_handle( hwnd );
2953 if (!wine_server_call_err( req ))
2958 retval = wine_server_ptr_handle( reply->first_sibling );
2961 retval = wine_server_ptr_handle( reply->last_sibling );
2964 retval = wine_server_ptr_handle( reply->next_sibling );
2967 retval = wine_server_ptr_handle( reply->prev_sibling );
2970 retval = wine_server_ptr_handle( reply->owner );
2973 retval = wine_server_ptr_handle( reply->first_child );
2983 /*******************************************************************
2984 * ShowOwnedPopups (USER32.@)
2986 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2990 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2992 if (!win_array) return TRUE;
2994 while (win_array[count]) count++;
2995 while (--count >= 0)
2997 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2998 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2999 if (pWnd == WND_OTHER_PROCESS) continue;
3002 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3004 WIN_ReleasePtr( pWnd );
3005 /* In Windows, ShowOwnedPopups(TRUE) generates
3006 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3007 * regardless of the state of the owner
3009 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3015 if (pWnd->dwStyle & WS_VISIBLE)
3017 WIN_ReleasePtr( pWnd );
3018 /* In Windows, ShowOwnedPopups(FALSE) generates
3019 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3020 * regardless of the state of the owner
3022 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3026 WIN_ReleasePtr( pWnd );
3028 HeapFree( GetProcessHeap(), 0, win_array );
3033 /*******************************************************************
3034 * GetLastActivePopup (USER32.@)
3036 HWND WINAPI GetLastActivePopup( HWND hwnd )
3040 SERVER_START_REQ( get_window_info )
3042 req->handle = wine_server_user_handle( hwnd );
3043 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3050 /*******************************************************************
3053 * Build an array of the children of a given window. The array must be
3054 * freed with HeapFree. Returns NULL when no windows are found.
3056 HWND *WIN_ListChildren( HWND hwnd )
3060 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3063 return list_window_children( 0, hwnd, NULL, 0 );
3067 /*******************************************************************
3068 * EnumWindows (USER32.@)
3070 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3076 USER_CheckNotLock();
3078 /* We have to build a list of all windows first, to avoid */
3079 /* unpleasant side-effects, for instance if the callback */
3080 /* function changes the Z-order of the windows. */
3082 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3084 /* Now call the callback function for every window */
3086 for (i = 0; list[i]; i++)
3088 /* Make sure that the window still exists */
3089 if (!IsWindow( list[i] )) continue;
3090 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3092 HeapFree( GetProcessHeap(), 0, list );
3097 /**********************************************************************
3098 * EnumThreadWindows (USER32.@)
3100 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3106 USER_CheckNotLock();
3108 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3110 /* Now call the callback function for every window */
3112 for (i = 0; list[i]; i++)
3113 if (!(ret = func( list[i], lParam ))) break;
3114 HeapFree( GetProcessHeap(), 0, list );
3119 /***********************************************************************
3120 * EnumDesktopWindows (USER32.@)
3122 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3127 USER_CheckNotLock();
3129 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3131 for (i = 0; list[i]; i++)
3132 if (!func( list[i], lparam )) break;
3133 HeapFree( GetProcessHeap(), 0, list );
3138 /**********************************************************************
3139 * WIN_EnumChildWindows
3141 * Helper function for EnumChildWindows().
3143 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3148 for ( ; *list; list++)
3150 /* Make sure that the window still exists */
3151 if (!IsWindow( *list )) continue;
3152 /* Build children list first */
3153 childList = WIN_ListChildren( *list );
3155 ret = func( *list, lParam );
3159 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3160 HeapFree( GetProcessHeap(), 0, childList );
3162 if (!ret) return FALSE;
3168 /**********************************************************************
3169 * EnumChildWindows (USER32.@)
3171 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3176 USER_CheckNotLock();
3178 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3179 ret = WIN_EnumChildWindows( list, func, lParam );
3180 HeapFree( GetProcessHeap(), 0, list );
3185 /*******************************************************************
3186 * AnyPopup (USER32.@)
3188 BOOL WINAPI AnyPopup(void)
3192 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3194 if (!list) return FALSE;
3195 for (i = 0; list[i]; i++)
3197 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3199 retvalue = (list[i] != 0);
3200 HeapFree( GetProcessHeap(), 0, list );
3205 /*******************************************************************
3206 * FlashWindow (USER32.@)
3208 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3212 TRACE("%p\n", hWnd);
3214 if (IsIconic( hWnd ))
3216 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3218 wndPtr = WIN_GetPtr(hWnd);
3219 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3220 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3222 wndPtr->flags |= WIN_NCACTIVATED;
3226 wndPtr->flags &= ~WIN_NCACTIVATED;
3228 WIN_ReleasePtr( wndPtr );
3235 wndPtr = WIN_GetPtr(hWnd);
3236 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3237 hWnd = wndPtr->obj.handle; /* make it a full handle */
3239 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3240 else wparam = (hWnd == GetForegroundWindow());
3242 WIN_ReleasePtr( wndPtr );
3243 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3248 /*******************************************************************
3249 * FlashWindowEx (USER32.@)
3251 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3253 FIXME("%p\n", pfwi);
3257 /*******************************************************************
3258 * GetWindowContextHelpId (USER32.@)
3260 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3263 WND *wnd = WIN_GetPtr( hwnd );
3264 if (!wnd || wnd == WND_DESKTOP) return 0;
3265 if (wnd == WND_OTHER_PROCESS)
3267 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3270 retval = wnd->helpContext;
3271 WIN_ReleasePtr( wnd );
3276 /*******************************************************************
3277 * SetWindowContextHelpId (USER32.@)
3279 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3281 WND *wnd = WIN_GetPtr( hwnd );
3282 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3283 if (wnd == WND_OTHER_PROCESS)
3285 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3288 wnd->helpContext = id;
3289 WIN_ReleasePtr( wnd );
3294 /*******************************************************************
3295 * DragDetect (USER32.@)
3297 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3301 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3302 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3304 rect.left = pt.x - wDragWidth;
3305 rect.right = pt.x + wDragWidth;
3307 rect.top = pt.y - wDragHeight;
3308 rect.bottom = pt.y + wDragHeight;
3314 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3316 if( msg.message == WM_LBUTTONUP )
3321 if( msg.message == WM_MOUSEMOVE )
3324 tmp.x = (short)LOWORD(msg.lParam);
3325 tmp.y = (short)HIWORD(msg.lParam);
3326 if( !PtInRect( &rect, tmp ))
3338 /******************************************************************************
3339 * GetWindowModuleFileNameA (USER32.@)
3341 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3346 TRACE( "%p, %p, %u\n", hwnd, module, size );
3348 win = WIN_GetPtr( hwnd );
3349 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3351 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3354 hinst = win->hInstance;
3355 WIN_ReleasePtr( win );
3357 return GetModuleFileNameA( hinst, module, size );
3360 /******************************************************************************
3361 * GetWindowModuleFileNameW (USER32.@)
3363 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3368 TRACE( "%p, %p, %u\n", hwnd, module, size );
3370 win = WIN_GetPtr( hwnd );
3371 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3373 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3376 hinst = win->hInstance;
3377 WIN_ReleasePtr( win );
3379 return GetModuleFileNameW( hinst, module, size );
3382 /******************************************************************************
3383 * GetWindowInfo (USER32.@)
3385 * Note: tests show that Windows doesn't check cbSize of the structure.
3387 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3389 if (!pwi) return FALSE;
3390 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3392 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3393 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3394 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3396 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3397 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3399 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3400 pwi->wCreatorVersion = 0x0400;
3405 /******************************************************************************
3406 * SwitchDesktop (USER32.@)
3408 * NOTES: Sets the current input or interactive desktop.
3410 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3412 FIXME("(hwnd %p) stub!\n", hDesktop);
3416 /*****************************************************************************
3417 * SetLayeredWindowAttributes (USER32.@)
3419 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3423 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3425 SERVER_START_REQ( set_window_layered_info )
3427 req->handle = wine_server_user_handle( hwnd );
3428 req->color_key = key;
3431 ret = !wine_server_call_err( req );
3435 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3441 /*****************************************************************************
3442 * GetLayeredWindowAttributes (USER32.@)
3444 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3448 SERVER_START_REQ( get_window_layered_info )
3450 req->handle = wine_server_user_handle( hwnd );
3451 if ((ret = !wine_server_call_err( req )))
3453 if (key) *key = reply->color_key;
3454 if (alpha) *alpha = reply->alpha;
3455 if (flags) *flags = reply->flags;
3464 /*****************************************************************************
3465 * UpdateLayeredWindowIndirect (USER32.@)
3467 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3471 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3472 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3474 SetLastError( ERROR_INVALID_PARAMETER );
3478 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3480 int x = 0, y = 0, cx = 0, cy = 0;
3481 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3485 x = info->pptDst->x;
3486 y = info->pptDst->y;
3487 flags &= ~SWP_NOMOVE;
3491 cx = info->psize->cx;
3492 cy = info->psize->cy;
3493 flags &= ~SWP_NOSIZE;
3495 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3496 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3501 HDC hdc = GetWindowDC( hwnd );
3508 GetWindowRect( hwnd, &rect );
3509 OffsetRect( &rect, -rect.left, -rect.top);
3512 x = info->pptSrc->x;
3513 y = info->pptSrc->y;
3516 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3518 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3519 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3520 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3522 ReleaseDC( hwnd, hdc );
3526 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3527 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3528 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3529 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3534 /*****************************************************************************
3535 * UpdateLayeredWindow (USER32.@)
3537 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3538 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3541 UPDATELAYEREDWINDOWINFO info;
3543 info.cbSize = sizeof(info);
3544 info.hdcDst = hdcDst;
3545 info.pptDst = pptDst;
3547 info.hdcSrc = hdcSrc;
3548 info.pptSrc = pptSrc;
3550 info.pblend = pblend;
3551 info.dwFlags = dwFlags;
3552 info.prcDirty = NULL;
3553 return UpdateLayeredWindowIndirect( hwnd, &info );
3557 /******************************************************************************
3558 * GetProcessDefaultLayout [USER32.@]
3560 * Gets the default layout for parentless windows.
3562 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3566 SetLastError( ERROR_NOACCESS );
3569 if (process_layout == ~0u)
3571 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3572 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3573 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3574 '\\','%','0','4','x','%','0','4','x',
3575 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3576 WCHAR *str, buffer[MAX_PATH];
3577 DWORD i, len, version_layout = 0;
3578 DWORD user_lang = GetUserDefaultLangID();
3582 GetModuleFileNameW( 0, buffer, MAX_PATH );
3583 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3584 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3585 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3586 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3588 len /= sizeof(DWORD);
3589 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3590 if (i == len) /* try neutral language */
3591 for (i = 0; i < len; i++)
3592 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3593 if (i == len) i = 0; /* default to the first one */
3595 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3596 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3597 TRACE( "found description %s\n", debugstr_w( str ));
3598 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3601 HeapFree( GetProcessHeap(), 0, data );
3602 process_layout = version_layout;
3604 *layout = process_layout;
3609 /******************************************************************************
3610 * SetProcessDefaultLayout [USER32.@]
3612 * Sets the default layout for parentless windows.
3614 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3616 process_layout = layout;
3621 /* 64bit versions */
3623 #ifdef GetWindowLongPtrW
3624 #undef GetWindowLongPtrW
3627 #ifdef GetWindowLongPtrA
3628 #undef GetWindowLongPtrA
3631 #ifdef SetWindowLongPtrW
3632 #undef SetWindowLongPtrW
3635 #ifdef SetWindowLongPtrA
3636 #undef SetWindowLongPtrA
3639 /*****************************************************************************
3640 * GetWindowLongPtrW (USER32.@)
3642 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3644 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3647 /*****************************************************************************
3648 * GetWindowLongPtrA (USER32.@)
3650 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3652 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3655 /*****************************************************************************
3656 * SetWindowLongPtrW (USER32.@)
3658 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3660 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3663 /*****************************************************************************
3664 * SetWindowLongPtrA (USER32.@)
3666 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3668 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );