user32: Only skip redraws on MDI child unmaximize if the new child is maximized.
[wine/multimedia.git] / dlls / user32 / win.c
blob6800abd439d28f1d7905152d2a32aa916ec4a8a2
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "controls.h"
35 #include "winerror.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(win);
40 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
41 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
43 /**********************************************************************/
45 /* helper for Get/SetWindowLong */
46 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
48 if (size == sizeof(WORD))
50 WORD ret;
51 memcpy( &ret, ptr, sizeof(ret) );
52 return ret;
54 else if (size == sizeof(DWORD))
56 DWORD ret;
57 memcpy( &ret, ptr, sizeof(ret) );
58 return ret;
60 else
62 LONG_PTR ret;
63 memcpy( &ret, ptr, sizeof(ret) );
64 return ret;
68 /* helper for Get/SetWindowLong */
69 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
71 if (size == sizeof(WORD))
73 WORD newval = val;
74 memcpy( ptr, &newval, sizeof(newval) );
76 else if (size == sizeof(DWORD))
78 DWORD newval = val;
79 memcpy( ptr, &newval, sizeof(newval) );
81 else
83 memcpy( ptr, &val, sizeof(val) );
88 static void *user_handles[NB_USER_HANDLES];
90 /***********************************************************************
91 * alloc_user_handle
93 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
95 HANDLE handle = 0;
97 SERVER_START_REQ( alloc_user_handle )
99 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
101 SERVER_END_REQ;
103 if (handle)
105 UINT index = USER_HANDLE_TO_INDEX( handle );
107 assert( index < NB_USER_HANDLES );
108 ptr->handle = handle;
109 ptr->type = type;
110 user_handles[index] = ptr;
112 return handle;
116 /***********************************************************************
117 * get_user_handle_ptr
119 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
121 struct user_object *ptr;
122 WORD index = USER_HANDLE_TO_INDEX( handle );
124 if (index >= NB_USER_HANDLES) return NULL;
126 USER_Lock();
127 if ((ptr = user_handles[index]))
129 if (ptr->type == type &&
130 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
131 !HIWORD(handle) || HIWORD(handle) == 0xffff))
132 return ptr;
133 ptr = NULL;
135 else ptr = OBJ_OTHER_PROCESS;
136 USER_Unlock();
137 return ptr;
141 /***********************************************************************
142 * release_user_handle_ptr
144 void release_user_handle_ptr( void *ptr )
146 assert( ptr && ptr != OBJ_OTHER_PROCESS );
147 USER_Unlock();
151 /***********************************************************************
152 * free_user_handle
154 void *free_user_handle( HANDLE handle, enum user_obj_type type )
156 struct user_object *ptr;
157 WORD index = USER_HANDLE_TO_INDEX( handle );
159 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
161 SERVER_START_REQ( free_user_handle )
163 req->handle = wine_server_user_handle( handle );
164 if (!wine_server_call( req )) user_handles[index] = NULL;
165 else ptr = NULL;
167 SERVER_END_REQ;
168 release_user_handle_ptr( ptr );
170 return ptr;
174 /***********************************************************************
175 * create_window_handle
177 * Create a window handle with the server.
179 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
180 HINSTANCE instance, BOOL unicode )
182 WORD index;
183 WND *win;
184 HWND handle = 0, full_parent = 0, full_owner = 0;
185 struct tagCLASS *class = NULL;
186 int extra_bytes = 0;
188 SERVER_START_REQ( create_window )
190 req->parent = wine_server_user_handle( parent );
191 req->owner = wine_server_user_handle( owner );
192 req->instance = wine_server_client_ptr( instance );
193 if (!(req->atom = get_int_atom_value( name )) && name)
194 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
195 if (!wine_server_call_err( req ))
197 handle = wine_server_ptr_handle( reply->handle );
198 full_parent = wine_server_ptr_handle( reply->parent );
199 full_owner = wine_server_ptr_handle( reply->owner );
200 extra_bytes = reply->extra;
201 class = wine_server_get_ptr( reply->class_ptr );
204 SERVER_END_REQ;
206 if (!handle)
208 WARN( "error %d creating window\n", GetLastError() );
209 return NULL;
212 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
213 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
215 SERVER_START_REQ( destroy_window )
217 req->handle = wine_server_user_handle( handle );
218 wine_server_call( req );
220 SERVER_END_REQ;
221 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
222 return NULL;
225 if (!parent) /* if parent is 0 we don't have a desktop window yet */
227 struct user_thread_info *thread_info = get_user_thread_info();
229 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
231 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
232 else assert( full_parent == thread_info->top_window );
233 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
234 ERR( "failed to create desktop window\n" );
236 else /* HWND_MESSAGE parent */
238 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
242 USER_Lock();
244 index = USER_HANDLE_TO_INDEX(handle);
245 assert( index < NB_USER_HANDLES );
246 user_handles[index] = win;
247 win->obj.handle = handle;
248 win->obj.type = USER_WINDOW;
249 win->parent = full_parent;
250 win->owner = full_owner;
251 win->class = class;
252 win->winproc = get_class_winproc( class );
253 win->cbWndExtra = extra_bytes;
254 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
255 return win;
259 /***********************************************************************
260 * free_window_handle
262 * Free a window handle.
264 static void free_window_handle( HWND hwnd )
266 struct user_object *ptr;
267 WORD index = USER_HANDLE_TO_INDEX(hwnd);
269 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
271 SERVER_START_REQ( destroy_window )
273 req->handle = wine_server_user_handle( hwnd );
274 if (!wine_server_call_err( req )) user_handles[index] = NULL;
275 else ptr = NULL;
277 SERVER_END_REQ;
278 release_user_handle_ptr( ptr );
279 HeapFree( GetProcessHeap(), 0, ptr );
284 /*******************************************************************
285 * list_window_children
287 * Build an array of the children of a given window. The array must be
288 * freed with HeapFree. Returns NULL when no windows are found.
290 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
292 HWND *list;
293 int i, size = 128;
294 ATOM atom = get_int_atom_value( class );
296 /* empty class is not the same as NULL class */
297 if (!atom && class && !class[0]) return NULL;
299 for (;;)
301 int count = 0;
303 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
305 SERVER_START_REQ( get_window_children )
307 req->desktop = wine_server_obj_handle( desktop );
308 req->parent = wine_server_user_handle( hwnd );
309 req->tid = tid;
310 req->atom = atom;
311 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
312 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
313 if (!wine_server_call( req )) count = reply->count;
315 SERVER_END_REQ;
316 if (count && count < size)
318 /* start from the end since HWND is potentially larger than user_handle_t */
319 for (i = count - 1; i >= 0; i--)
320 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
321 list[count] = 0;
322 return list;
324 HeapFree( GetProcessHeap(), 0, list );
325 if (!count) break;
326 size = count + 1; /* restart with a large enough buffer */
328 return NULL;
332 /*******************************************************************
333 * list_window_parents
335 * Build an array of all parents of a given window, starting with
336 * the immediate parent. The array must be freed with HeapFree.
338 static HWND *list_window_parents( HWND hwnd )
340 WND *win;
341 HWND current, *list;
342 int i, pos = 0, size = 16, count = 0;
344 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
346 current = hwnd;
347 for (;;)
349 if (!(win = WIN_GetPtr( current ))) goto empty;
350 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
351 if (win == WND_DESKTOP)
353 if (!pos) goto empty;
354 list[pos] = 0;
355 return list;
357 list[pos] = current = win->parent;
358 WIN_ReleasePtr( win );
359 if (!current) return list;
360 if (++pos == size - 1)
362 /* need to grow the list */
363 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
364 if (!new_list) goto empty;
365 list = new_list;
366 size += 16;
370 /* at least one parent belongs to another process, have to query the server */
372 for (;;)
374 count = 0;
375 SERVER_START_REQ( get_window_parents )
377 req->handle = wine_server_user_handle( hwnd );
378 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
379 if (!wine_server_call( req )) count = reply->count;
381 SERVER_END_REQ;
382 if (!count) goto empty;
383 if (size > count)
385 /* start from the end since HWND is potentially larger than user_handle_t */
386 for (i = count - 1; i >= 0; i--)
387 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
388 list[count] = 0;
389 return list;
391 HeapFree( GetProcessHeap(), 0, list );
392 size = count + 1;
393 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
396 empty:
397 HeapFree( GetProcessHeap(), 0, list );
398 return NULL;
402 /*******************************************************************
403 * send_parent_notify
405 static void send_parent_notify( HWND hwnd, UINT msg )
407 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
408 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
410 HWND parent = GetParent(hwnd);
411 if (parent && parent != GetDesktopWindow())
412 SendMessageW( parent, WM_PARENTNOTIFY,
413 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
418 /*******************************************************************
419 * get_server_window_text
421 * Retrieve the window text from the server.
423 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
425 size_t len = 0;
427 SERVER_START_REQ( get_window_text )
429 req->handle = wine_server_user_handle( hwnd );
430 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
431 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
433 SERVER_END_REQ;
434 text[len / sizeof(WCHAR)] = 0;
438 /*******************************************************************
439 * get_hwnd_message_parent
441 * Return the parent for HWND_MESSAGE windows.
443 HWND get_hwnd_message_parent(void)
445 struct user_thread_info *thread_info = get_user_thread_info();
447 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
448 return thread_info->msg_window;
452 /*******************************************************************
453 * is_desktop_window
455 * Check if window is the desktop or the HWND_MESSAGE top parent.
457 BOOL is_desktop_window( HWND hwnd )
459 struct user_thread_info *thread_info = get_user_thread_info();
461 if (!hwnd) return FALSE;
462 if (hwnd == thread_info->top_window) return TRUE;
463 if (hwnd == thread_info->msg_window) return TRUE;
465 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
467 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
468 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
470 return FALSE;
474 /***********************************************************************
475 * WIN_GetPtr
477 * Return a pointer to the WND structure if local to the process,
478 * or WND_OTHER_PROCESS if handle may be valid in other process.
479 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
481 WND *WIN_GetPtr( HWND hwnd )
483 WND *ptr;
485 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
487 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
489 return ptr;
493 /***********************************************************************
494 * WIN_IsCurrentProcess
496 * Check whether a given window belongs to the current process (and return the full handle).
498 HWND WIN_IsCurrentProcess( HWND hwnd )
500 WND *ptr;
501 HWND ret;
503 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
504 ret = ptr->obj.handle;
505 WIN_ReleasePtr( ptr );
506 return ret;
510 /***********************************************************************
511 * WIN_IsCurrentThread
513 * Check whether a given window belongs to the current thread (and return the full handle).
515 HWND WIN_IsCurrentThread( HWND hwnd )
517 WND *ptr;
518 HWND ret = 0;
520 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
521 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
522 WIN_ReleasePtr( ptr );
523 return ret;
527 /***********************************************************************
528 * WIN_GetFullHandle
530 * Convert a possibly truncated window handle to a full 32-bit handle.
532 HWND WIN_GetFullHandle( HWND hwnd )
534 WND *ptr;
536 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
537 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
538 /* do sign extension for -2 and -3 */
539 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
541 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
543 if (ptr == WND_DESKTOP)
545 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
546 else return get_hwnd_message_parent();
549 if (ptr != WND_OTHER_PROCESS)
551 hwnd = ptr->obj.handle;
552 WIN_ReleasePtr( ptr );
554 else /* may belong to another process */
556 SERVER_START_REQ( get_window_info )
558 req->handle = wine_server_user_handle( hwnd );
559 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
561 SERVER_END_REQ;
563 return hwnd;
567 /***********************************************************************
568 * WIN_SetOwner
570 * Change the owner of a window.
572 HWND WIN_SetOwner( HWND hwnd, HWND owner )
574 WND *win = WIN_GetPtr( hwnd );
575 HWND ret = 0;
577 if (!win || win == WND_DESKTOP) return 0;
578 if (win == WND_OTHER_PROCESS)
580 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
581 return 0;
583 SERVER_START_REQ( set_window_owner )
585 req->handle = wine_server_user_handle( hwnd );
586 req->owner = wine_server_user_handle( owner );
587 if (!wine_server_call( req ))
589 win->owner = wine_server_ptr_handle( reply->full_owner );
590 ret = wine_server_ptr_handle( reply->prev_owner );
593 SERVER_END_REQ;
594 WIN_ReleasePtr( win );
595 return ret;
599 /***********************************************************************
600 * WIN_SetStyle
602 * Change the style of a window.
604 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
606 BOOL ok;
607 STYLESTRUCT style;
608 WND *win = WIN_GetPtr( hwnd );
610 if (!win || win == WND_DESKTOP) return 0;
611 if (win == WND_OTHER_PROCESS)
613 if (IsWindow(hwnd))
614 ERR( "cannot set style %x/%x on other process window %p\n",
615 set_bits, clear_bits, hwnd );
616 return 0;
618 style.styleOld = win->dwStyle;
619 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
620 if (style.styleNew == style.styleOld)
622 WIN_ReleasePtr( win );
623 return style.styleNew;
625 SERVER_START_REQ( set_window_info )
627 req->handle = wine_server_user_handle( hwnd );
628 req->flags = SET_WIN_STYLE;
629 req->style = style.styleNew;
630 req->extra_offset = -1;
631 if ((ok = !wine_server_call( req )))
633 style.styleOld = reply->old_style;
634 win->dwStyle = style.styleNew;
637 SERVER_END_REQ;
638 WIN_ReleasePtr( win );
639 if (ok)
641 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
642 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
644 return style.styleOld;
648 /***********************************************************************
649 * WIN_GetRectangles
651 * Get the window and client rectangles.
653 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
655 WND *win = WIN_GetPtr( hwnd );
656 BOOL ret = TRUE;
658 if (!win)
660 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
661 return FALSE;
663 if (win == WND_DESKTOP)
665 RECT rect;
666 rect.left = rect.top = 0;
667 if (hwnd == get_hwnd_message_parent())
669 rect.right = 100;
670 rect.bottom = 100;
672 else
674 rect.right = GetSystemMetrics(SM_CXSCREEN);
675 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
677 if (rectWindow) *rectWindow = rect;
678 if (rectClient) *rectClient = rect;
680 else if (win == WND_OTHER_PROCESS)
682 SERVER_START_REQ( get_window_rectangles )
684 req->handle = wine_server_user_handle( hwnd );
685 if ((ret = !wine_server_call_err( req )))
687 if (rectWindow)
689 rectWindow->left = reply->window.left;
690 rectWindow->top = reply->window.top;
691 rectWindow->right = reply->window.right;
692 rectWindow->bottom = reply->window.bottom;
694 if (rectClient)
696 rectClient->left = reply->client.left;
697 rectClient->top = reply->client.top;
698 rectClient->right = reply->client.right;
699 rectClient->bottom = reply->client.bottom;
703 SERVER_END_REQ;
705 else
707 if (rectWindow) *rectWindow = win->rectWindow;
708 if (rectClient) *rectClient = win->rectClient;
709 WIN_ReleasePtr( win );
711 return ret;
715 /***********************************************************************
716 * WIN_DestroyWindow
718 * Destroy storage associated to a window. "Internals" p.358
720 LRESULT WIN_DestroyWindow( HWND hwnd )
722 WND *wndPtr;
723 HWND *list;
724 HMENU menu = 0, sys_menu;
725 HWND icon_title;
727 TRACE("%p\n", hwnd );
729 /* free child windows */
730 if ((list = WIN_ListChildren( hwnd )))
732 int i;
733 for (i = 0; list[i]; i++)
735 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
736 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
738 HeapFree( GetProcessHeap(), 0, list );
741 /* Unlink now so we won't bother with the children later on */
742 SERVER_START_REQ( set_parent )
744 req->handle = wine_server_user_handle( hwnd );
745 req->parent = 0;
746 wine_server_call( req );
748 SERVER_END_REQ;
751 * Send the WM_NCDESTROY to the window being destroyed.
753 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
755 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
757 /* free resources associated with the window */
759 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
760 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
761 menu = (HMENU)wndPtr->wIDmenu;
762 sys_menu = wndPtr->hSysMenu;
763 free_dce( wndPtr->dce, hwnd );
764 wndPtr->dce = NULL;
765 icon_title = wndPtr->icon_title;
766 HeapFree( GetProcessHeap(), 0, wndPtr->text );
767 wndPtr->text = NULL;
768 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
769 wndPtr->pScroll = NULL;
770 WIN_ReleasePtr( wndPtr );
772 if (icon_title) DestroyWindow( icon_title );
773 if (menu) DestroyMenu( menu );
774 if (sys_menu) DestroyMenu( sys_menu );
776 USER_Driver->pDestroyWindow( hwnd );
778 free_window_handle( hwnd );
779 return 0;
783 /***********************************************************************
784 * destroy_thread_window
786 * Destroy a window upon exit of its thread.
788 static void destroy_thread_window( HWND hwnd )
790 WND *wndPtr;
791 HWND *list;
792 HMENU menu = 0, sys_menu = 0;
793 WORD index;
795 /* free child windows */
797 if ((list = WIN_ListChildren( hwnd )))
799 int i;
800 for (i = 0; list[i]; i++)
802 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
803 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
805 HeapFree( GetProcessHeap(), 0, list );
808 /* destroy the client-side storage */
810 index = USER_HANDLE_TO_INDEX(hwnd);
811 if (index >= NB_USER_HANDLES) return;
812 USER_Lock();
813 if ((wndPtr = user_handles[index]))
815 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
816 sys_menu = wndPtr->hSysMenu;
817 free_dce( wndPtr->dce, hwnd );
818 user_handles[index] = NULL;
820 USER_Unlock();
822 HeapFree( GetProcessHeap(), 0, wndPtr );
823 if (menu) DestroyMenu( menu );
824 if (sys_menu) DestroyMenu( sys_menu );
828 /***********************************************************************
829 * destroy_thread_child_windows
831 * Destroy child windows upon exit of its thread.
833 static void destroy_thread_child_windows( HWND hwnd )
835 HWND *list;
836 int i;
838 if (WIN_IsCurrentThread( hwnd ))
840 destroy_thread_window( hwnd );
842 else if ((list = WIN_ListChildren( hwnd )))
844 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
845 HeapFree( GetProcessHeap(), 0, list );
850 /***********************************************************************
851 * WIN_DestroyThreadWindows
853 * Destroy all children of 'wnd' owned by the current thread.
855 void WIN_DestroyThreadWindows( HWND hwnd )
857 HWND *list;
858 int i;
860 if (!(list = WIN_ListChildren( hwnd ))) return;
862 /* reset owners of top-level windows */
863 for (i = 0; list[i]; i++)
865 if (!WIN_IsCurrentThread( list[i] ))
867 HWND owner = GetWindow( list[i], GW_OWNER );
868 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
872 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
873 HeapFree( GetProcessHeap(), 0, list );
877 /***********************************************************************
878 * WIN_FixCoordinates
880 * Fix the coordinates - Helper for WIN_CreateWindowEx.
881 * returns default show mode in sw.
883 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
885 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
886 POINT pos[2];
888 if (cs->dwExStyle & WS_EX_MDICHILD)
890 UINT id = 0;
892 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
893 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
895 TRACE("MDI child id %04x\n", id);
898 if (cs->style & (WS_CHILD | WS_POPUP))
900 if (cs->dwExStyle & WS_EX_MDICHILD)
902 if (IS_DEFAULT(cs->x))
904 cs->x = pos[0].x;
905 cs->y = pos[0].y;
907 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
908 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
910 else
912 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
913 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
916 else /* overlapped window */
918 HMONITOR monitor;
919 MONITORINFO mon_info;
920 STARTUPINFOW info;
922 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
924 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
925 mon_info.cbSize = sizeof(mon_info);
926 GetMonitorInfoW( monitor, &mon_info );
927 GetStartupInfoW( &info );
929 if (IS_DEFAULT(cs->x))
931 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
932 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
933 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
936 if (IS_DEFAULT(cs->cx))
938 if (info.dwFlags & STARTF_USESIZE)
940 cs->cx = info.dwXSize;
941 cs->cy = info.dwYSize;
943 else
945 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
946 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
949 /* neither x nor cx are default. Check the y values .
950 * In the trace we see Outlook and Outlook Express using
951 * cy set to CW_USEDEFAULT when opening the address book.
953 else if (IS_DEFAULT(cs->cy))
955 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
956 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
959 #undef IS_DEFAULT
962 /***********************************************************************
963 * dump_window_styles
965 static void dump_window_styles( DWORD style, DWORD exstyle )
967 TRACE( "style:" );
968 if(style & WS_POPUP) TRACE(" WS_POPUP");
969 if(style & WS_CHILD) TRACE(" WS_CHILD");
970 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
971 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
972 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
973 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
974 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
975 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
976 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
977 else
979 if(style & WS_BORDER) TRACE(" WS_BORDER");
980 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
982 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
983 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
984 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
985 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
986 if (style & WS_CHILD)
988 if(style & WS_GROUP) TRACE(" WS_GROUP");
989 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
991 else
993 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
994 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
997 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
998 #define DUMPED_STYLES \
999 (WS_POPUP | \
1000 WS_CHILD | \
1001 WS_MINIMIZE | \
1002 WS_VISIBLE | \
1003 WS_DISABLED | \
1004 WS_CLIPSIBLINGS | \
1005 WS_CLIPCHILDREN | \
1006 WS_MAXIMIZE | \
1007 WS_BORDER | \
1008 WS_DLGFRAME | \
1009 WS_VSCROLL | \
1010 WS_HSCROLL | \
1011 WS_SYSMENU | \
1012 WS_THICKFRAME | \
1013 WS_GROUP | \
1014 WS_TABSTOP | \
1015 WS_MINIMIZEBOX | \
1016 WS_MAXIMIZEBOX)
1018 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1019 TRACE("\n");
1020 #undef DUMPED_STYLES
1022 TRACE( "exstyle:" );
1023 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1024 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1025 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1026 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1027 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1028 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1029 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1030 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1031 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1032 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1033 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1034 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1035 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1036 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1037 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1038 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1039 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1040 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1042 #define DUMPED_EX_STYLES \
1043 (WS_EX_DLGMODALFRAME | \
1044 WS_EX_DRAGDETECT | \
1045 WS_EX_NOPARENTNOTIFY | \
1046 WS_EX_TOPMOST | \
1047 WS_EX_ACCEPTFILES | \
1048 WS_EX_TRANSPARENT | \
1049 WS_EX_MDICHILD | \
1050 WS_EX_TOOLWINDOW | \
1051 WS_EX_WINDOWEDGE | \
1052 WS_EX_CLIENTEDGE | \
1053 WS_EX_CONTEXTHELP | \
1054 WS_EX_RIGHT | \
1055 WS_EX_RTLREADING | \
1056 WS_EX_LEFTSCROLLBAR | \
1057 WS_EX_CONTROLPARENT | \
1058 WS_EX_STATICEDGE | \
1059 WS_EX_APPWINDOW | \
1060 WS_EX_LAYERED)
1062 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1063 TRACE("\n");
1064 #undef DUMPED_EX_STYLES
1068 /***********************************************************************
1069 * WIN_CreateWindowEx
1071 * Implementation of CreateWindowEx().
1073 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1075 INT cx, cy, style, sw = SW_SHOW;
1076 LRESULT result;
1077 RECT rect;
1078 WND *wndPtr;
1079 HWND hwnd, parent, owner, top_child = 0;
1080 MDICREATESTRUCTW mdi_cs;
1081 CBT_CREATEWNDW cbtc;
1082 CREATESTRUCTW cbcs;
1084 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1085 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1086 debugstr_w(className),
1087 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1088 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1089 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1091 /* Fix the styles for MDI children */
1092 if (cs->dwExStyle & WS_EX_MDICHILD)
1094 UINT flags = 0;
1096 wndPtr = WIN_GetPtr(cs->hwndParent);
1097 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1099 flags = wndPtr->flags;
1100 WIN_ReleasePtr(wndPtr);
1103 if (!(flags & WIN_ISMDICLIENT))
1105 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1106 return 0;
1109 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1110 * MDICREATESTRUCT members have the originally passed values.
1112 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1113 * have the same layout.
1115 mdi_cs.szClass = cs->lpszClass;
1116 mdi_cs.szTitle = cs->lpszName;
1117 mdi_cs.hOwner = cs->hInstance;
1118 mdi_cs.x = cs->x;
1119 mdi_cs.y = cs->y;
1120 mdi_cs.cx = cs->cx;
1121 mdi_cs.cy = cs->cy;
1122 mdi_cs.style = cs->style;
1123 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1125 cs->lpCreateParams = &mdi_cs;
1127 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1129 if (cs->style & WS_POPUP)
1131 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1132 return 0;
1134 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1136 else
1138 cs->style &= ~WS_POPUP;
1139 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1140 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1143 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1145 if (top_child)
1147 /* Restore current maximized child */
1148 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1150 TRACE("Restoring current maximized child %p\n", top_child);
1151 if (cs->style & WS_MAXIMIZE)
1153 /* if the new window is maximized don't bother repainting */
1154 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1155 ShowWindow( top_child, SW_SHOWNORMAL );
1156 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1158 else ShowWindow( top_child, SW_SHOWNORMAL );
1163 /* Find the parent window */
1165 parent = cs->hwndParent;
1166 owner = 0;
1168 if (cs->hwndParent == HWND_MESSAGE)
1170 cs->hwndParent = parent = get_hwnd_message_parent();
1172 else if (cs->hwndParent)
1174 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1176 parent = GetDesktopWindow();
1177 owner = cs->hwndParent;
1180 else
1182 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1184 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1186 WARN("No parent for child window\n" );
1187 SetLastError(ERROR_TLW_WITH_WSCHILD);
1188 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1190 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1191 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1192 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1193 parent = GetDesktopWindow();
1196 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1198 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1199 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1200 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1201 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1202 else
1203 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1205 /* Create the window structure */
1207 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1208 return 0;
1209 hwnd = wndPtr->obj.handle;
1211 /* Fill the window structure */
1213 wndPtr->tid = GetCurrentThreadId();
1214 wndPtr->hInstance = cs->hInstance;
1215 wndPtr->text = NULL;
1216 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1217 wndPtr->dwExStyle = cs->dwExStyle;
1218 wndPtr->wIDmenu = 0;
1219 wndPtr->helpContext = 0;
1220 wndPtr->pScroll = NULL;
1221 wndPtr->userdata = 0;
1222 wndPtr->hIcon = 0;
1223 wndPtr->hIconSmall = 0;
1224 wndPtr->hSysMenu = 0;
1226 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1227 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1229 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1232 * Correct the window styles.
1234 * It affects only the style loaded into the WIN structure.
1237 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1239 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1240 if (!(wndPtr->dwStyle & WS_POPUP))
1241 wndPtr->dwStyle |= WS_CAPTION;
1245 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1246 * why does the user get to set it?
1249 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1250 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1251 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1252 else
1253 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1255 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1256 wndPtr->flags |= WIN_NEED_SIZE;
1258 SERVER_START_REQ( set_window_info )
1260 req->handle = wine_server_user_handle( hwnd );
1261 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1262 req->style = wndPtr->dwStyle;
1263 req->ex_style = wndPtr->dwExStyle;
1264 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1265 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1266 req->extra_offset = -1;
1267 wine_server_call( req );
1269 SERVER_END_REQ;
1271 /* Set the window menu */
1273 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1275 if (cs->hMenu)
1277 if (!MENU_SetMenu(hwnd, cs->hMenu))
1279 WIN_ReleasePtr( wndPtr );
1280 free_window_handle( hwnd );
1281 return 0;
1284 else
1286 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1287 if (menuName)
1289 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1290 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1294 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1296 /* call the WH_CBT hook */
1298 /* the window style passed to the hook must be the real window style,
1299 * rather than just the window style that the caller to CreateWindowEx
1300 * passed in, so we have to copy the original CREATESTRUCT and get the
1301 * the real style. */
1302 cbcs = *cs;
1303 cbcs.style = wndPtr->dwStyle;
1304 cbtc.lpcs = &cbcs;
1305 cbtc.hwndInsertAfter = HWND_TOP;
1306 WIN_ReleasePtr( wndPtr );
1307 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1309 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1311 cx = cs->cx;
1312 cy = cs->cy;
1313 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1315 POINT maxSize, maxPos, minTrack, maxTrack;
1316 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1317 if (maxTrack.x < cx) cx = maxTrack.x;
1318 if (maxTrack.y < cy) cy = maxTrack.y;
1319 if (minTrack.x > cx) cx = minTrack.x;
1320 if (minTrack.y > cy) cy = minTrack.y;
1323 if (cx < 0) cx = 0;
1324 if (cy < 0) cy = 0;
1325 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1326 /* check for wraparound */
1327 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1328 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1329 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1331 /* send WM_NCCREATE */
1333 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1334 if (unicode)
1335 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1336 else
1337 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1338 if (!result)
1340 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1341 goto failed;
1344 /* send WM_NCCALCSIZE */
1346 if ((wndPtr = WIN_GetPtr(hwnd)))
1348 /* yes, even if the CBT hook was called with HWND_TOP */
1349 POINT pt;
1350 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1351 RECT window_rect = wndPtr->rectWindow;
1352 RECT client_rect = window_rect;
1353 WIN_ReleasePtr( wndPtr );
1355 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1356 pt.x = pt.y = 0;
1357 MapWindowPoints( parent, 0, &pt, 1 );
1358 OffsetRect( &client_rect, pt.x, pt.y );
1359 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1360 OffsetRect( &client_rect, -pt.x, -pt.y );
1361 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1363 else return 0;
1365 /* send WM_CREATE */
1367 if (unicode)
1368 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1369 else
1370 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1371 if (result == -1) goto failed;
1373 /* call the driver */
1375 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1377 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1379 /* send the size messages */
1381 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1382 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1383 if (!(wndPtr->flags & WIN_NEED_SIZE))
1385 rect = wndPtr->rectClient;
1386 WIN_ReleasePtr( wndPtr );
1387 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1388 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1389 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1391 else WIN_ReleasePtr( wndPtr );
1393 /* Show the window, maximizing or minimizing if needed */
1395 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1396 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1398 RECT newPos;
1399 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1401 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1402 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1403 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1404 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1405 newPos.bottom - newPos.top, swFlag );
1408 /* Notify the parent window only */
1410 send_parent_notify( hwnd, WM_CREATE );
1411 if (!IsWindow( hwnd )) return 0;
1413 if (cs->style & WS_VISIBLE)
1415 if (cs->style & WS_MAXIMIZE)
1416 sw = SW_SHOW;
1417 else if (cs->style & WS_MINIMIZE)
1418 sw = SW_SHOWMINIMIZED;
1420 ShowWindow( hwnd, sw );
1421 if (cs->dwExStyle & WS_EX_MDICHILD)
1423 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1424 /* ShowWindow won't activate child windows */
1425 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1429 /* Call WH_SHELL hook */
1431 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1432 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1434 TRACE("created window %p\n", hwnd);
1435 return hwnd;
1437 failed:
1438 WIN_DestroyWindow( hwnd );
1439 return 0;
1443 /***********************************************************************
1444 * CreateWindowExA (USER32.@)
1446 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1447 LPCSTR windowName, DWORD style, INT x,
1448 INT y, INT width, INT height,
1449 HWND parent, HMENU menu,
1450 HINSTANCE instance, LPVOID data )
1452 CREATESTRUCTA cs;
1454 cs.lpCreateParams = data;
1455 cs.hInstance = instance;
1456 cs.hMenu = menu;
1457 cs.hwndParent = parent;
1458 cs.x = x;
1459 cs.y = y;
1460 cs.cx = width;
1461 cs.cy = height;
1462 cs.style = style;
1463 cs.lpszName = windowName;
1464 cs.lpszClass = className;
1465 cs.dwExStyle = exStyle;
1467 if (!IS_INTRESOURCE(className))
1469 WCHAR bufferW[256];
1470 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1471 return 0;
1472 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1474 /* Note: we rely on the fact that CREATESTRUCTA and */
1475 /* CREATESTRUCTW have the same layout. */
1476 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1480 /***********************************************************************
1481 * CreateWindowExW (USER32.@)
1483 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1484 LPCWSTR windowName, DWORD style, INT x,
1485 INT y, INT width, INT height,
1486 HWND parent, HMENU menu,
1487 HINSTANCE instance, LPVOID data )
1489 CREATESTRUCTW cs;
1491 cs.lpCreateParams = data;
1492 cs.hInstance = instance;
1493 cs.hMenu = menu;
1494 cs.hwndParent = parent;
1495 cs.x = x;
1496 cs.y = y;
1497 cs.cx = width;
1498 cs.cy = height;
1499 cs.style = style;
1500 cs.lpszName = windowName;
1501 cs.lpszClass = className;
1502 cs.dwExStyle = exStyle;
1504 return wow_handlers.create_window( &cs, className, instance, TRUE );
1508 /***********************************************************************
1509 * WIN_SendDestroyMsg
1511 static void WIN_SendDestroyMsg( HWND hwnd )
1513 GUITHREADINFO info;
1515 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1517 if (hwnd == info.hwndCaret) DestroyCaret();
1518 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1522 * Send the WM_DESTROY to the window.
1524 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1527 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1528 * make sure that the window still exists when we come back.
1530 if (IsWindow(hwnd))
1532 HWND* pWndArray;
1533 int i;
1535 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1537 for (i = 0; pWndArray[i]; i++)
1539 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1541 HeapFree( GetProcessHeap(), 0, pWndArray );
1543 else
1544 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1548 /***********************************************************************
1549 * DestroyWindow (USER32.@)
1551 BOOL WINAPI DestroyWindow( HWND hwnd )
1553 BOOL is_child;
1555 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1557 SetLastError( ERROR_ACCESS_DENIED );
1558 return FALSE;
1561 TRACE("(%p)\n", hwnd);
1563 /* Call hooks */
1565 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1567 if (MENU_IsMenuActive() == hwnd)
1568 EndMenu();
1570 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1572 if (is_child)
1574 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1575 send_parent_notify( hwnd, WM_DESTROY );
1577 else if (!GetWindow( hwnd, GW_OWNER ))
1579 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1580 /* FIXME: clean up palette - see "Internals" p.352 */
1583 if (!IsWindow(hwnd)) return TRUE;
1585 /* Hide the window */
1586 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1588 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1589 if (is_child)
1590 ShowWindow( hwnd, SW_HIDE );
1591 else
1592 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1593 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1596 if (!IsWindow(hwnd)) return TRUE;
1598 /* Recursively destroy owned windows */
1600 if (!is_child)
1602 for (;;)
1604 int i, got_one = 0;
1605 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1606 if (list)
1608 for (i = 0; list[i]; i++)
1610 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1611 if (WIN_IsCurrentThread( list[i] ))
1613 DestroyWindow( list[i] );
1614 got_one = 1;
1615 continue;
1617 WIN_SetOwner( list[i], 0 );
1619 HeapFree( GetProcessHeap(), 0, list );
1621 if (!got_one) break;
1625 /* Send destroy messages */
1627 WIN_SendDestroyMsg( hwnd );
1628 if (!IsWindow( hwnd )) return TRUE;
1630 if (GetClipboardOwner() == hwnd)
1631 CLIPBOARD_ReleaseOwner();
1633 /* Destroy the window storage */
1635 WIN_DestroyWindow( hwnd );
1636 return TRUE;
1640 /***********************************************************************
1641 * CloseWindow (USER32.@)
1643 BOOL WINAPI CloseWindow( HWND hwnd )
1645 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1646 ShowWindow( hwnd, SW_MINIMIZE );
1647 return TRUE;
1651 /***********************************************************************
1652 * OpenIcon (USER32.@)
1654 BOOL WINAPI OpenIcon( HWND hwnd )
1656 if (!IsIconic( hwnd )) return FALSE;
1657 ShowWindow( hwnd, SW_SHOWNORMAL );
1658 return TRUE;
1662 /***********************************************************************
1663 * FindWindowExW (USER32.@)
1665 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1667 HWND *list = NULL;
1668 HWND retvalue = 0;
1669 int i = 0, len = 0;
1670 WCHAR *buffer = NULL;
1672 if (!parent && child) parent = GetDesktopWindow();
1673 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1675 if (title)
1677 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1678 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1681 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1683 if (child)
1685 child = WIN_GetFullHandle( child );
1686 while (list[i] && list[i] != child) i++;
1687 if (!list[i]) goto done;
1688 i++; /* start from next window */
1691 if (title)
1693 while (list[i])
1695 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1696 i++;
1699 retvalue = list[i];
1701 done:
1702 HeapFree( GetProcessHeap(), 0, list );
1703 HeapFree( GetProcessHeap(), 0, buffer );
1704 return retvalue;
1709 /***********************************************************************
1710 * FindWindowA (USER32.@)
1712 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1714 HWND ret = FindWindowExA( 0, 0, className, title );
1715 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1716 return ret;
1720 /***********************************************************************
1721 * FindWindowExA (USER32.@)
1723 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1725 LPWSTR titleW = NULL;
1726 HWND hwnd = 0;
1728 if (title)
1730 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1731 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1732 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1735 if (!IS_INTRESOURCE(className))
1737 WCHAR classW[256];
1738 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1739 hwnd = FindWindowExW( parent, child, classW, titleW );
1741 else
1743 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1746 HeapFree( GetProcessHeap(), 0, titleW );
1747 return hwnd;
1751 /***********************************************************************
1752 * FindWindowW (USER32.@)
1754 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1756 return FindWindowExW( 0, 0, className, title );
1760 /**********************************************************************
1761 * GetDesktopWindow (USER32.@)
1763 HWND WINAPI GetDesktopWindow(void)
1765 struct user_thread_info *thread_info = get_user_thread_info();
1767 if (thread_info->top_window) return thread_info->top_window;
1769 SERVER_START_REQ( get_desktop_window )
1771 req->force = 0;
1772 if (!wine_server_call( req ))
1774 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1775 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1778 SERVER_END_REQ;
1780 if (!thread_info->top_window)
1782 USEROBJECTFLAGS flags;
1783 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1784 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1786 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1787 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1788 STARTUPINFOW si;
1789 PROCESS_INFORMATION pi;
1790 WCHAR windir[MAX_PATH];
1791 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1792 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1793 void *redir;
1795 memset( &si, 0, sizeof(si) );
1796 si.cb = sizeof(si);
1797 si.dwFlags = STARTF_USESTDHANDLES;
1798 si.hStdInput = 0;
1799 si.hStdOutput = 0;
1800 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1802 GetSystemDirectoryW( windir, MAX_PATH );
1803 strcpyW( app, windir );
1804 strcatW( app, explorer );
1805 strcpyW( cmdline, app );
1806 strcatW( cmdline, args );
1808 Wow64DisableWow64FsRedirection( &redir );
1809 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1810 NULL, windir, &si, &pi ))
1812 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1813 WaitForInputIdle( pi.hProcess, 10000 );
1814 CloseHandle( pi.hThread );
1815 CloseHandle( pi.hProcess );
1817 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1818 Wow64RevertWow64FsRedirection( redir );
1820 else TRACE( "not starting explorer since winstation is not visible\n" );
1822 SERVER_START_REQ( get_desktop_window )
1824 req->force = 1;
1825 if (!wine_server_call( req ))
1827 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1828 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1831 SERVER_END_REQ;
1834 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1835 ERR( "failed to create desktop window\n" );
1837 return thread_info->top_window;
1841 /*******************************************************************
1842 * EnableWindow (USER32.@)
1844 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1846 BOOL retvalue;
1847 HWND full_handle;
1849 if (is_broadcast(hwnd))
1851 SetLastError( ERROR_INVALID_PARAMETER );
1852 return FALSE;
1855 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1856 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1858 hwnd = full_handle;
1860 TRACE("( %p, %d )\n", hwnd, enable);
1862 retvalue = !IsWindowEnabled( hwnd );
1864 if (enable && retvalue)
1866 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1867 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1869 else if (!enable && !retvalue)
1871 HWND capture_wnd;
1873 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1875 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1877 if (hwnd == GetFocus())
1878 SetFocus( 0 ); /* A disabled window can't have the focus */
1880 capture_wnd = GetCapture();
1881 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1882 ReleaseCapture(); /* A disabled window can't capture the mouse */
1884 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1886 return retvalue;
1890 /***********************************************************************
1891 * IsWindowEnabled (USER32.@)
1893 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1895 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1899 /***********************************************************************
1900 * IsWindowUnicode (USER32.@)
1902 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1904 WND * wndPtr;
1905 BOOL retvalue = FALSE;
1907 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1909 if (wndPtr == WND_DESKTOP) return TRUE;
1911 if (wndPtr != WND_OTHER_PROCESS)
1913 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1914 WIN_ReleasePtr( wndPtr );
1916 else
1918 SERVER_START_REQ( get_window_info )
1920 req->handle = wine_server_user_handle( hwnd );
1921 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1923 SERVER_END_REQ;
1925 return retvalue;
1929 /**********************************************************************
1930 * WIN_GetWindowLong
1932 * Helper function for GetWindowLong().
1934 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1936 LONG_PTR retvalue = 0;
1937 WND *wndPtr;
1939 if (offset == GWLP_HWNDPARENT)
1941 HWND parent = GetAncestor( hwnd, GA_PARENT );
1942 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1943 return (ULONG_PTR)parent;
1946 if (!(wndPtr = WIN_GetPtr( hwnd )))
1948 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1949 return 0;
1952 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1954 if (offset == GWLP_WNDPROC)
1956 SetLastError( ERROR_ACCESS_DENIED );
1957 return 0;
1959 SERVER_START_REQ( set_window_info )
1961 req->handle = wine_server_user_handle( hwnd );
1962 req->flags = 0; /* don't set anything, just retrieve */
1963 req->extra_offset = (offset >= 0) ? offset : -1;
1964 req->extra_size = (offset >= 0) ? size : 0;
1965 if (!wine_server_call_err( req ))
1967 switch(offset)
1969 case GWL_STYLE: retvalue = reply->old_style; break;
1970 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1971 case GWLP_ID: retvalue = reply->old_id; break;
1972 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1973 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1974 default:
1975 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1976 else SetLastError( ERROR_INVALID_INDEX );
1977 break;
1981 SERVER_END_REQ;
1982 return retvalue;
1985 /* now we have a valid wndPtr */
1987 if (offset >= 0)
1989 if (offset > (int)(wndPtr->cbWndExtra - size))
1991 WARN("Invalid offset %d\n", offset );
1992 WIN_ReleasePtr( wndPtr );
1993 SetLastError( ERROR_INVALID_INDEX );
1994 return 0;
1996 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1998 /* Special case for dialog window procedure */
1999 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2000 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2001 WIN_ReleasePtr( wndPtr );
2002 return retvalue;
2005 switch(offset)
2007 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2008 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2009 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2010 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2011 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2012 case GWLP_WNDPROC:
2013 /* This looks like a hack only for the edit control (see tests). This makes these controls
2014 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2015 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2017 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2018 retvalue = (ULONG_PTR)wndPtr->winproc;
2019 else
2020 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2021 break;
2022 default:
2023 WARN("Unknown offset %d\n", offset );
2024 SetLastError( ERROR_INVALID_INDEX );
2025 break;
2027 WIN_ReleasePtr(wndPtr);
2028 return retvalue;
2032 /**********************************************************************
2033 * WIN_SetWindowLong
2035 * Helper function for SetWindowLong().
2037 * 0 is the failure code. However, in the case of failure SetLastError
2038 * must be set to distinguish between a 0 return value and a failure.
2040 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2042 STYLESTRUCT style;
2043 BOOL ok;
2044 LONG_PTR retval = 0;
2045 WND *wndPtr;
2047 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2049 if (is_broadcast(hwnd))
2051 SetLastError( ERROR_INVALID_PARAMETER );
2052 return FALSE;
2055 if (!(wndPtr = WIN_GetPtr( hwnd )))
2057 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2058 return 0;
2060 if (wndPtr == WND_DESKTOP)
2062 /* can't change anything on the desktop window */
2063 SetLastError( ERROR_ACCESS_DENIED );
2064 return 0;
2066 if (wndPtr == WND_OTHER_PROCESS)
2068 if (offset == GWLP_WNDPROC)
2070 SetLastError( ERROR_ACCESS_DENIED );
2071 return 0;
2073 if (offset > 32767 || offset < -32767)
2075 SetLastError( ERROR_INVALID_INDEX );
2076 return 0;
2078 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2081 /* first some special cases */
2082 switch( offset )
2084 case GWL_STYLE:
2085 case GWL_EXSTYLE:
2086 style.styleOld =
2087 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2088 style.styleNew = newval;
2089 WIN_ReleasePtr( wndPtr );
2090 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2091 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2092 newval = style.styleNew;
2093 break;
2094 case GWLP_HWNDPARENT:
2095 if (wndPtr->parent == GetDesktopWindow())
2097 WIN_ReleasePtr( wndPtr );
2098 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2100 else
2102 WIN_ReleasePtr( wndPtr );
2103 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2105 case GWLP_WNDPROC:
2107 WNDPROC proc;
2108 UINT old_flags = wndPtr->flags;
2109 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2110 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2111 if (proc) wndPtr->winproc = proc;
2112 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2113 else wndPtr->flags &= ~WIN_ISUNICODE;
2114 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2116 WIN_ReleasePtr( wndPtr );
2117 return retval;
2119 /* update is_unicode flag on the server side */
2120 break;
2122 case GWLP_ID:
2123 case GWLP_HINSTANCE:
2124 case GWLP_USERDATA:
2125 break;
2126 case DWLP_DLGPROC:
2127 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2128 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2130 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2131 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2132 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2133 WIN_ReleasePtr( wndPtr );
2134 return retval;
2136 /* fall through */
2137 default:
2138 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2140 WARN("Invalid offset %d\n", offset );
2141 WIN_ReleasePtr( wndPtr );
2142 SetLastError( ERROR_INVALID_INDEX );
2143 return 0;
2145 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2147 /* already set to the same value */
2148 WIN_ReleasePtr( wndPtr );
2149 return newval;
2151 break;
2154 SERVER_START_REQ( set_window_info )
2156 req->handle = wine_server_user_handle( hwnd );
2157 req->extra_offset = -1;
2158 switch(offset)
2160 case GWL_STYLE:
2161 req->flags = SET_WIN_STYLE;
2162 req->style = newval;
2163 break;
2164 case GWL_EXSTYLE:
2165 req->flags = SET_WIN_EXSTYLE;
2166 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2167 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2168 req->ex_style = newval;
2169 break;
2170 case GWLP_ID:
2171 req->flags = SET_WIN_ID;
2172 req->id = newval;
2173 break;
2174 case GWLP_HINSTANCE:
2175 req->flags = SET_WIN_INSTANCE;
2176 req->instance = wine_server_client_ptr( (void *)newval );
2177 break;
2178 case GWLP_WNDPROC:
2179 req->flags = SET_WIN_UNICODE;
2180 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2181 break;
2182 case GWLP_USERDATA:
2183 req->flags = SET_WIN_USERDATA;
2184 req->user_data = newval;
2185 break;
2186 default:
2187 req->flags = SET_WIN_EXTRA;
2188 req->extra_offset = offset;
2189 req->extra_size = size;
2190 set_win_data( &req->extra_value, newval, size );
2192 if ((ok = !wine_server_call_err( req )))
2194 switch(offset)
2196 case GWL_STYLE:
2197 wndPtr->dwStyle = newval;
2198 retval = reply->old_style;
2199 break;
2200 case GWL_EXSTYLE:
2201 wndPtr->dwExStyle = newval;
2202 retval = reply->old_ex_style;
2203 break;
2204 case GWLP_ID:
2205 wndPtr->wIDmenu = newval;
2206 retval = reply->old_id;
2207 break;
2208 case GWLP_HINSTANCE:
2209 wndPtr->hInstance = (HINSTANCE)newval;
2210 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2211 break;
2212 case GWLP_WNDPROC:
2213 break;
2214 case GWLP_USERDATA:
2215 wndPtr->userdata = newval;
2216 retval = reply->old_user_data;
2217 break;
2218 default:
2219 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2220 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2221 break;
2225 SERVER_END_REQ;
2226 WIN_ReleasePtr( wndPtr );
2228 if (!ok) return 0;
2230 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2232 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2233 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2236 return retval;
2240 /**********************************************************************
2241 * GetWindowWord (USER32.@)
2243 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2245 switch(offset)
2247 case GWLP_ID:
2248 case GWLP_HINSTANCE:
2249 case GWLP_HWNDPARENT:
2250 break;
2251 default:
2252 if (offset < 0)
2254 WARN("Invalid offset %d\n", offset );
2255 SetLastError( ERROR_INVALID_INDEX );
2256 return 0;
2258 break;
2260 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2264 /**********************************************************************
2265 * GetWindowLongA (USER32.@)
2267 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2269 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2273 /**********************************************************************
2274 * GetWindowLongW (USER32.@)
2276 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2278 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2282 /**********************************************************************
2283 * SetWindowWord (USER32.@)
2285 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2287 switch(offset)
2289 case GWLP_ID:
2290 case GWLP_HINSTANCE:
2291 case GWLP_HWNDPARENT:
2292 break;
2293 default:
2294 if (offset < 0)
2296 WARN("Invalid offset %d\n", offset );
2297 SetLastError( ERROR_INVALID_INDEX );
2298 return 0;
2300 break;
2302 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2306 /**********************************************************************
2307 * SetWindowLongA (USER32.@)
2309 * See SetWindowLongW.
2311 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2313 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2317 /**********************************************************************
2318 * SetWindowLongW (USER32.@) Set window attribute
2320 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2321 * value in a window's extra memory.
2323 * The _hwnd_ parameter specifies the window. is the handle to a
2324 * window that has extra memory. The _newval_ parameter contains the
2325 * new attribute or extra memory value. If positive, the _offset_
2326 * parameter is the byte-addressed location in the window's extra
2327 * memory to set. If negative, _offset_ specifies the window
2328 * attribute to set, and should be one of the following values:
2330 * GWL_EXSTYLE The window's extended window style
2332 * GWL_STYLE The window's window style.
2334 * GWLP_WNDPROC Pointer to the window's window procedure.
2336 * GWLP_HINSTANCE The window's pplication instance handle.
2338 * GWLP_ID The window's identifier.
2340 * GWLP_USERDATA The window's user-specified data.
2342 * If the window is a dialog box, the _offset_ parameter can be one of
2343 * the following values:
2345 * DWLP_DLGPROC The address of the window's dialog box procedure.
2347 * DWLP_MSGRESULT The return value of a message
2348 * that the dialog box procedure processed.
2350 * DWLP_USER Application specific information.
2352 * RETURNS
2354 * If successful, returns the previous value located at _offset_. Otherwise,
2355 * returns 0.
2357 * NOTES
2359 * Extra memory for a window class is specified by a nonzero cbWndExtra
2360 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2361 * time of class creation.
2363 * Using GWL_WNDPROC to set a new window procedure effectively creates
2364 * a window subclass. Use CallWindowProc() in the new windows procedure
2365 * to pass messages to the superclass's window procedure.
2367 * The user data is reserved for use by the application which created
2368 * the window.
2370 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2371 * instead, call the EnableWindow() function to change the window's
2372 * disabled state.
2374 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2375 * SetParent() instead.
2377 * Win95:
2378 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2379 * it sends WM_STYLECHANGING before changing the settings
2380 * and WM_STYLECHANGED afterwards.
2381 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2383 LONG WINAPI SetWindowLongW(
2384 HWND hwnd, /* [in] window to alter */
2385 INT offset, /* [in] offset, in bytes, of location to alter */
2386 LONG newval /* [in] new value of location */
2388 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2392 /*******************************************************************
2393 * GetWindowTextA (USER32.@)
2395 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2397 WCHAR *buffer;
2399 if (!lpString) return 0;
2401 if (WIN_IsCurrentProcess( hwnd ))
2402 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2404 /* when window belongs to other process, don't send a message */
2405 if (nMaxCount <= 0) return 0;
2406 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2407 get_server_window_text( hwnd, buffer, nMaxCount );
2408 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2409 lpString[nMaxCount-1] = 0;
2410 HeapFree( GetProcessHeap(), 0, buffer );
2411 return strlen(lpString);
2415 /*******************************************************************
2416 * InternalGetWindowText (USER32.@)
2418 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2420 WND *win;
2422 if (nMaxCount <= 0) return 0;
2423 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2424 if (win == WND_DESKTOP) lpString[0] = 0;
2425 else if (win != WND_OTHER_PROCESS)
2427 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2428 else lpString[0] = 0;
2429 WIN_ReleasePtr( win );
2431 else
2433 get_server_window_text( hwnd, lpString, nMaxCount );
2435 return strlenW(lpString);
2439 /*******************************************************************
2440 * GetWindowTextW (USER32.@)
2442 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2444 if (!lpString) return 0;
2446 if (WIN_IsCurrentProcess( hwnd ))
2447 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2449 /* when window belongs to other process, don't send a message */
2450 if (nMaxCount <= 0) return 0;
2451 get_server_window_text( hwnd, lpString, nMaxCount );
2452 return strlenW(lpString);
2456 /*******************************************************************
2457 * SetWindowTextA (USER32.@)
2458 * SetWindowText (USER32.@)
2460 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2462 if (is_broadcast(hwnd))
2464 SetLastError( ERROR_INVALID_PARAMETER );
2465 return FALSE;
2467 if (!WIN_IsCurrentProcess( hwnd ))
2468 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2469 debugstr_a(lpString), hwnd );
2470 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2474 /*******************************************************************
2475 * SetWindowTextW (USER32.@)
2477 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2479 if (is_broadcast(hwnd))
2481 SetLastError( ERROR_INVALID_PARAMETER );
2482 return FALSE;
2484 if (!WIN_IsCurrentProcess( hwnd ))
2485 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2486 debugstr_w(lpString), hwnd );
2487 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2491 /*******************************************************************
2492 * GetWindowTextLengthA (USER32.@)
2494 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2496 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2499 /*******************************************************************
2500 * GetWindowTextLengthW (USER32.@)
2502 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2504 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2508 /*******************************************************************
2509 * IsWindow (USER32.@)
2511 BOOL WINAPI IsWindow( HWND hwnd )
2513 WND *ptr;
2514 BOOL ret;
2516 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2517 if (ptr == WND_DESKTOP) return TRUE;
2519 if (ptr != WND_OTHER_PROCESS)
2521 WIN_ReleasePtr( ptr );
2522 return TRUE;
2525 /* check other processes */
2526 SERVER_START_REQ( get_window_info )
2528 req->handle = wine_server_user_handle( hwnd );
2529 ret = !wine_server_call_err( req );
2531 SERVER_END_REQ;
2532 return ret;
2536 /***********************************************************************
2537 * GetWindowThreadProcessId (USER32.@)
2539 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2541 WND *ptr;
2542 DWORD tid = 0;
2544 if (!(ptr = WIN_GetPtr( hwnd )))
2546 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2547 return 0;
2550 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2552 /* got a valid window */
2553 tid = ptr->tid;
2554 if (process) *process = GetCurrentProcessId();
2555 WIN_ReleasePtr( ptr );
2556 return tid;
2559 /* check other processes */
2560 SERVER_START_REQ( get_window_info )
2562 req->handle = wine_server_user_handle( hwnd );
2563 if (!wine_server_call_err( req ))
2565 tid = (DWORD)reply->tid;
2566 if (process) *process = (DWORD)reply->pid;
2569 SERVER_END_REQ;
2570 return tid;
2574 /*****************************************************************
2575 * GetParent (USER32.@)
2577 HWND WINAPI GetParent( HWND hwnd )
2579 WND *wndPtr;
2580 HWND retvalue = 0;
2582 if (!(wndPtr = WIN_GetPtr( hwnd )))
2584 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2585 return 0;
2587 if (wndPtr == WND_DESKTOP) return 0;
2588 if (wndPtr == WND_OTHER_PROCESS)
2590 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2591 if (style & (WS_POPUP | WS_CHILD))
2593 SERVER_START_REQ( get_window_tree )
2595 req->handle = wine_server_user_handle( hwnd );
2596 if (!wine_server_call_err( req ))
2598 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2599 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2602 SERVER_END_REQ;
2605 else
2607 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2608 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2609 WIN_ReleasePtr( wndPtr );
2611 return retvalue;
2615 /*****************************************************************
2616 * GetAncestor (USER32.@)
2618 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2620 WND *win;
2621 HWND *list, ret = 0;
2623 switch(type)
2625 case GA_PARENT:
2626 if (!(win = WIN_GetPtr( hwnd )))
2628 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2629 return 0;
2631 if (win == WND_DESKTOP) return 0;
2632 if (win != WND_OTHER_PROCESS)
2634 ret = win->parent;
2635 WIN_ReleasePtr( win );
2637 else /* need to query the server */
2639 SERVER_START_REQ( get_window_tree )
2641 req->handle = wine_server_user_handle( hwnd );
2642 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2644 SERVER_END_REQ;
2646 break;
2648 case GA_ROOT:
2649 if (!(list = list_window_parents( hwnd ))) return 0;
2651 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2652 else
2654 int count = 2;
2655 while (list[count]) count++;
2656 ret = list[count - 2]; /* get the one before the desktop */
2658 HeapFree( GetProcessHeap(), 0, list );
2659 break;
2661 case GA_ROOTOWNER:
2662 if (is_desktop_window( hwnd )) return 0;
2663 ret = WIN_GetFullHandle( hwnd );
2664 for (;;)
2666 HWND parent = GetParent( ret );
2667 if (!parent) break;
2668 ret = parent;
2670 break;
2672 return ret;
2676 /*****************************************************************
2677 * SetParent (USER32.@)
2679 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2681 HWND full_handle;
2682 HWND old_parent = 0;
2683 BOOL was_visible;
2684 WND *wndPtr;
2685 BOOL ret;
2687 if (is_broadcast(hwnd) || is_broadcast(parent))
2689 SetLastError(ERROR_INVALID_PARAMETER);
2690 return 0;
2693 if (!parent) parent = GetDesktopWindow();
2694 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2695 else parent = WIN_GetFullHandle( parent );
2697 if (!IsWindow( parent ))
2699 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2700 return 0;
2703 /* Some applications try to set a child as a parent */
2704 if (IsChild(hwnd, parent))
2706 SetLastError( ERROR_INVALID_PARAMETER );
2707 return 0;
2710 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2711 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2713 if (full_handle == parent)
2715 SetLastError( ERROR_INVALID_PARAMETER );
2716 return 0;
2719 /* Windows hides the window first, then shows it again
2720 * including the WM_SHOWWINDOW messages and all */
2721 was_visible = ShowWindow( hwnd, SW_HIDE );
2723 wndPtr = WIN_GetPtr( hwnd );
2724 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2726 SERVER_START_REQ( set_parent )
2728 req->handle = wine_server_user_handle( hwnd );
2729 req->parent = wine_server_user_handle( parent );
2730 if ((ret = !wine_server_call( req )))
2732 old_parent = wine_server_ptr_handle( reply->old_parent );
2733 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2737 SERVER_END_REQ;
2738 WIN_ReleasePtr( wndPtr );
2739 if (!ret) return 0;
2741 USER_Driver->pSetParent( full_handle, parent, old_parent );
2743 /* SetParent additionally needs to make hwnd the topmost window
2744 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2745 WM_WINDOWPOSCHANGED notification messages.
2747 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2748 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2749 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2750 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2752 return old_parent;
2756 /*******************************************************************
2757 * IsChild (USER32.@)
2759 BOOL WINAPI IsChild( HWND parent, HWND child )
2761 HWND *list = list_window_parents( child );
2762 int i;
2763 BOOL ret;
2765 if (!list) return FALSE;
2766 parent = WIN_GetFullHandle( parent );
2767 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2768 ret = list[i] && list[i+1];
2769 HeapFree( GetProcessHeap(), 0, list );
2770 return ret;
2774 /***********************************************************************
2775 * IsWindowVisible (USER32.@)
2777 BOOL WINAPI IsWindowVisible( HWND hwnd )
2779 HWND *list;
2780 BOOL retval = TRUE;
2781 int i;
2783 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2784 if (!(list = list_window_parents( hwnd ))) return TRUE;
2785 if (list[0])
2787 for (i = 0; list[i+1]; i++)
2788 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2789 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2791 HeapFree( GetProcessHeap(), 0, list );
2792 return retval;
2796 /***********************************************************************
2797 * WIN_IsWindowDrawable
2799 * hwnd is drawable when it is visible, all parents are not
2800 * minimized, and it is itself not minimized unless we are
2801 * trying to draw its default class icon.
2803 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2805 HWND *list;
2806 BOOL retval = TRUE;
2807 int i;
2808 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2810 if (!(style & WS_VISIBLE)) return FALSE;
2811 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2813 if (!(list = list_window_parents( hwnd ))) return TRUE;
2814 if (list[0])
2816 for (i = 0; list[i+1]; i++)
2817 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2818 break;
2819 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2821 HeapFree( GetProcessHeap(), 0, list );
2822 return retval;
2826 /*******************************************************************
2827 * GetTopWindow (USER32.@)
2829 HWND WINAPI GetTopWindow( HWND hwnd )
2831 if (!hwnd) hwnd = GetDesktopWindow();
2832 return GetWindow( hwnd, GW_CHILD );
2836 /*******************************************************************
2837 * GetWindow (USER32.@)
2839 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2841 HWND retval = 0;
2843 if (rel == GW_OWNER) /* this one may be available locally */
2845 WND *wndPtr = WIN_GetPtr( hwnd );
2846 if (!wndPtr)
2848 SetLastError( ERROR_INVALID_HANDLE );
2849 return 0;
2851 if (wndPtr == WND_DESKTOP) return 0;
2852 if (wndPtr != WND_OTHER_PROCESS)
2854 retval = wndPtr->owner;
2855 WIN_ReleasePtr( wndPtr );
2856 return retval;
2858 /* else fall through to server call */
2861 SERVER_START_REQ( get_window_tree )
2863 req->handle = wine_server_user_handle( hwnd );
2864 if (!wine_server_call_err( req ))
2866 switch(rel)
2868 case GW_HWNDFIRST:
2869 retval = wine_server_ptr_handle( reply->first_sibling );
2870 break;
2871 case GW_HWNDLAST:
2872 retval = wine_server_ptr_handle( reply->last_sibling );
2873 break;
2874 case GW_HWNDNEXT:
2875 retval = wine_server_ptr_handle( reply->next_sibling );
2876 break;
2877 case GW_HWNDPREV:
2878 retval = wine_server_ptr_handle( reply->prev_sibling );
2879 break;
2880 case GW_OWNER:
2881 retval = wine_server_ptr_handle( reply->owner );
2882 break;
2883 case GW_CHILD:
2884 retval = wine_server_ptr_handle( reply->first_child );
2885 break;
2889 SERVER_END_REQ;
2890 return retval;
2894 /*******************************************************************
2895 * ShowOwnedPopups (USER32.@)
2897 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2899 int count = 0;
2900 WND *pWnd;
2901 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2903 if (!win_array) return TRUE;
2905 while (win_array[count]) count++;
2906 while (--count >= 0)
2908 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2909 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2910 if (pWnd == WND_OTHER_PROCESS) continue;
2911 if (fShow)
2913 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2915 WIN_ReleasePtr( pWnd );
2916 /* In Windows, ShowOwnedPopups(TRUE) generates
2917 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2918 * regardless of the state of the owner
2920 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2921 continue;
2924 else
2926 if (pWnd->dwStyle & WS_VISIBLE)
2928 WIN_ReleasePtr( pWnd );
2929 /* In Windows, ShowOwnedPopups(FALSE) generates
2930 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2931 * regardless of the state of the owner
2933 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2934 continue;
2937 WIN_ReleasePtr( pWnd );
2939 HeapFree( GetProcessHeap(), 0, win_array );
2940 return TRUE;
2944 /*******************************************************************
2945 * GetLastActivePopup (USER32.@)
2947 HWND WINAPI GetLastActivePopup( HWND hwnd )
2949 HWND retval = hwnd;
2951 SERVER_START_REQ( get_window_info )
2953 req->handle = wine_server_user_handle( hwnd );
2954 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2956 SERVER_END_REQ;
2957 return retval;
2961 /*******************************************************************
2962 * WIN_ListChildren
2964 * Build an array of the children of a given window. The array must be
2965 * freed with HeapFree. Returns NULL when no windows are found.
2967 HWND *WIN_ListChildren( HWND hwnd )
2969 if (!hwnd)
2971 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2972 return NULL;
2974 return list_window_children( 0, hwnd, NULL, 0 );
2978 /*******************************************************************
2979 * EnumWindows (USER32.@)
2981 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2983 HWND *list;
2984 BOOL ret = TRUE;
2985 int i;
2987 USER_CheckNotLock();
2989 /* We have to build a list of all windows first, to avoid */
2990 /* unpleasant side-effects, for instance if the callback */
2991 /* function changes the Z-order of the windows. */
2993 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2995 /* Now call the callback function for every window */
2997 for (i = 0; list[i]; i++)
2999 /* Make sure that the window still exists */
3000 if (!IsWindow( list[i] )) continue;
3001 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3003 HeapFree( GetProcessHeap(), 0, list );
3004 return ret;
3008 /**********************************************************************
3009 * EnumThreadWindows (USER32.@)
3011 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3013 HWND *list;
3014 int i;
3015 BOOL ret = TRUE;
3017 USER_CheckNotLock();
3019 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3021 /* Now call the callback function for every window */
3023 for (i = 0; list[i]; i++)
3024 if (!(ret = func( list[i], lParam ))) break;
3025 HeapFree( GetProcessHeap(), 0, list );
3026 return ret;
3030 /***********************************************************************
3031 * EnumDesktopWindows (USER32.@)
3033 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3035 HWND *list;
3036 int i;
3038 USER_CheckNotLock();
3040 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3042 for (i = 0; list[i]; i++)
3043 if (!func( list[i], lparam )) break;
3044 HeapFree( GetProcessHeap(), 0, list );
3045 return TRUE;
3049 /**********************************************************************
3050 * WIN_EnumChildWindows
3052 * Helper function for EnumChildWindows().
3054 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3056 HWND *childList;
3057 BOOL ret = FALSE;
3059 for ( ; *list; list++)
3061 /* Make sure that the window still exists */
3062 if (!IsWindow( *list )) continue;
3063 /* Build children list first */
3064 childList = WIN_ListChildren( *list );
3066 ret = func( *list, lParam );
3068 if (childList)
3070 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3071 HeapFree( GetProcessHeap(), 0, childList );
3073 if (!ret) return FALSE;
3075 return TRUE;
3079 /**********************************************************************
3080 * EnumChildWindows (USER32.@)
3082 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3084 HWND *list;
3085 BOOL ret;
3087 USER_CheckNotLock();
3089 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3090 ret = WIN_EnumChildWindows( list, func, lParam );
3091 HeapFree( GetProcessHeap(), 0, list );
3092 return ret;
3096 /*******************************************************************
3097 * AnyPopup (USER32.@)
3099 BOOL WINAPI AnyPopup(void)
3101 int i;
3102 BOOL retvalue;
3103 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3105 if (!list) return FALSE;
3106 for (i = 0; list[i]; i++)
3108 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3110 retvalue = (list[i] != 0);
3111 HeapFree( GetProcessHeap(), 0, list );
3112 return retvalue;
3116 /*******************************************************************
3117 * FlashWindow (USER32.@)
3119 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3121 WND *wndPtr;
3123 TRACE("%p\n", hWnd);
3125 if (IsIconic( hWnd ))
3127 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3129 wndPtr = WIN_GetPtr(hWnd);
3130 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3131 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3133 wndPtr->flags |= WIN_NCACTIVATED;
3135 else
3137 wndPtr->flags &= ~WIN_NCACTIVATED;
3139 WIN_ReleasePtr( wndPtr );
3140 return TRUE;
3142 else
3144 WPARAM wparam;
3146 wndPtr = WIN_GetPtr(hWnd);
3147 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3148 hWnd = wndPtr->obj.handle; /* make it a full handle */
3150 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3151 else wparam = (hWnd == GetForegroundWindow());
3153 WIN_ReleasePtr( wndPtr );
3154 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3155 return wparam;
3159 /*******************************************************************
3160 * FlashWindowEx (USER32.@)
3162 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3164 FIXME("%p\n", pfwi);
3165 return TRUE;
3168 /*******************************************************************
3169 * GetWindowContextHelpId (USER32.@)
3171 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3173 DWORD retval;
3174 WND *wnd = WIN_GetPtr( hwnd );
3175 if (!wnd || wnd == WND_DESKTOP) return 0;
3176 if (wnd == WND_OTHER_PROCESS)
3178 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3179 return 0;
3181 retval = wnd->helpContext;
3182 WIN_ReleasePtr( wnd );
3183 return retval;
3187 /*******************************************************************
3188 * SetWindowContextHelpId (USER32.@)
3190 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3192 WND *wnd = WIN_GetPtr( hwnd );
3193 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3194 if (wnd == WND_OTHER_PROCESS)
3196 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3197 return 0;
3199 wnd->helpContext = id;
3200 WIN_ReleasePtr( wnd );
3201 return TRUE;
3205 /*******************************************************************
3206 * DragDetect (USER32.@)
3208 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3210 MSG msg;
3211 RECT rect;
3212 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3213 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3215 rect.left = pt.x - wDragWidth;
3216 rect.right = pt.x + wDragWidth;
3218 rect.top = pt.y - wDragHeight;
3219 rect.bottom = pt.y + wDragHeight;
3221 SetCapture(hWnd);
3223 while(1)
3225 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3227 if( msg.message == WM_LBUTTONUP )
3229 ReleaseCapture();
3230 return 0;
3232 if( msg.message == WM_MOUSEMOVE )
3234 POINT tmp;
3235 tmp.x = (short)LOWORD(msg.lParam);
3236 tmp.y = (short)HIWORD(msg.lParam);
3237 if( !PtInRect( &rect, tmp ))
3239 ReleaseCapture();
3240 return 1;
3244 WaitMessage();
3246 return 0;
3249 /******************************************************************************
3250 * GetWindowModuleFileNameA (USER32.@)
3252 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3254 WND *win;
3255 HINSTANCE hinst;
3257 TRACE( "%p, %p, %u\n", hwnd, module, size );
3259 win = WIN_GetPtr( hwnd );
3260 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3262 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3263 return 0;
3265 hinst = win->hInstance;
3266 WIN_ReleasePtr( win );
3268 return GetModuleFileNameA( hinst, module, size );
3271 /******************************************************************************
3272 * GetWindowModuleFileNameW (USER32.@)
3274 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3276 WND *win;
3277 HINSTANCE hinst;
3279 TRACE( "%p, %p, %u\n", hwnd, module, size );
3281 win = WIN_GetPtr( hwnd );
3282 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3284 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3285 return 0;
3287 hinst = win->hInstance;
3288 WIN_ReleasePtr( win );
3290 return GetModuleFileNameW( hinst, module, size );
3293 /******************************************************************************
3294 * GetWindowInfo (USER32.@)
3296 * Note: tests show that Windows doesn't check cbSize of the structure.
3298 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3300 if (!pwi) return FALSE;
3301 if (!IsWindow(hwnd)) return FALSE;
3303 GetWindowRect(hwnd, &pwi->rcWindow);
3304 GetClientRect(hwnd, &pwi->rcClient);
3305 /* translate to screen coordinates */
3306 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3308 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3309 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3310 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3312 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3313 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3315 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3316 pwi->wCreatorVersion = 0x0400;
3318 return TRUE;
3321 /******************************************************************************
3322 * SwitchDesktop (USER32.@)
3324 * NOTES: Sets the current input or interactive desktop.
3326 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3328 FIXME("(hwnd %p) stub!\n", hDesktop);
3329 return TRUE;
3332 /*****************************************************************************
3333 * SetLayeredWindowAttributes (USER32.@)
3335 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3337 BOOL ret;
3339 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3341 SERVER_START_REQ( set_window_layered_info )
3343 req->handle = wine_server_user_handle( hwnd );
3344 req->color_key = key;
3345 req->alpha = alpha;
3346 req->flags = flags;
3347 ret = !wine_server_call_err( req );
3349 SERVER_END_REQ;
3351 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3353 return ret;
3357 /*****************************************************************************
3358 * GetLayeredWindowAttributes (USER32.@)
3360 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3362 BOOL ret;
3364 SERVER_START_REQ( get_window_layered_info )
3366 req->handle = wine_server_user_handle( hwnd );
3367 if ((ret = !wine_server_call_err( req )))
3369 if (key) *key = reply->color_key;
3370 if (alpha) *alpha = reply->alpha;
3371 if (flags) *flags = reply->flags;
3374 SERVER_END_REQ;
3376 return ret;
3380 /*****************************************************************************
3381 * UpdateLayeredWindowIndirect (USER32.@)
3383 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3385 BYTE alpha = 0xff;
3387 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3389 int x = 0, y = 0, cx = 0, cy = 0;
3390 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3392 if (info->pptDst)
3394 x = info->pptDst->x;
3395 y = info->pptDst->y;
3396 flags &= ~SWP_NOMOVE;
3398 if (info->psize)
3400 cx = info->psize->cx;
3401 cy = info->psize->cy;
3402 flags &= ~SWP_NOSIZE;
3404 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3405 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3408 if (info->hdcSrc)
3410 HDC hdc = GetWindowDC( hwnd );
3412 if (hdc)
3414 int x = 0, y = 0;
3415 RECT rect;
3417 GetWindowRect( hwnd, &rect );
3418 OffsetRect( &rect, -rect.left, -rect.top);
3419 if (info->pptSrc)
3421 x = info->pptSrc->x;
3422 y = info->pptSrc->y;
3425 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3427 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3428 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3429 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3431 ReleaseDC( hwnd, hdc );
3435 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3436 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3437 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3438 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3439 return TRUE;
3443 /*****************************************************************************
3444 * UpdateLayeredWindow (USER32.@)
3446 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3447 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3448 DWORD dwFlags)
3450 UPDATELAYEREDWINDOWINFO info;
3452 info.cbSize = sizeof(info);
3453 info.hdcDst = hdcDst;
3454 info.pptDst = pptDst;
3455 info.psize = psize;
3456 info.hdcSrc = hdcSrc;
3457 info.pptSrc = pptSrc;
3458 info.crKey = crKey;
3459 info.pblend = pblend;
3460 info.dwFlags = dwFlags;
3461 info.prcDirty = NULL;
3462 return UpdateLayeredWindowIndirect( hwnd, &info );
3465 /* 64bit versions */
3467 #ifdef GetWindowLongPtrW
3468 #undef GetWindowLongPtrW
3469 #endif
3471 #ifdef GetWindowLongPtrA
3472 #undef GetWindowLongPtrA
3473 #endif
3475 #ifdef SetWindowLongPtrW
3476 #undef SetWindowLongPtrW
3477 #endif
3479 #ifdef SetWindowLongPtrA
3480 #undef SetWindowLongPtrA
3481 #endif
3483 /*****************************************************************************
3484 * GetWindowLongPtrW (USER32.@)
3486 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3488 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3491 /*****************************************************************************
3492 * GetWindowLongPtrA (USER32.@)
3494 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3496 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3499 /*****************************************************************************
3500 * SetWindowLongPtrW (USER32.@)
3502 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3504 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3507 /*****************************************************************************
3508 * SetWindowLongPtrA (USER32.@)
3510 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3512 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );