Release 1.1.37.
[wine/gsoc-2012-control.git] / dlls / user32 / win.c
blobacf70a3a5c146b7ff6e10e5ed1b5b3f2259794db
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 USER_Unlock();
150 /***********************************************************************
151 * free_user_handle
153 void *free_user_handle( HANDLE handle, enum user_obj_type type )
155 struct user_object *ptr;
156 WORD index = USER_HANDLE_TO_INDEX( handle );
158 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
160 SERVER_START_REQ( free_user_handle )
162 req->handle = wine_server_user_handle( handle );
163 if (!wine_server_call( req )) user_handles[index] = NULL;
164 else ptr = NULL;
166 SERVER_END_REQ;
167 release_user_handle_ptr( ptr );
169 return ptr;
173 /***********************************************************************
174 * create_window_handle
176 * Create a window handle with the server.
178 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
179 HINSTANCE instance, BOOL unicode )
181 WORD index;
182 WND *win;
183 HWND handle = 0, full_parent = 0, full_owner = 0;
184 struct tagCLASS *class = NULL;
185 int extra_bytes = 0;
187 SERVER_START_REQ( create_window )
189 req->parent = wine_server_user_handle( parent );
190 req->owner = wine_server_user_handle( owner );
191 req->instance = wine_server_client_ptr( instance );
192 if (!(req->atom = get_int_atom_value( name )) && name)
193 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
194 if (!wine_server_call_err( req ))
196 handle = wine_server_ptr_handle( reply->handle );
197 full_parent = wine_server_ptr_handle( reply->parent );
198 full_owner = wine_server_ptr_handle( reply->owner );
199 extra_bytes = reply->extra;
200 class = wine_server_get_ptr( reply->class_ptr );
203 SERVER_END_REQ;
205 if (!handle)
207 WARN( "error %d creating window\n", GetLastError() );
208 return NULL;
211 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
212 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
214 SERVER_START_REQ( destroy_window )
216 req->handle = wine_server_user_handle( handle );
217 wine_server_call( req );
219 SERVER_END_REQ;
220 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
221 return NULL;
224 if (!parent) /* if parent is 0 we don't have a desktop window yet */
226 struct user_thread_info *thread_info = get_user_thread_info();
228 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
230 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
231 else assert( full_parent == thread_info->top_window );
232 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
233 ERR( "failed to create desktop window\n" );
235 else /* HWND_MESSAGE parent */
237 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
241 USER_Lock();
243 index = USER_HANDLE_TO_INDEX(handle);
244 assert( index < NB_USER_HANDLES );
245 user_handles[index] = win;
246 win->obj.handle = handle;
247 win->obj.type = USER_WINDOW;
248 win->parent = full_parent;
249 win->owner = full_owner;
250 win->class = class;
251 win->winproc = get_class_winproc( class );
252 win->cbWndExtra = extra_bytes;
253 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
254 return win;
258 /***********************************************************************
259 * free_window_handle
261 * Free a window handle.
263 static void free_window_handle( HWND hwnd )
265 struct user_object *ptr;
266 WORD index = USER_HANDLE_TO_INDEX(hwnd);
268 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
270 SERVER_START_REQ( destroy_window )
272 req->handle = wine_server_user_handle( hwnd );
273 if (!wine_server_call_err( req )) user_handles[index] = NULL;
274 else ptr = NULL;
276 SERVER_END_REQ;
277 release_user_handle_ptr( ptr );
278 HeapFree( GetProcessHeap(), 0, ptr );
283 /*******************************************************************
284 * list_window_children
286 * Build an array of the children of a given window. The array must be
287 * freed with HeapFree. Returns NULL when no windows are found.
289 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
291 HWND *list;
292 int i, size = 128;
293 ATOM atom = get_int_atom_value( class );
295 /* empty class is not the same as NULL class */
296 if (!atom && class && !class[0]) return NULL;
298 for (;;)
300 int count = 0;
302 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
304 SERVER_START_REQ( get_window_children )
306 req->desktop = wine_server_obj_handle( desktop );
307 req->parent = wine_server_user_handle( hwnd );
308 req->tid = tid;
309 req->atom = atom;
310 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
311 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
312 if (!wine_server_call( req )) count = reply->count;
314 SERVER_END_REQ;
315 if (count && count < size)
317 /* start from the end since HWND is potentially larger than user_handle_t */
318 for (i = count - 1; i >= 0; i--)
319 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
320 list[count] = 0;
321 return list;
323 HeapFree( GetProcessHeap(), 0, list );
324 if (!count) break;
325 size = count + 1; /* restart with a large enough buffer */
327 return NULL;
331 /*******************************************************************
332 * list_window_parents
334 * Build an array of all parents of a given window, starting with
335 * the immediate parent. The array must be freed with HeapFree.
337 static HWND *list_window_parents( HWND hwnd )
339 WND *win;
340 HWND current, *list;
341 int i, pos = 0, size = 16, count = 0;
343 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
345 current = hwnd;
346 for (;;)
348 if (!(win = WIN_GetPtr( current ))) goto empty;
349 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
350 if (win == WND_DESKTOP)
352 if (!pos) goto empty;
353 list[pos] = 0;
354 return list;
356 list[pos] = current = win->parent;
357 WIN_ReleasePtr( win );
358 if (!current) return list;
359 if (++pos == size - 1)
361 /* need to grow the list */
362 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
363 if (!new_list) goto empty;
364 list = new_list;
365 size += 16;
369 /* at least one parent belongs to another process, have to query the server */
371 for (;;)
373 count = 0;
374 SERVER_START_REQ( get_window_parents )
376 req->handle = wine_server_user_handle( hwnd );
377 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
378 if (!wine_server_call( req )) count = reply->count;
380 SERVER_END_REQ;
381 if (!count) goto empty;
382 if (size > count)
384 /* start from the end since HWND is potentially larger than user_handle_t */
385 for (i = count - 1; i >= 0; i--)
386 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
387 list[count] = 0;
388 return list;
390 HeapFree( GetProcessHeap(), 0, list );
391 size = count + 1;
392 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
395 empty:
396 HeapFree( GetProcessHeap(), 0, list );
397 return NULL;
401 /*******************************************************************
402 * send_parent_notify
404 static void send_parent_notify( HWND hwnd, UINT msg )
406 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
407 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
409 HWND parent = GetParent(hwnd);
410 if (parent && parent != GetDesktopWindow())
411 SendMessageW( parent, WM_PARENTNOTIFY,
412 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
417 /*******************************************************************
418 * get_server_window_text
420 * Retrieve the window text from the server.
422 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
424 size_t len = 0;
426 SERVER_START_REQ( get_window_text )
428 req->handle = wine_server_user_handle( hwnd );
429 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
430 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
432 SERVER_END_REQ;
433 text[len / sizeof(WCHAR)] = 0;
437 /*******************************************************************
438 * get_hwnd_message_parent
440 * Return the parent for HWND_MESSAGE windows.
442 HWND get_hwnd_message_parent(void)
444 struct user_thread_info *thread_info = get_user_thread_info();
446 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
447 return thread_info->msg_window;
451 /*******************************************************************
452 * is_desktop_window
454 * Check if window is the desktop or the HWND_MESSAGE top parent.
456 BOOL is_desktop_window( HWND hwnd )
458 struct user_thread_info *thread_info = get_user_thread_info();
460 if (!hwnd) return FALSE;
461 if (hwnd == thread_info->top_window) return TRUE;
462 if (hwnd == thread_info->msg_window) return TRUE;
464 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
466 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
467 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
469 return FALSE;
473 /***********************************************************************
474 * WIN_GetPtr
476 * Return a pointer to the WND structure if local to the process,
477 * or WND_OTHER_PROCESS if handle may be valid in other process.
478 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
480 WND *WIN_GetPtr( HWND hwnd )
482 WND *ptr;
484 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
486 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
488 return ptr;
492 /***********************************************************************
493 * WIN_IsCurrentProcess
495 * Check whether a given window belongs to the current process (and return the full handle).
497 HWND WIN_IsCurrentProcess( HWND hwnd )
499 WND *ptr;
500 HWND ret;
502 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
503 ret = ptr->obj.handle;
504 WIN_ReleasePtr( ptr );
505 return ret;
509 /***********************************************************************
510 * WIN_IsCurrentThread
512 * Check whether a given window belongs to the current thread (and return the full handle).
514 HWND WIN_IsCurrentThread( HWND hwnd )
516 WND *ptr;
517 HWND ret = 0;
519 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
520 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
521 WIN_ReleasePtr( ptr );
522 return ret;
526 /***********************************************************************
527 * WIN_GetFullHandle
529 * Convert a possibly truncated window handle to a full 32-bit handle.
531 HWND WIN_GetFullHandle( HWND hwnd )
533 WND *ptr;
535 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
536 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
537 /* do sign extension for -2 and -3 */
538 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
540 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
542 if (ptr == WND_DESKTOP)
544 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
545 else return get_hwnd_message_parent();
548 if (ptr != WND_OTHER_PROCESS)
550 hwnd = ptr->obj.handle;
551 WIN_ReleasePtr( ptr );
553 else /* may belong to another process */
555 SERVER_START_REQ( get_window_info )
557 req->handle = wine_server_user_handle( hwnd );
558 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
560 SERVER_END_REQ;
562 return hwnd;
566 /***********************************************************************
567 * WIN_SetOwner
569 * Change the owner of a window.
571 HWND WIN_SetOwner( HWND hwnd, HWND owner )
573 WND *win = WIN_GetPtr( hwnd );
574 HWND ret = 0;
576 if (!win || win == WND_DESKTOP) return 0;
577 if (win == WND_OTHER_PROCESS)
579 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
580 return 0;
582 SERVER_START_REQ( set_window_owner )
584 req->handle = wine_server_user_handle( hwnd );
585 req->owner = wine_server_user_handle( owner );
586 if (!wine_server_call( req ))
588 win->owner = wine_server_ptr_handle( reply->full_owner );
589 ret = wine_server_ptr_handle( reply->prev_owner );
592 SERVER_END_REQ;
593 WIN_ReleasePtr( win );
594 return ret;
598 /***********************************************************************
599 * WIN_SetStyle
601 * Change the style of a window.
603 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
605 BOOL ok;
606 STYLESTRUCT style;
607 WND *win = WIN_GetPtr( hwnd );
609 if (!win || win == WND_DESKTOP) return 0;
610 if (win == WND_OTHER_PROCESS)
612 if (IsWindow(hwnd))
613 ERR( "cannot set style %x/%x on other process window %p\n",
614 set_bits, clear_bits, hwnd );
615 return 0;
617 style.styleOld = win->dwStyle;
618 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
619 if (style.styleNew == style.styleOld)
621 WIN_ReleasePtr( win );
622 return style.styleNew;
624 SERVER_START_REQ( set_window_info )
626 req->handle = wine_server_user_handle( hwnd );
627 req->flags = SET_WIN_STYLE;
628 req->style = style.styleNew;
629 req->extra_offset = -1;
630 if ((ok = !wine_server_call( req )))
632 style.styleOld = reply->old_style;
633 win->dwStyle = style.styleNew;
636 SERVER_END_REQ;
637 WIN_ReleasePtr( win );
638 if (ok)
640 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
641 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
643 return style.styleOld;
647 /***********************************************************************
648 * WIN_GetRectangles
650 * Get the window and client rectangles.
652 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
654 WND *win = WIN_GetPtr( hwnd );
655 BOOL ret = TRUE;
657 if (!win)
659 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
660 return FALSE;
662 if (win == WND_DESKTOP)
664 RECT rect;
665 rect.left = rect.top = 0;
666 if (hwnd == get_hwnd_message_parent())
668 rect.right = 100;
669 rect.bottom = 100;
671 else
673 rect.right = GetSystemMetrics(SM_CXSCREEN);
674 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
676 if (rectWindow) *rectWindow = rect;
677 if (rectClient) *rectClient = rect;
679 else if (win == WND_OTHER_PROCESS)
681 SERVER_START_REQ( get_window_rectangles )
683 req->handle = wine_server_user_handle( hwnd );
684 if ((ret = !wine_server_call_err( req )))
686 if (rectWindow)
688 rectWindow->left = reply->window.left;
689 rectWindow->top = reply->window.top;
690 rectWindow->right = reply->window.right;
691 rectWindow->bottom = reply->window.bottom;
693 if (rectClient)
695 rectClient->left = reply->client.left;
696 rectClient->top = reply->client.top;
697 rectClient->right = reply->client.right;
698 rectClient->bottom = reply->client.bottom;
702 SERVER_END_REQ;
704 else
706 if (rectWindow) *rectWindow = win->rectWindow;
707 if (rectClient) *rectClient = win->rectClient;
708 WIN_ReleasePtr( win );
710 return ret;
714 /***********************************************************************
715 * WIN_DestroyWindow
717 * Destroy storage associated to a window. "Internals" p.358
719 LRESULT WIN_DestroyWindow( HWND hwnd )
721 WND *wndPtr;
722 HWND *list;
723 HMENU menu = 0, sys_menu;
724 HWND icon_title;
726 TRACE("%p\n", hwnd );
728 /* free child windows */
729 if ((list = WIN_ListChildren( hwnd )))
731 int i;
732 for (i = 0; list[i]; i++)
734 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
735 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
737 HeapFree( GetProcessHeap(), 0, list );
740 /* Unlink now so we won't bother with the children later on */
741 SERVER_START_REQ( set_parent )
743 req->handle = wine_server_user_handle( hwnd );
744 req->parent = 0;
745 wine_server_call( req );
747 SERVER_END_REQ;
750 * Send the WM_NCDESTROY to the window being destroyed.
752 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
754 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
756 /* free resources associated with the window */
758 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
759 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
760 menu = (HMENU)wndPtr->wIDmenu;
761 sys_menu = wndPtr->hSysMenu;
762 free_dce( wndPtr->dce, hwnd );
763 wndPtr->dce = NULL;
764 icon_title = wndPtr->icon_title;
765 HeapFree( GetProcessHeap(), 0, wndPtr->text );
766 wndPtr->text = NULL;
767 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
768 wndPtr->pScroll = NULL;
769 WIN_ReleasePtr( wndPtr );
771 if (icon_title) DestroyWindow( icon_title );
772 if (menu) DestroyMenu( menu );
773 if (sys_menu) DestroyMenu( sys_menu );
775 USER_Driver->pDestroyWindow( hwnd );
777 free_window_handle( hwnd );
778 return 0;
782 /***********************************************************************
783 * destroy_thread_window
785 * Destroy a window upon exit of its thread.
787 static void destroy_thread_window( HWND hwnd )
789 WND *wndPtr;
790 HWND *list;
791 HMENU menu = 0, sys_menu = 0;
792 WORD index;
794 /* free child windows */
796 if ((list = WIN_ListChildren( hwnd )))
798 int i;
799 for (i = 0; list[i]; i++)
801 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
802 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
804 HeapFree( GetProcessHeap(), 0, list );
807 /* destroy the client-side storage */
809 index = USER_HANDLE_TO_INDEX(hwnd);
810 if (index >= NB_USER_HANDLES) return;
811 USER_Lock();
812 if ((wndPtr = user_handles[index]))
814 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
815 sys_menu = wndPtr->hSysMenu;
816 free_dce( wndPtr->dce, hwnd );
817 user_handles[index] = NULL;
819 USER_Unlock();
821 HeapFree( GetProcessHeap(), 0, wndPtr );
822 if (menu) DestroyMenu( menu );
823 if (sys_menu) DestroyMenu( sys_menu );
827 /***********************************************************************
828 * destroy_thread_child_windows
830 * Destroy child windows upon exit of its thread.
832 static void destroy_thread_child_windows( HWND hwnd )
834 HWND *list;
835 int i;
837 if (WIN_IsCurrentThread( hwnd ))
839 destroy_thread_window( hwnd );
841 else if ((list = WIN_ListChildren( hwnd )))
843 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
844 HeapFree( GetProcessHeap(), 0, list );
849 /***********************************************************************
850 * WIN_DestroyThreadWindows
852 * Destroy all children of 'wnd' owned by the current thread.
854 void WIN_DestroyThreadWindows( HWND hwnd )
856 HWND *list;
857 int i;
859 if (!(list = WIN_ListChildren( hwnd ))) return;
861 /* reset owners of top-level windows */
862 for (i = 0; list[i]; i++)
864 if (!WIN_IsCurrentThread( list[i] ))
866 HWND owner = GetWindow( list[i], GW_OWNER );
867 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
871 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
872 HeapFree( GetProcessHeap(), 0, list );
876 /***********************************************************************
877 * WIN_FixCoordinates
879 * Fix the coordinates - Helper for WIN_CreateWindowEx.
880 * returns default show mode in sw.
882 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
884 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
885 POINT pos[2];
887 if (cs->dwExStyle & WS_EX_MDICHILD)
889 UINT id = 0;
891 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
892 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
894 TRACE("MDI child id %04x\n", id);
897 if (cs->style & (WS_CHILD | WS_POPUP))
899 if (cs->dwExStyle & WS_EX_MDICHILD)
901 if (IS_DEFAULT(cs->x))
903 cs->x = pos[0].x;
904 cs->y = pos[0].y;
906 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
907 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
909 else
911 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
912 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
915 else /* overlapped window */
917 HMONITOR monitor;
918 MONITORINFO mon_info;
919 STARTUPINFOW info;
921 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
923 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
924 mon_info.cbSize = sizeof(mon_info);
925 GetMonitorInfoW( monitor, &mon_info );
926 GetStartupInfoW( &info );
928 if (IS_DEFAULT(cs->x))
930 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
931 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
932 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
935 if (IS_DEFAULT(cs->cx))
937 if (info.dwFlags & STARTF_USESIZE)
939 cs->cx = info.dwXSize;
940 cs->cy = info.dwYSize;
942 else
944 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
945 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
948 /* neither x nor cx are default. Check the y values .
949 * In the trace we see Outlook and Outlook Express using
950 * cy set to CW_USEDEFAULT when opening the address book.
952 else if (IS_DEFAULT(cs->cy))
954 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
955 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
958 #undef IS_DEFAULT
961 /***********************************************************************
962 * dump_window_styles
964 static void dump_window_styles( DWORD style, DWORD exstyle )
966 TRACE( "style:" );
967 if(style & WS_POPUP) TRACE(" WS_POPUP");
968 if(style & WS_CHILD) TRACE(" WS_CHILD");
969 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
970 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
971 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
972 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
973 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
974 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
975 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
976 else
978 if(style & WS_BORDER) TRACE(" WS_BORDER");
979 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
981 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
982 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
983 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
984 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
985 if (style & WS_CHILD)
987 if(style & WS_GROUP) TRACE(" WS_GROUP");
988 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
990 else
992 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
993 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
996 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
997 #define DUMPED_STYLES \
998 (WS_POPUP | \
999 WS_CHILD | \
1000 WS_MINIMIZE | \
1001 WS_VISIBLE | \
1002 WS_DISABLED | \
1003 WS_CLIPSIBLINGS | \
1004 WS_CLIPCHILDREN | \
1005 WS_MAXIMIZE | \
1006 WS_BORDER | \
1007 WS_DLGFRAME | \
1008 WS_VSCROLL | \
1009 WS_HSCROLL | \
1010 WS_SYSMENU | \
1011 WS_THICKFRAME | \
1012 WS_GROUP | \
1013 WS_TABSTOP | \
1014 WS_MINIMIZEBOX | \
1015 WS_MAXIMIZEBOX)
1017 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1018 TRACE("\n");
1019 #undef DUMPED_STYLES
1021 TRACE( "exstyle:" );
1022 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1023 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1024 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1025 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1026 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1027 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1028 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1029 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1030 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1031 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1032 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1033 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1034 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1035 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1036 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1037 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1038 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1039 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1041 #define DUMPED_EX_STYLES \
1042 (WS_EX_DLGMODALFRAME | \
1043 WS_EX_DRAGDETECT | \
1044 WS_EX_NOPARENTNOTIFY | \
1045 WS_EX_TOPMOST | \
1046 WS_EX_ACCEPTFILES | \
1047 WS_EX_TRANSPARENT | \
1048 WS_EX_MDICHILD | \
1049 WS_EX_TOOLWINDOW | \
1050 WS_EX_WINDOWEDGE | \
1051 WS_EX_CLIENTEDGE | \
1052 WS_EX_CONTEXTHELP | \
1053 WS_EX_RIGHT | \
1054 WS_EX_RTLREADING | \
1055 WS_EX_LEFTSCROLLBAR | \
1056 WS_EX_CONTROLPARENT | \
1057 WS_EX_STATICEDGE | \
1058 WS_EX_APPWINDOW | \
1059 WS_EX_LAYERED)
1061 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1062 TRACE("\n");
1063 #undef DUMPED_EX_STYLES
1067 /***********************************************************************
1068 * WIN_CreateWindowEx
1070 * Implementation of CreateWindowEx().
1072 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1074 INT cx, cy, style, sw = SW_SHOW;
1075 LRESULT result;
1076 RECT rect;
1077 WND *wndPtr;
1078 HWND hwnd, parent, owner, top_child = 0;
1079 MDICREATESTRUCTW mdi_cs;
1080 CBT_CREATEWNDW cbtc;
1081 CREATESTRUCTW cbcs;
1083 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1084 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1085 debugstr_w(className),
1086 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1087 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1088 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1090 /* Fix the styles for MDI children */
1091 if (cs->dwExStyle & WS_EX_MDICHILD)
1093 UINT flags = 0;
1095 wndPtr = WIN_GetPtr(cs->hwndParent);
1096 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1098 flags = wndPtr->flags;
1099 WIN_ReleasePtr(wndPtr);
1102 if (!(flags & WIN_ISMDICLIENT))
1104 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1105 return 0;
1108 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1109 * MDICREATESTRUCT members have the originally passed values.
1111 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1112 * have the same layout.
1114 mdi_cs.szClass = cs->lpszClass;
1115 mdi_cs.szTitle = cs->lpszName;
1116 mdi_cs.hOwner = cs->hInstance;
1117 mdi_cs.x = cs->x;
1118 mdi_cs.y = cs->y;
1119 mdi_cs.cx = cs->cx;
1120 mdi_cs.cy = cs->cy;
1121 mdi_cs.style = cs->style;
1122 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1124 cs->lpCreateParams = &mdi_cs;
1126 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1128 if (cs->style & WS_POPUP)
1130 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1131 return 0;
1133 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1135 else
1137 cs->style &= ~WS_POPUP;
1138 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1139 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1142 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1144 if (top_child)
1146 /* Restore current maximized child */
1147 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1149 TRACE("Restoring current maximized child %p\n", top_child);
1150 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1151 ShowWindow( top_child, SW_SHOWNORMAL );
1152 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1157 /* Find the parent window */
1159 parent = cs->hwndParent;
1160 owner = 0;
1162 if (cs->hwndParent == HWND_MESSAGE)
1164 cs->hwndParent = parent = get_hwnd_message_parent();
1166 else if (cs->hwndParent)
1168 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1170 parent = GetDesktopWindow();
1171 owner = cs->hwndParent;
1174 else
1176 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1178 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1180 WARN("No parent for child window\n" );
1181 SetLastError(ERROR_TLW_WITH_WSCHILD);
1182 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1184 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1185 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1186 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1187 parent = GetDesktopWindow();
1190 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1192 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1193 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1194 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1195 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1196 else
1197 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1199 /* Create the window structure */
1201 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1202 return 0;
1203 hwnd = wndPtr->obj.handle;
1205 /* Fill the window structure */
1207 wndPtr->tid = GetCurrentThreadId();
1208 wndPtr->hInstance = cs->hInstance;
1209 wndPtr->text = NULL;
1210 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1211 wndPtr->dwExStyle = cs->dwExStyle;
1212 wndPtr->wIDmenu = 0;
1213 wndPtr->helpContext = 0;
1214 wndPtr->pScroll = NULL;
1215 wndPtr->userdata = 0;
1216 wndPtr->hIcon = 0;
1217 wndPtr->hIconSmall = 0;
1218 wndPtr->hSysMenu = 0;
1220 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1221 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1223 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1226 * Correct the window styles.
1228 * It affects only the style loaded into the WIN structure.
1231 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1233 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1234 if (!(wndPtr->dwStyle & WS_POPUP))
1235 wndPtr->dwStyle |= WS_CAPTION;
1239 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1240 * why does the user get to set it?
1243 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1244 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1245 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1246 else
1247 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1249 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1250 wndPtr->flags |= WIN_NEED_SIZE;
1252 SERVER_START_REQ( set_window_info )
1254 req->handle = wine_server_user_handle( hwnd );
1255 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1256 req->style = wndPtr->dwStyle;
1257 req->ex_style = wndPtr->dwExStyle;
1258 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1259 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1260 req->extra_offset = -1;
1261 wine_server_call( req );
1263 SERVER_END_REQ;
1265 /* Set the window menu */
1267 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1269 if (cs->hMenu)
1271 if (!MENU_SetMenu(hwnd, cs->hMenu))
1273 WIN_ReleasePtr( wndPtr );
1274 free_window_handle( hwnd );
1275 return 0;
1278 else
1280 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1281 if (menuName)
1283 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1284 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1288 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1290 /* call the WH_CBT hook */
1292 /* the window style passed to the hook must be the real window style,
1293 * rather than just the window style that the caller to CreateWindowEx
1294 * passed in, so we have to copy the original CREATESTRUCT and get the
1295 * the real style. */
1296 cbcs = *cs;
1297 cbcs.style = wndPtr->dwStyle;
1298 cbtc.lpcs = &cbcs;
1299 cbtc.hwndInsertAfter = HWND_TOP;
1300 WIN_ReleasePtr( wndPtr );
1301 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1303 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1305 cx = cs->cx;
1306 cy = cs->cy;
1307 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1309 POINT maxSize, maxPos, minTrack, maxTrack;
1310 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1311 if (maxTrack.x < cx) cx = maxTrack.x;
1312 if (maxTrack.y < cy) cy = maxTrack.y;
1313 if (minTrack.x > cx) cx = minTrack.x;
1314 if (minTrack.y > cy) cy = minTrack.y;
1317 if (cx < 0) cx = 0;
1318 if (cy < 0) cy = 0;
1319 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1320 /* check for wraparound */
1321 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1322 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1323 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1325 /* send WM_NCCREATE */
1327 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1328 if (unicode)
1329 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1330 else
1331 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1332 if (!result)
1334 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1335 goto failed;
1338 /* send WM_NCCALCSIZE */
1340 if ((wndPtr = WIN_GetPtr(hwnd)))
1342 /* yes, even if the CBT hook was called with HWND_TOP */
1343 POINT pt;
1344 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1345 RECT window_rect = wndPtr->rectWindow;
1346 RECT client_rect = window_rect;
1347 WIN_ReleasePtr( wndPtr );
1349 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1350 pt.x = pt.y = 0;
1351 MapWindowPoints( parent, 0, &pt, 1 );
1352 OffsetRect( &client_rect, pt.x, pt.y );
1353 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1354 OffsetRect( &client_rect, -pt.x, -pt.y );
1355 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1357 else return 0;
1359 /* send WM_CREATE */
1361 if (unicode)
1362 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1363 else
1364 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1365 if (result == -1) goto failed;
1367 /* call the driver */
1369 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1371 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1373 /* send the size messages */
1375 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1376 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1377 if (!(wndPtr->flags & WIN_NEED_SIZE))
1379 rect = wndPtr->rectClient;
1380 WIN_ReleasePtr( wndPtr );
1381 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1382 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1383 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1385 else WIN_ReleasePtr( wndPtr );
1387 /* Show the window, maximizing or minimizing if needed */
1389 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1390 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1392 RECT newPos;
1393 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1395 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1396 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1397 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1398 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1399 newPos.bottom - newPos.top, swFlag );
1402 /* Notify the parent window only */
1404 send_parent_notify( hwnd, WM_CREATE );
1405 if (!IsWindow( hwnd )) return 0;
1407 if (cs->style & WS_VISIBLE)
1409 if (cs->style & WS_MAXIMIZE)
1410 sw = SW_SHOW;
1411 else if (cs->style & WS_MINIMIZE)
1412 sw = SW_SHOWMINIMIZED;
1414 ShowWindow( hwnd, sw );
1415 if (cs->dwExStyle & WS_EX_MDICHILD)
1417 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1418 /* ShowWindow won't activate child windows */
1419 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1423 /* Call WH_SHELL hook */
1425 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1426 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1428 TRACE("created window %p\n", hwnd);
1429 return hwnd;
1431 failed:
1432 WIN_DestroyWindow( hwnd );
1433 return 0;
1437 /***********************************************************************
1438 * CreateWindowExA (USER32.@)
1440 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1441 LPCSTR windowName, DWORD style, INT x,
1442 INT y, INT width, INT height,
1443 HWND parent, HMENU menu,
1444 HINSTANCE instance, LPVOID data )
1446 CREATESTRUCTA cs;
1448 cs.lpCreateParams = data;
1449 cs.hInstance = instance;
1450 cs.hMenu = menu;
1451 cs.hwndParent = parent;
1452 cs.x = x;
1453 cs.y = y;
1454 cs.cx = width;
1455 cs.cy = height;
1456 cs.style = style;
1457 cs.lpszName = windowName;
1458 cs.lpszClass = className;
1459 cs.dwExStyle = exStyle;
1461 if (!IS_INTRESOURCE(className))
1463 WCHAR bufferW[256];
1464 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1465 return 0;
1466 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1468 /* Note: we rely on the fact that CREATESTRUCTA and */
1469 /* CREATESTRUCTW have the same layout. */
1470 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1474 /***********************************************************************
1475 * CreateWindowExW (USER32.@)
1477 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1478 LPCWSTR windowName, DWORD style, INT x,
1479 INT y, INT width, INT height,
1480 HWND parent, HMENU menu,
1481 HINSTANCE instance, LPVOID data )
1483 CREATESTRUCTW cs;
1485 cs.lpCreateParams = data;
1486 cs.hInstance = instance;
1487 cs.hMenu = menu;
1488 cs.hwndParent = parent;
1489 cs.x = x;
1490 cs.y = y;
1491 cs.cx = width;
1492 cs.cy = height;
1493 cs.style = style;
1494 cs.lpszName = windowName;
1495 cs.lpszClass = className;
1496 cs.dwExStyle = exStyle;
1498 return wow_handlers.create_window( &cs, className, instance, TRUE );
1502 /***********************************************************************
1503 * WIN_SendDestroyMsg
1505 static void WIN_SendDestroyMsg( HWND hwnd )
1507 GUITHREADINFO info;
1509 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1511 if (hwnd == info.hwndCaret) DestroyCaret();
1512 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1516 * Send the WM_DESTROY to the window.
1518 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1521 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1522 * make sure that the window still exists when we come back.
1524 if (IsWindow(hwnd))
1526 HWND* pWndArray;
1527 int i;
1529 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1531 for (i = 0; pWndArray[i]; i++)
1533 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1535 HeapFree( GetProcessHeap(), 0, pWndArray );
1537 else
1538 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1542 /***********************************************************************
1543 * DestroyWindow (USER32.@)
1545 BOOL WINAPI DestroyWindow( HWND hwnd )
1547 BOOL is_child;
1549 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1551 SetLastError( ERROR_ACCESS_DENIED );
1552 return FALSE;
1555 TRACE("(%p)\n", hwnd);
1557 /* Call hooks */
1559 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1561 if (MENU_IsMenuActive() == hwnd)
1562 EndMenu();
1564 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1566 if (is_child)
1568 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1569 send_parent_notify( hwnd, WM_DESTROY );
1571 else if (!GetWindow( hwnd, GW_OWNER ))
1573 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1574 /* FIXME: clean up palette - see "Internals" p.352 */
1577 if (!IsWindow(hwnd)) return TRUE;
1579 /* Hide the window */
1580 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1582 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1583 if (is_child)
1584 ShowWindow( hwnd, SW_HIDE );
1585 else
1586 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1587 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1590 if (!IsWindow(hwnd)) return TRUE;
1592 /* Recursively destroy owned windows */
1594 if (!is_child)
1596 for (;;)
1598 int i, got_one = 0;
1599 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1600 if (list)
1602 for (i = 0; list[i]; i++)
1604 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1605 if (WIN_IsCurrentThread( list[i] ))
1607 DestroyWindow( list[i] );
1608 got_one = 1;
1609 continue;
1611 WIN_SetOwner( list[i], 0 );
1613 HeapFree( GetProcessHeap(), 0, list );
1615 if (!got_one) break;
1619 /* Send destroy messages */
1621 WIN_SendDestroyMsg( hwnd );
1622 if (!IsWindow( hwnd )) return TRUE;
1624 if (GetClipboardOwner() == hwnd)
1625 CLIPBOARD_ReleaseOwner();
1627 /* Destroy the window storage */
1629 WIN_DestroyWindow( hwnd );
1630 return TRUE;
1634 /***********************************************************************
1635 * CloseWindow (USER32.@)
1637 BOOL WINAPI CloseWindow( HWND hwnd )
1639 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1640 ShowWindow( hwnd, SW_MINIMIZE );
1641 return TRUE;
1645 /***********************************************************************
1646 * OpenIcon (USER32.@)
1648 BOOL WINAPI OpenIcon( HWND hwnd )
1650 if (!IsIconic( hwnd )) return FALSE;
1651 ShowWindow( hwnd, SW_SHOWNORMAL );
1652 return TRUE;
1656 /***********************************************************************
1657 * FindWindowExW (USER32.@)
1659 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1661 HWND *list = NULL;
1662 HWND retvalue = 0;
1663 int i = 0, len = 0;
1664 WCHAR *buffer = NULL;
1666 if (!parent && child) parent = GetDesktopWindow();
1667 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1669 if (title)
1671 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1672 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1675 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1677 if (child)
1679 child = WIN_GetFullHandle( child );
1680 while (list[i] && list[i] != child) i++;
1681 if (!list[i]) goto done;
1682 i++; /* start from next window */
1685 if (title)
1687 while (list[i])
1689 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1690 i++;
1693 retvalue = list[i];
1695 done:
1696 HeapFree( GetProcessHeap(), 0, list );
1697 HeapFree( GetProcessHeap(), 0, buffer );
1698 return retvalue;
1703 /***********************************************************************
1704 * FindWindowA (USER32.@)
1706 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1708 HWND ret = FindWindowExA( 0, 0, className, title );
1709 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1710 return ret;
1714 /***********************************************************************
1715 * FindWindowExA (USER32.@)
1717 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1719 LPWSTR titleW = NULL;
1720 HWND hwnd = 0;
1722 if (title)
1724 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1725 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1726 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1729 if (!IS_INTRESOURCE(className))
1731 WCHAR classW[256];
1732 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1733 hwnd = FindWindowExW( parent, child, classW, titleW );
1735 else
1737 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1740 HeapFree( GetProcessHeap(), 0, titleW );
1741 return hwnd;
1745 /***********************************************************************
1746 * FindWindowW (USER32.@)
1748 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1750 return FindWindowExW( 0, 0, className, title );
1754 /**********************************************************************
1755 * GetDesktopWindow (USER32.@)
1757 HWND WINAPI GetDesktopWindow(void)
1759 struct user_thread_info *thread_info = get_user_thread_info();
1761 if (thread_info->top_window) return thread_info->top_window;
1763 SERVER_START_REQ( get_desktop_window )
1765 req->force = 0;
1766 if (!wine_server_call( req ))
1768 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1769 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1772 SERVER_END_REQ;
1774 if (!thread_info->top_window)
1776 USEROBJECTFLAGS flags;
1777 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1778 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1780 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1781 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1782 STARTUPINFOW si;
1783 PROCESS_INFORMATION pi;
1784 WCHAR windir[MAX_PATH];
1785 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1786 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1788 memset( &si, 0, sizeof(si) );
1789 si.cb = sizeof(si);
1790 si.dwFlags = STARTF_USESTDHANDLES;
1791 si.hStdInput = 0;
1792 si.hStdOutput = 0;
1793 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1795 GetWindowsDirectoryW( windir, MAX_PATH );
1796 strcpyW( app, windir );
1797 strcatW( app, explorer );
1798 strcpyW( cmdline, app );
1799 strcatW( cmdline, args );
1800 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1801 NULL, windir, &si, &pi ))
1803 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1804 WaitForInputIdle( pi.hProcess, 10000 );
1805 CloseHandle( pi.hThread );
1806 CloseHandle( pi.hProcess );
1808 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1810 else TRACE( "not starting explorer since winstation is not visible\n" );
1812 SERVER_START_REQ( get_desktop_window )
1814 req->force = 1;
1815 if (!wine_server_call( req ))
1817 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1818 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1821 SERVER_END_REQ;
1824 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1825 ERR( "failed to create desktop window\n" );
1827 return thread_info->top_window;
1831 /*******************************************************************
1832 * EnableWindow (USER32.@)
1834 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1836 BOOL retvalue;
1837 HWND full_handle;
1839 if (is_broadcast(hwnd))
1841 SetLastError( ERROR_INVALID_PARAMETER );
1842 return FALSE;
1845 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1846 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1848 hwnd = full_handle;
1850 TRACE("( %p, %d )\n", hwnd, enable);
1852 retvalue = !IsWindowEnabled( hwnd );
1854 if (enable && retvalue)
1856 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1857 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1859 else if (!enable && !retvalue)
1861 HWND capture_wnd;
1863 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1865 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1867 if (hwnd == GetFocus())
1868 SetFocus( 0 ); /* A disabled window can't have the focus */
1870 capture_wnd = GetCapture();
1871 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1872 ReleaseCapture(); /* A disabled window can't capture the mouse */
1874 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1876 return retvalue;
1880 /***********************************************************************
1881 * IsWindowEnabled (USER32.@)
1883 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1885 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1889 /***********************************************************************
1890 * IsWindowUnicode (USER32.@)
1892 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1894 WND * wndPtr;
1895 BOOL retvalue = FALSE;
1897 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1899 if (wndPtr == WND_DESKTOP) return TRUE;
1901 if (wndPtr != WND_OTHER_PROCESS)
1903 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1904 WIN_ReleasePtr( wndPtr );
1906 else
1908 SERVER_START_REQ( get_window_info )
1910 req->handle = wine_server_user_handle( hwnd );
1911 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1913 SERVER_END_REQ;
1915 return retvalue;
1919 /**********************************************************************
1920 * WIN_GetWindowLong
1922 * Helper function for GetWindowLong().
1924 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1926 LONG_PTR retvalue = 0;
1927 WND *wndPtr;
1929 if (offset == GWLP_HWNDPARENT)
1931 HWND parent = GetAncestor( hwnd, GA_PARENT );
1932 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1933 return (ULONG_PTR)parent;
1936 if (!(wndPtr = WIN_GetPtr( hwnd )))
1938 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1939 return 0;
1942 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1944 if (offset == GWLP_WNDPROC)
1946 SetLastError( ERROR_ACCESS_DENIED );
1947 return 0;
1949 SERVER_START_REQ( set_window_info )
1951 req->handle = wine_server_user_handle( hwnd );
1952 req->flags = 0; /* don't set anything, just retrieve */
1953 req->extra_offset = (offset >= 0) ? offset : -1;
1954 req->extra_size = (offset >= 0) ? size : 0;
1955 if (!wine_server_call_err( req ))
1957 switch(offset)
1959 case GWL_STYLE: retvalue = reply->old_style; break;
1960 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1961 case GWLP_ID: retvalue = reply->old_id; break;
1962 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1963 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1964 default:
1965 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1966 else SetLastError( ERROR_INVALID_INDEX );
1967 break;
1971 SERVER_END_REQ;
1972 return retvalue;
1975 /* now we have a valid wndPtr */
1977 if (offset >= 0)
1979 if (offset > (int)(wndPtr->cbWndExtra - size))
1981 WARN("Invalid offset %d\n", offset );
1982 WIN_ReleasePtr( wndPtr );
1983 SetLastError( ERROR_INVALID_INDEX );
1984 return 0;
1986 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1988 /* Special case for dialog window procedure */
1989 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1990 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1991 WIN_ReleasePtr( wndPtr );
1992 return retvalue;
1995 switch(offset)
1997 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1998 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1999 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2000 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2001 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2002 case GWLP_WNDPROC:
2003 /* This looks like a hack only for the edit control (see tests). This makes these controls
2004 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2005 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2007 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2008 retvalue = (ULONG_PTR)wndPtr->winproc;
2009 else
2010 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2011 break;
2012 default:
2013 WARN("Unknown offset %d\n", offset );
2014 SetLastError( ERROR_INVALID_INDEX );
2015 break;
2017 WIN_ReleasePtr(wndPtr);
2018 return retvalue;
2022 /**********************************************************************
2023 * WIN_SetWindowLong
2025 * Helper function for SetWindowLong().
2027 * 0 is the failure code. However, in the case of failure SetLastError
2028 * must be set to distinguish between a 0 return value and a failure.
2030 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2032 STYLESTRUCT style;
2033 BOOL ok;
2034 LONG_PTR retval = 0;
2035 WND *wndPtr;
2037 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2039 if (is_broadcast(hwnd))
2041 SetLastError( ERROR_INVALID_PARAMETER );
2042 return FALSE;
2045 if (!(wndPtr = WIN_GetPtr( hwnd )))
2047 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2048 return 0;
2050 if (wndPtr == WND_DESKTOP)
2052 /* can't change anything on the desktop window */
2053 SetLastError( ERROR_ACCESS_DENIED );
2054 return 0;
2056 if (wndPtr == WND_OTHER_PROCESS)
2058 if (offset == GWLP_WNDPROC)
2060 SetLastError( ERROR_ACCESS_DENIED );
2061 return 0;
2063 if (offset > 32767 || offset < -32767)
2065 SetLastError( ERROR_INVALID_INDEX );
2066 return 0;
2068 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2071 /* first some special cases */
2072 switch( offset )
2074 case GWL_STYLE:
2075 case GWL_EXSTYLE:
2076 style.styleOld =
2077 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2078 style.styleNew = newval;
2079 WIN_ReleasePtr( wndPtr );
2080 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2081 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2082 newval = style.styleNew;
2083 break;
2084 case GWLP_HWNDPARENT:
2085 if (wndPtr->parent == GetDesktopWindow())
2087 WIN_ReleasePtr( wndPtr );
2088 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2090 else
2092 WIN_ReleasePtr( wndPtr );
2093 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2095 case GWLP_WNDPROC:
2097 WNDPROC proc;
2098 UINT old_flags = wndPtr->flags;
2099 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2100 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2101 if (proc) wndPtr->winproc = proc;
2102 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2103 else wndPtr->flags &= ~WIN_ISUNICODE;
2104 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2106 WIN_ReleasePtr( wndPtr );
2107 return retval;
2109 /* update is_unicode flag on the server side */
2110 break;
2112 case GWLP_ID:
2113 case GWLP_HINSTANCE:
2114 case GWLP_USERDATA:
2115 break;
2116 case DWLP_DLGPROC:
2117 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2118 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2120 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2121 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2122 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2123 WIN_ReleasePtr( wndPtr );
2124 return retval;
2126 /* fall through */
2127 default:
2128 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2130 WARN("Invalid offset %d\n", offset );
2131 WIN_ReleasePtr( wndPtr );
2132 SetLastError( ERROR_INVALID_INDEX );
2133 return 0;
2135 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2137 /* already set to the same value */
2138 WIN_ReleasePtr( wndPtr );
2139 return newval;
2141 break;
2144 SERVER_START_REQ( set_window_info )
2146 req->handle = wine_server_user_handle( hwnd );
2147 req->extra_offset = -1;
2148 switch(offset)
2150 case GWL_STYLE:
2151 req->flags = SET_WIN_STYLE;
2152 req->style = newval;
2153 break;
2154 case GWL_EXSTYLE:
2155 req->flags = SET_WIN_EXSTYLE;
2156 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2157 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2158 req->ex_style = newval;
2159 break;
2160 case GWLP_ID:
2161 req->flags = SET_WIN_ID;
2162 req->id = newval;
2163 break;
2164 case GWLP_HINSTANCE:
2165 req->flags = SET_WIN_INSTANCE;
2166 req->instance = wine_server_client_ptr( (void *)newval );
2167 break;
2168 case GWLP_WNDPROC:
2169 req->flags = SET_WIN_UNICODE;
2170 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2171 break;
2172 case GWLP_USERDATA:
2173 req->flags = SET_WIN_USERDATA;
2174 req->user_data = newval;
2175 break;
2176 default:
2177 req->flags = SET_WIN_EXTRA;
2178 req->extra_offset = offset;
2179 req->extra_size = size;
2180 set_win_data( &req->extra_value, newval, size );
2182 if ((ok = !wine_server_call_err( req )))
2184 switch(offset)
2186 case GWL_STYLE:
2187 wndPtr->dwStyle = newval;
2188 retval = reply->old_style;
2189 break;
2190 case GWL_EXSTYLE:
2191 wndPtr->dwExStyle = newval;
2192 retval = reply->old_ex_style;
2193 break;
2194 case GWLP_ID:
2195 wndPtr->wIDmenu = newval;
2196 retval = reply->old_id;
2197 break;
2198 case GWLP_HINSTANCE:
2199 wndPtr->hInstance = (HINSTANCE)newval;
2200 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2201 break;
2202 case GWLP_WNDPROC:
2203 break;
2204 case GWLP_USERDATA:
2205 wndPtr->userdata = newval;
2206 retval = reply->old_user_data;
2207 break;
2208 default:
2209 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2210 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2211 break;
2215 SERVER_END_REQ;
2216 WIN_ReleasePtr( wndPtr );
2218 if (!ok) return 0;
2220 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2222 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2223 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2226 return retval;
2230 /**********************************************************************
2231 * GetWindowWord (USER32.@)
2233 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2235 switch(offset)
2237 case GWLP_ID:
2238 case GWLP_HINSTANCE:
2239 case GWLP_HWNDPARENT:
2240 break;
2241 default:
2242 if (offset < 0)
2244 WARN("Invalid offset %d\n", offset );
2245 SetLastError( ERROR_INVALID_INDEX );
2246 return 0;
2248 break;
2250 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2254 /**********************************************************************
2255 * GetWindowLongA (USER32.@)
2257 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2259 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2263 /**********************************************************************
2264 * GetWindowLongW (USER32.@)
2266 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2268 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2272 /**********************************************************************
2273 * SetWindowWord (USER32.@)
2275 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2277 switch(offset)
2279 case GWLP_ID:
2280 case GWLP_HINSTANCE:
2281 case GWLP_HWNDPARENT:
2282 break;
2283 default:
2284 if (offset < 0)
2286 WARN("Invalid offset %d\n", offset );
2287 SetLastError( ERROR_INVALID_INDEX );
2288 return 0;
2290 break;
2292 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2296 /**********************************************************************
2297 * SetWindowLongA (USER32.@)
2299 * See SetWindowLongW.
2301 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2303 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2307 /**********************************************************************
2308 * SetWindowLongW (USER32.@) Set window attribute
2310 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2311 * value in a window's extra memory.
2313 * The _hwnd_ parameter specifies the window. is the handle to a
2314 * window that has extra memory. The _newval_ parameter contains the
2315 * new attribute or extra memory value. If positive, the _offset_
2316 * parameter is the byte-addressed location in the window's extra
2317 * memory to set. If negative, _offset_ specifies the window
2318 * attribute to set, and should be one of the following values:
2320 * GWL_EXSTYLE The window's extended window style
2322 * GWL_STYLE The window's window style.
2324 * GWLP_WNDPROC Pointer to the window's window procedure.
2326 * GWLP_HINSTANCE The window's pplication instance handle.
2328 * GWLP_ID The window's identifier.
2330 * GWLP_USERDATA The window's user-specified data.
2332 * If the window is a dialog box, the _offset_ parameter can be one of
2333 * the following values:
2335 * DWLP_DLGPROC The address of the window's dialog box procedure.
2337 * DWLP_MSGRESULT The return value of a message
2338 * that the dialog box procedure processed.
2340 * DWLP_USER Application specific information.
2342 * RETURNS
2344 * If successful, returns the previous value located at _offset_. Otherwise,
2345 * returns 0.
2347 * NOTES
2349 * Extra memory for a window class is specified by a nonzero cbWndExtra
2350 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2351 * time of class creation.
2353 * Using GWL_WNDPROC to set a new window procedure effectively creates
2354 * a window subclass. Use CallWindowProc() in the new windows procedure
2355 * to pass messages to the superclass's window procedure.
2357 * The user data is reserved for use by the application which created
2358 * the window.
2360 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2361 * instead, call the EnableWindow() function to change the window's
2362 * disabled state.
2364 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2365 * SetParent() instead.
2367 * Win95:
2368 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2369 * it sends WM_STYLECHANGING before changing the settings
2370 * and WM_STYLECHANGED afterwards.
2371 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2373 LONG WINAPI SetWindowLongW(
2374 HWND hwnd, /* [in] window to alter */
2375 INT offset, /* [in] offset, in bytes, of location to alter */
2376 LONG newval /* [in] new value of location */
2378 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2382 /*******************************************************************
2383 * GetWindowTextA (USER32.@)
2385 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2387 WCHAR *buffer;
2389 if (!lpString) return 0;
2391 if (WIN_IsCurrentProcess( hwnd ))
2392 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2394 /* when window belongs to other process, don't send a message */
2395 if (nMaxCount <= 0) return 0;
2396 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2397 get_server_window_text( hwnd, buffer, nMaxCount );
2398 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2399 lpString[nMaxCount-1] = 0;
2400 HeapFree( GetProcessHeap(), 0, buffer );
2401 return strlen(lpString);
2405 /*******************************************************************
2406 * InternalGetWindowText (USER32.@)
2408 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2410 WND *win;
2412 if (nMaxCount <= 0) return 0;
2413 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2414 if (win == WND_DESKTOP) lpString[0] = 0;
2415 else if (win != WND_OTHER_PROCESS)
2417 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2418 else lpString[0] = 0;
2419 WIN_ReleasePtr( win );
2421 else
2423 get_server_window_text( hwnd, lpString, nMaxCount );
2425 return strlenW(lpString);
2429 /*******************************************************************
2430 * GetWindowTextW (USER32.@)
2432 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2434 if (!lpString) return 0;
2436 if (WIN_IsCurrentProcess( hwnd ))
2437 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2439 /* when window belongs to other process, don't send a message */
2440 if (nMaxCount <= 0) return 0;
2441 get_server_window_text( hwnd, lpString, nMaxCount );
2442 return strlenW(lpString);
2446 /*******************************************************************
2447 * SetWindowTextA (USER32.@)
2448 * SetWindowText (USER32.@)
2450 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2452 if (is_broadcast(hwnd))
2454 SetLastError( ERROR_INVALID_PARAMETER );
2455 return FALSE;
2457 if (!WIN_IsCurrentProcess( hwnd ))
2458 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2459 debugstr_a(lpString), hwnd );
2460 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2464 /*******************************************************************
2465 * SetWindowTextW (USER32.@)
2467 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2469 if (is_broadcast(hwnd))
2471 SetLastError( ERROR_INVALID_PARAMETER );
2472 return FALSE;
2474 if (!WIN_IsCurrentProcess( hwnd ))
2475 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2476 debugstr_w(lpString), hwnd );
2477 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2481 /*******************************************************************
2482 * GetWindowTextLengthA (USER32.@)
2484 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2486 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2489 /*******************************************************************
2490 * GetWindowTextLengthW (USER32.@)
2492 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2494 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2498 /*******************************************************************
2499 * IsWindow (USER32.@)
2501 BOOL WINAPI IsWindow( HWND hwnd )
2503 WND *ptr;
2504 BOOL ret;
2506 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2507 if (ptr == WND_DESKTOP) return TRUE;
2509 if (ptr != WND_OTHER_PROCESS)
2511 WIN_ReleasePtr( ptr );
2512 return TRUE;
2515 /* check other processes */
2516 SERVER_START_REQ( get_window_info )
2518 req->handle = wine_server_user_handle( hwnd );
2519 ret = !wine_server_call_err( req );
2521 SERVER_END_REQ;
2522 return ret;
2526 /***********************************************************************
2527 * GetWindowThreadProcessId (USER32.@)
2529 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2531 WND *ptr;
2532 DWORD tid = 0;
2534 if (!(ptr = WIN_GetPtr( hwnd )))
2536 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2537 return 0;
2540 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2542 /* got a valid window */
2543 tid = ptr->tid;
2544 if (process) *process = GetCurrentProcessId();
2545 WIN_ReleasePtr( ptr );
2546 return tid;
2549 /* check other processes */
2550 SERVER_START_REQ( get_window_info )
2552 req->handle = wine_server_user_handle( hwnd );
2553 if (!wine_server_call_err( req ))
2555 tid = (DWORD)reply->tid;
2556 if (process) *process = (DWORD)reply->pid;
2559 SERVER_END_REQ;
2560 return tid;
2564 /*****************************************************************
2565 * GetParent (USER32.@)
2567 HWND WINAPI GetParent( HWND hwnd )
2569 WND *wndPtr;
2570 HWND retvalue = 0;
2572 if (!(wndPtr = WIN_GetPtr( hwnd )))
2574 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2575 return 0;
2577 if (wndPtr == WND_DESKTOP) return 0;
2578 if (wndPtr == WND_OTHER_PROCESS)
2580 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2581 if (style & (WS_POPUP | WS_CHILD))
2583 SERVER_START_REQ( get_window_tree )
2585 req->handle = wine_server_user_handle( hwnd );
2586 if (!wine_server_call_err( req ))
2588 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2589 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2592 SERVER_END_REQ;
2595 else
2597 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2598 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2599 WIN_ReleasePtr( wndPtr );
2601 return retvalue;
2605 /*****************************************************************
2606 * GetAncestor (USER32.@)
2608 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2610 WND *win;
2611 HWND *list, ret = 0;
2613 switch(type)
2615 case GA_PARENT:
2616 if (!(win = WIN_GetPtr( hwnd )))
2618 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2619 return 0;
2621 if (win == WND_DESKTOP) return 0;
2622 if (win != WND_OTHER_PROCESS)
2624 ret = win->parent;
2625 WIN_ReleasePtr( win );
2627 else /* need to query the server */
2629 SERVER_START_REQ( get_window_tree )
2631 req->handle = wine_server_user_handle( hwnd );
2632 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2634 SERVER_END_REQ;
2636 break;
2638 case GA_ROOT:
2639 if (!(list = list_window_parents( hwnd ))) return 0;
2641 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2642 else
2644 int count = 2;
2645 while (list[count]) count++;
2646 ret = list[count - 2]; /* get the one before the desktop */
2648 HeapFree( GetProcessHeap(), 0, list );
2649 break;
2651 case GA_ROOTOWNER:
2652 if (is_desktop_window( hwnd )) return 0;
2653 ret = WIN_GetFullHandle( hwnd );
2654 for (;;)
2656 HWND parent = GetParent( ret );
2657 if (!parent) break;
2658 ret = parent;
2660 break;
2662 return ret;
2666 /*****************************************************************
2667 * SetParent (USER32.@)
2669 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2671 HWND full_handle;
2672 HWND old_parent = 0;
2673 BOOL was_visible;
2674 WND *wndPtr;
2675 BOOL ret;
2677 if (is_broadcast(hwnd) || is_broadcast(parent))
2679 SetLastError(ERROR_INVALID_PARAMETER);
2680 return 0;
2683 if (!parent) parent = GetDesktopWindow();
2684 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2685 else parent = WIN_GetFullHandle( parent );
2687 if (!IsWindow( parent ))
2689 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2690 return 0;
2693 /* Some applications try to set a child as a parent */
2694 if (IsChild(hwnd, parent))
2696 SetLastError( ERROR_INVALID_PARAMETER );
2697 return 0;
2700 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2701 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2703 /* Windows hides the window first, then shows it again
2704 * including the WM_SHOWWINDOW messages and all */
2705 was_visible = ShowWindow( hwnd, SW_HIDE );
2707 wndPtr = WIN_GetPtr( hwnd );
2708 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2710 SERVER_START_REQ( set_parent )
2712 req->handle = wine_server_user_handle( hwnd );
2713 req->parent = wine_server_user_handle( parent );
2714 if ((ret = !wine_server_call( req )))
2716 old_parent = wine_server_ptr_handle( reply->old_parent );
2717 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2721 SERVER_END_REQ;
2722 WIN_ReleasePtr( wndPtr );
2723 if (!ret) return 0;
2725 USER_Driver->pSetParent( full_handle, parent, old_parent );
2727 /* SetParent additionally needs to make hwnd the topmost window
2728 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2729 WM_WINDOWPOSCHANGED notification messages.
2731 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2732 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2733 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2734 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2736 return old_parent;
2740 /*******************************************************************
2741 * IsChild (USER32.@)
2743 BOOL WINAPI IsChild( HWND parent, HWND child )
2745 HWND *list = list_window_parents( child );
2746 int i;
2747 BOOL ret;
2749 if (!list) return FALSE;
2750 parent = WIN_GetFullHandle( parent );
2751 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2752 ret = list[i] && list[i+1];
2753 HeapFree( GetProcessHeap(), 0, list );
2754 return ret;
2758 /***********************************************************************
2759 * IsWindowVisible (USER32.@)
2761 BOOL WINAPI IsWindowVisible( HWND hwnd )
2763 HWND *list;
2764 BOOL retval = TRUE;
2765 int i;
2767 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2768 if (!(list = list_window_parents( hwnd ))) return TRUE;
2769 if (list[0])
2771 for (i = 0; list[i+1]; i++)
2772 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2773 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2775 HeapFree( GetProcessHeap(), 0, list );
2776 return retval;
2780 /***********************************************************************
2781 * WIN_IsWindowDrawable
2783 * hwnd is drawable when it is visible, all parents are not
2784 * minimized, and it is itself not minimized unless we are
2785 * trying to draw its default class icon.
2787 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2789 HWND *list;
2790 BOOL retval = TRUE;
2791 int i;
2792 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2794 if (!(style & WS_VISIBLE)) return FALSE;
2795 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2797 if (!(list = list_window_parents( hwnd ))) return TRUE;
2798 if (list[0])
2800 for (i = 0; list[i+1]; i++)
2801 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2802 break;
2803 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2805 HeapFree( GetProcessHeap(), 0, list );
2806 return retval;
2810 /*******************************************************************
2811 * GetTopWindow (USER32.@)
2813 HWND WINAPI GetTopWindow( HWND hwnd )
2815 if (!hwnd) hwnd = GetDesktopWindow();
2816 return GetWindow( hwnd, GW_CHILD );
2820 /*******************************************************************
2821 * GetWindow (USER32.@)
2823 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2825 HWND retval = 0;
2827 if (rel == GW_OWNER) /* this one may be available locally */
2829 WND *wndPtr = WIN_GetPtr( hwnd );
2830 if (!wndPtr)
2832 SetLastError( ERROR_INVALID_HANDLE );
2833 return 0;
2835 if (wndPtr == WND_DESKTOP) return 0;
2836 if (wndPtr != WND_OTHER_PROCESS)
2838 retval = wndPtr->owner;
2839 WIN_ReleasePtr( wndPtr );
2840 return retval;
2842 /* else fall through to server call */
2845 SERVER_START_REQ( get_window_tree )
2847 req->handle = wine_server_user_handle( hwnd );
2848 if (!wine_server_call_err( req ))
2850 switch(rel)
2852 case GW_HWNDFIRST:
2853 retval = wine_server_ptr_handle( reply->first_sibling );
2854 break;
2855 case GW_HWNDLAST:
2856 retval = wine_server_ptr_handle( reply->last_sibling );
2857 break;
2858 case GW_HWNDNEXT:
2859 retval = wine_server_ptr_handle( reply->next_sibling );
2860 break;
2861 case GW_HWNDPREV:
2862 retval = wine_server_ptr_handle( reply->prev_sibling );
2863 break;
2864 case GW_OWNER:
2865 retval = wine_server_ptr_handle( reply->owner );
2866 break;
2867 case GW_CHILD:
2868 retval = wine_server_ptr_handle( reply->first_child );
2869 break;
2873 SERVER_END_REQ;
2874 return retval;
2878 /*******************************************************************
2879 * ShowOwnedPopups (USER32.@)
2881 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2883 int count = 0;
2884 WND *pWnd;
2885 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2887 if (!win_array) return TRUE;
2889 while (win_array[count]) count++;
2890 while (--count >= 0)
2892 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2893 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2894 if (pWnd == WND_OTHER_PROCESS) continue;
2895 if (fShow)
2897 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2899 WIN_ReleasePtr( pWnd );
2900 /* In Windows, ShowOwnedPopups(TRUE) generates
2901 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2902 * regardless of the state of the owner
2904 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2905 continue;
2908 else
2910 if (pWnd->dwStyle & WS_VISIBLE)
2912 WIN_ReleasePtr( pWnd );
2913 /* In Windows, ShowOwnedPopups(FALSE) generates
2914 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2915 * regardless of the state of the owner
2917 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2918 continue;
2921 WIN_ReleasePtr( pWnd );
2923 HeapFree( GetProcessHeap(), 0, win_array );
2924 return TRUE;
2928 /*******************************************************************
2929 * GetLastActivePopup (USER32.@)
2931 HWND WINAPI GetLastActivePopup( HWND hwnd )
2933 HWND retval = hwnd;
2935 SERVER_START_REQ( get_window_info )
2937 req->handle = wine_server_user_handle( hwnd );
2938 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2940 SERVER_END_REQ;
2941 return retval;
2945 /*******************************************************************
2946 * WIN_ListChildren
2948 * Build an array of the children of a given window. The array must be
2949 * freed with HeapFree. Returns NULL when no windows are found.
2951 HWND *WIN_ListChildren( HWND hwnd )
2953 if (!hwnd)
2955 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2956 return NULL;
2958 return list_window_children( 0, hwnd, NULL, 0 );
2962 /*******************************************************************
2963 * EnumWindows (USER32.@)
2965 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2967 HWND *list;
2968 BOOL ret = TRUE;
2969 int i;
2971 USER_CheckNotLock();
2973 /* We have to build a list of all windows first, to avoid */
2974 /* unpleasant side-effects, for instance if the callback */
2975 /* function changes the Z-order of the windows. */
2977 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2979 /* Now call the callback function for every window */
2981 for (i = 0; list[i]; i++)
2983 /* Make sure that the window still exists */
2984 if (!IsWindow( list[i] )) continue;
2985 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2987 HeapFree( GetProcessHeap(), 0, list );
2988 return ret;
2992 /**********************************************************************
2993 * EnumThreadWindows (USER32.@)
2995 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2997 HWND *list;
2998 int i;
2999 BOOL ret = TRUE;
3001 USER_CheckNotLock();
3003 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3005 /* Now call the callback function for every window */
3007 for (i = 0; list[i]; i++)
3008 if (!(ret = func( list[i], lParam ))) break;
3009 HeapFree( GetProcessHeap(), 0, list );
3010 return ret;
3014 /***********************************************************************
3015 * EnumDesktopWindows (USER32.@)
3017 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3019 HWND *list;
3020 int i;
3022 USER_CheckNotLock();
3024 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3026 for (i = 0; list[i]; i++)
3027 if (!func( list[i], lparam )) break;
3028 HeapFree( GetProcessHeap(), 0, list );
3029 return TRUE;
3033 /**********************************************************************
3034 * WIN_EnumChildWindows
3036 * Helper function for EnumChildWindows().
3038 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3040 HWND *childList;
3041 BOOL ret = FALSE;
3043 for ( ; *list; list++)
3045 /* Make sure that the window still exists */
3046 if (!IsWindow( *list )) continue;
3047 /* Build children list first */
3048 childList = WIN_ListChildren( *list );
3050 ret = func( *list, lParam );
3052 if (childList)
3054 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3055 HeapFree( GetProcessHeap(), 0, childList );
3057 if (!ret) return FALSE;
3059 return TRUE;
3063 /**********************************************************************
3064 * EnumChildWindows (USER32.@)
3066 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3068 HWND *list;
3069 BOOL ret;
3071 USER_CheckNotLock();
3073 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3074 ret = WIN_EnumChildWindows( list, func, lParam );
3075 HeapFree( GetProcessHeap(), 0, list );
3076 return ret;
3080 /*******************************************************************
3081 * AnyPopup (USER32.@)
3083 BOOL WINAPI AnyPopup(void)
3085 int i;
3086 BOOL retvalue;
3087 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3089 if (!list) return FALSE;
3090 for (i = 0; list[i]; i++)
3092 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3094 retvalue = (list[i] != 0);
3095 HeapFree( GetProcessHeap(), 0, list );
3096 return retvalue;
3100 /*******************************************************************
3101 * FlashWindow (USER32.@)
3103 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3105 WND *wndPtr;
3107 TRACE("%p\n", hWnd);
3109 if (IsIconic( hWnd ))
3111 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3113 wndPtr = WIN_GetPtr(hWnd);
3114 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3115 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3117 wndPtr->flags |= WIN_NCACTIVATED;
3119 else
3121 wndPtr->flags &= ~WIN_NCACTIVATED;
3123 WIN_ReleasePtr( wndPtr );
3124 return TRUE;
3126 else
3128 WPARAM wparam;
3130 wndPtr = WIN_GetPtr(hWnd);
3131 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3132 hWnd = wndPtr->obj.handle; /* make it a full handle */
3134 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3135 else wparam = (hWnd == GetForegroundWindow());
3137 WIN_ReleasePtr( wndPtr );
3138 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3139 return wparam;
3143 /*******************************************************************
3144 * FlashWindowEx (USER32.@)
3146 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3148 FIXME("%p\n", pfwi);
3149 return TRUE;
3152 /*******************************************************************
3153 * GetWindowContextHelpId (USER32.@)
3155 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3157 DWORD retval;
3158 WND *wnd = WIN_GetPtr( hwnd );
3159 if (!wnd || wnd == WND_DESKTOP) return 0;
3160 if (wnd == WND_OTHER_PROCESS)
3162 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3163 return 0;
3165 retval = wnd->helpContext;
3166 WIN_ReleasePtr( wnd );
3167 return retval;
3171 /*******************************************************************
3172 * SetWindowContextHelpId (USER32.@)
3174 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3176 WND *wnd = WIN_GetPtr( hwnd );
3177 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3178 if (wnd == WND_OTHER_PROCESS)
3180 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3181 return 0;
3183 wnd->helpContext = id;
3184 WIN_ReleasePtr( wnd );
3185 return TRUE;
3189 /*******************************************************************
3190 * DragDetect (USER32.@)
3192 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3194 MSG msg;
3195 RECT rect;
3196 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3197 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3199 rect.left = pt.x - wDragWidth;
3200 rect.right = pt.x + wDragWidth;
3202 rect.top = pt.y - wDragHeight;
3203 rect.bottom = pt.y + wDragHeight;
3205 SetCapture(hWnd);
3207 while(1)
3209 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3211 if( msg.message == WM_LBUTTONUP )
3213 ReleaseCapture();
3214 return 0;
3216 if( msg.message == WM_MOUSEMOVE )
3218 POINT tmp;
3219 tmp.x = (short)LOWORD(msg.lParam);
3220 tmp.y = (short)HIWORD(msg.lParam);
3221 if( !PtInRect( &rect, tmp ))
3223 ReleaseCapture();
3224 return 1;
3228 WaitMessage();
3230 return 0;
3233 /******************************************************************************
3234 * GetWindowModuleFileNameA (USER32.@)
3236 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3238 WND *win;
3239 HINSTANCE hinst;
3241 TRACE( "%p, %p, %u\n", hwnd, module, size );
3243 win = WIN_GetPtr( hwnd );
3244 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3246 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3247 return 0;
3249 hinst = win->hInstance;
3250 WIN_ReleasePtr( win );
3252 return GetModuleFileNameA( hinst, module, size );
3255 /******************************************************************************
3256 * GetWindowModuleFileNameW (USER32.@)
3258 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3260 WND *win;
3261 HINSTANCE hinst;
3263 TRACE( "%p, %p, %u\n", hwnd, module, size );
3265 win = WIN_GetPtr( hwnd );
3266 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3268 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3269 return 0;
3271 hinst = win->hInstance;
3272 WIN_ReleasePtr( win );
3274 return GetModuleFileNameW( hinst, module, size );
3277 /******************************************************************************
3278 * GetWindowInfo (USER32.@)
3280 * Note: tests show that Windows doesn't check cbSize of the structure.
3282 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3284 if (!pwi) return FALSE;
3285 if (!IsWindow(hwnd)) return FALSE;
3287 GetWindowRect(hwnd, &pwi->rcWindow);
3288 GetClientRect(hwnd, &pwi->rcClient);
3289 /* translate to screen coordinates */
3290 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3292 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3293 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3294 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3296 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3297 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3299 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3300 pwi->wCreatorVersion = 0x0400;
3302 return TRUE;
3305 /******************************************************************************
3306 * SwitchDesktop (USER32.@)
3308 * NOTES: Sets the current input or interactive desktop.
3310 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3312 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3313 return TRUE;
3316 /*****************************************************************************
3317 * SetLayeredWindowAttributes (USER32.@)
3319 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3321 BOOL ret;
3323 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3325 SERVER_START_REQ( set_window_layered_info )
3327 req->handle = wine_server_user_handle( hwnd );
3328 req->color_key = key;
3329 req->alpha = alpha;
3330 req->flags = flags;
3331 ret = !wine_server_call_err( req );
3333 SERVER_END_REQ;
3335 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3337 return ret;
3341 /*****************************************************************************
3342 * GetLayeredWindowAttributes (USER32.@)
3344 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3346 BOOL ret;
3348 SERVER_START_REQ( get_window_layered_info )
3350 req->handle = wine_server_user_handle( hwnd );
3351 if ((ret = !wine_server_call_err( req )))
3353 if (key) *key = reply->color_key;
3354 if (alpha) *alpha = reply->alpha;
3355 if (flags) *flags = reply->flags;
3358 SERVER_END_REQ;
3360 return ret;
3364 /*****************************************************************************
3365 * UpdateLayeredWindowIndirect (USER32.@)
3367 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3369 BYTE alpha = 0xff;
3371 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3373 int x = 0, y = 0, cx = 0, cy = 0;
3374 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3376 if (info->pptDst)
3378 x = info->pptDst->x;
3379 y = info->pptDst->y;
3380 flags &= ~SWP_NOMOVE;
3382 if (info->psize)
3384 cx = info->psize->cx;
3385 cy = info->psize->cy;
3386 flags &= ~SWP_NOSIZE;
3388 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3389 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3392 if (info->hdcSrc)
3394 RECT rect;
3395 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3397 if (hdc)
3399 int x = 0, y = 0;
3401 GetClientRect( hwnd, &rect );
3402 if (info->pptSrc)
3404 x = info->pptSrc->x;
3405 y = info->pptSrc->y;
3407 /* FIXME: intersect rect with info->prcDirty */
3408 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3409 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3410 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3411 ReleaseDC( hwnd, hdc );
3415 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3416 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3417 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3418 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3419 return TRUE;
3423 /*****************************************************************************
3424 * UpdateLayeredWindow (USER32.@)
3426 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3427 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3428 DWORD dwFlags)
3430 UPDATELAYEREDWINDOWINFO info;
3432 info.cbSize = sizeof(info);
3433 info.hdcDst = hdcDst;
3434 info.pptDst = pptDst;
3435 info.psize = psize;
3436 info.hdcSrc = hdcSrc;
3437 info.pptSrc = pptSrc;
3438 info.crKey = crKey;
3439 info.pblend = pblend;
3440 info.dwFlags = dwFlags;
3441 info.prcDirty = NULL;
3442 return UpdateLayeredWindowIndirect( hwnd, &info );
3445 /* 64bit versions */
3447 #ifdef GetWindowLongPtrW
3448 #undef GetWindowLongPtrW
3449 #endif
3451 #ifdef GetWindowLongPtrA
3452 #undef GetWindowLongPtrA
3453 #endif
3455 #ifdef SetWindowLongPtrW
3456 #undef SetWindowLongPtrW
3457 #endif
3459 #ifdef SetWindowLongPtrA
3460 #undef SetWindowLongPtrA
3461 #endif
3463 /*****************************************************************************
3464 * GetWindowLongPtrW (USER32.@)
3466 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3468 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3471 /*****************************************************************************
3472 * GetWindowLongPtrA (USER32.@)
3474 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3476 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3479 /*****************************************************************************
3480 * SetWindowLongPtrW (USER32.@)
3482 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3484 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3487 /*****************************************************************************
3488 * SetWindowLongPtrA (USER32.@)
3490 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3492 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );