comctl32: Also generate an alpha channel when replacing an image or icon in an imagelist.
[wine/multimedia.git] / dlls / user32 / win.c
blob74ea0b358916cf7410d1c0d89c55ec34d460d7b8
1 /*
2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "controls.h"
35 #include "winerror.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(win);
40 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
41 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
43 /**********************************************************************/
45 /* helper for Get/SetWindowLong */
46 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
48 if (size == sizeof(WORD))
50 WORD ret;
51 memcpy( &ret, ptr, sizeof(ret) );
52 return ret;
54 else if (size == sizeof(DWORD))
56 DWORD ret;
57 memcpy( &ret, ptr, sizeof(ret) );
58 return ret;
60 else
62 LONG_PTR ret;
63 memcpy( &ret, ptr, sizeof(ret) );
64 return ret;
68 /* helper for Get/SetWindowLong */
69 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
71 if (size == sizeof(WORD))
73 WORD newval = val;
74 memcpy( ptr, &newval, sizeof(newval) );
76 else if (size == sizeof(DWORD))
78 DWORD newval = val;
79 memcpy( ptr, &newval, sizeof(newval) );
81 else
83 memcpy( ptr, &val, sizeof(val) );
88 static void *user_handles[NB_USER_HANDLES];
90 /***********************************************************************
91 * alloc_user_handle
93 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
95 HANDLE handle = 0;
97 SERVER_START_REQ( alloc_user_handle )
99 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
101 SERVER_END_REQ;
103 if (handle)
105 UINT index = USER_HANDLE_TO_INDEX( handle );
107 assert( index < NB_USER_HANDLES );
108 ptr->handle = handle;
109 ptr->type = type;
110 user_handles[index] = ptr;
112 return handle;
116 /***********************************************************************
117 * get_user_handle_ptr
119 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
121 struct user_object *ptr;
122 WORD index = USER_HANDLE_TO_INDEX( handle );
124 if (index >= NB_USER_HANDLES) return NULL;
126 USER_Lock();
127 if ((ptr = user_handles[index]))
129 if (ptr->type == type &&
130 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
131 !HIWORD(handle) || HIWORD(handle) == 0xffff))
132 return ptr;
133 ptr = NULL;
135 else ptr = OBJ_OTHER_PROCESS;
136 USER_Unlock();
137 return ptr;
141 /***********************************************************************
142 * release_user_handle_ptr
144 void release_user_handle_ptr( void *ptr )
146 assert( ptr && ptr != OBJ_OTHER_PROCESS );
147 USER_Unlock();
151 /***********************************************************************
152 * free_user_handle
154 void *free_user_handle( HANDLE handle, enum user_obj_type type )
156 struct user_object *ptr;
157 WORD index = USER_HANDLE_TO_INDEX( handle );
159 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
161 SERVER_START_REQ( free_user_handle )
163 req->handle = wine_server_user_handle( handle );
164 if (!wine_server_call( req )) user_handles[index] = NULL;
165 else ptr = NULL;
167 SERVER_END_REQ;
168 release_user_handle_ptr( ptr );
170 return ptr;
174 /***********************************************************************
175 * create_window_handle
177 * Create a window handle with the server.
179 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
180 HINSTANCE instance, BOOL unicode )
182 WORD index;
183 WND *win;
184 HWND handle = 0, full_parent = 0, full_owner = 0;
185 struct tagCLASS *class = NULL;
186 int extra_bytes = 0;
188 SERVER_START_REQ( create_window )
190 req->parent = wine_server_user_handle( parent );
191 req->owner = wine_server_user_handle( owner );
192 req->instance = wine_server_client_ptr( instance );
193 if (!(req->atom = get_int_atom_value( name )) && name)
194 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
195 if (!wine_server_call_err( req ))
197 handle = wine_server_ptr_handle( reply->handle );
198 full_parent = wine_server_ptr_handle( reply->parent );
199 full_owner = wine_server_ptr_handle( reply->owner );
200 extra_bytes = reply->extra;
201 class = wine_server_get_ptr( reply->class_ptr );
204 SERVER_END_REQ;
206 if (!handle)
208 WARN( "error %d creating window\n", GetLastError() );
209 return NULL;
212 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
213 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
215 SERVER_START_REQ( destroy_window )
217 req->handle = wine_server_user_handle( handle );
218 wine_server_call( req );
220 SERVER_END_REQ;
221 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
222 return NULL;
225 if (!parent) /* if parent is 0 we don't have a desktop window yet */
227 struct user_thread_info *thread_info = get_user_thread_info();
229 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
231 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
232 else assert( full_parent == thread_info->top_window );
233 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
234 ERR( "failed to create desktop window\n" );
236 else /* HWND_MESSAGE parent */
238 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
242 USER_Lock();
244 index = USER_HANDLE_TO_INDEX(handle);
245 assert( index < NB_USER_HANDLES );
246 user_handles[index] = win;
247 win->obj.handle = handle;
248 win->obj.type = USER_WINDOW;
249 win->parent = full_parent;
250 win->owner = full_owner;
251 win->class = class;
252 win->winproc = get_class_winproc( class );
253 win->cbWndExtra = extra_bytes;
254 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
255 return win;
259 /***********************************************************************
260 * free_window_handle
262 * Free a window handle.
264 static void free_window_handle( HWND hwnd )
266 struct user_object *ptr;
267 WORD index = USER_HANDLE_TO_INDEX(hwnd);
269 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
271 SERVER_START_REQ( destroy_window )
273 req->handle = wine_server_user_handle( hwnd );
274 if (!wine_server_call_err( req )) user_handles[index] = NULL;
275 else ptr = NULL;
277 SERVER_END_REQ;
278 release_user_handle_ptr( ptr );
279 HeapFree( GetProcessHeap(), 0, ptr );
284 /*******************************************************************
285 * list_window_children
287 * Build an array of the children of a given window. The array must be
288 * freed with HeapFree. Returns NULL when no windows are found.
290 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
292 HWND *list;
293 int i, size = 128;
294 ATOM atom = get_int_atom_value( class );
296 /* empty class is not the same as NULL class */
297 if (!atom && class && !class[0]) return NULL;
299 for (;;)
301 int count = 0;
303 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
305 SERVER_START_REQ( get_window_children )
307 req->desktop = wine_server_obj_handle( desktop );
308 req->parent = wine_server_user_handle( hwnd );
309 req->tid = tid;
310 req->atom = atom;
311 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
312 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
313 if (!wine_server_call( req )) count = reply->count;
315 SERVER_END_REQ;
316 if (count && count < size)
318 /* start from the end since HWND is potentially larger than user_handle_t */
319 for (i = count - 1; i >= 0; i--)
320 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
321 list[count] = 0;
322 return list;
324 HeapFree( GetProcessHeap(), 0, list );
325 if (!count) break;
326 size = count + 1; /* restart with a large enough buffer */
328 return NULL;
332 /*******************************************************************
333 * list_window_parents
335 * Build an array of all parents of a given window, starting with
336 * the immediate parent. The array must be freed with HeapFree.
338 static HWND *list_window_parents( HWND hwnd )
340 WND *win;
341 HWND current, *list;
342 int i, pos = 0, size = 16, count = 0;
344 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
346 current = hwnd;
347 for (;;)
349 if (!(win = WIN_GetPtr( current ))) goto empty;
350 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
351 if (win == WND_DESKTOP)
353 if (!pos) goto empty;
354 list[pos] = 0;
355 return list;
357 list[pos] = current = win->parent;
358 WIN_ReleasePtr( win );
359 if (!current) return list;
360 if (++pos == size - 1)
362 /* need to grow the list */
363 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
364 if (!new_list) goto empty;
365 list = new_list;
366 size += 16;
370 /* at least one parent belongs to another process, have to query the server */
372 for (;;)
374 count = 0;
375 SERVER_START_REQ( get_window_parents )
377 req->handle = wine_server_user_handle( hwnd );
378 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
379 if (!wine_server_call( req )) count = reply->count;
381 SERVER_END_REQ;
382 if (!count) goto empty;
383 if (size > count)
385 /* start from the end since HWND is potentially larger than user_handle_t */
386 for (i = count - 1; i >= 0; i--)
387 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
388 list[count] = 0;
389 return list;
391 HeapFree( GetProcessHeap(), 0, list );
392 size = count + 1;
393 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
396 empty:
397 HeapFree( GetProcessHeap(), 0, list );
398 return NULL;
402 /*******************************************************************
403 * send_parent_notify
405 static void send_parent_notify( HWND hwnd, UINT msg )
407 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
408 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
410 HWND parent = GetParent(hwnd);
411 if (parent && parent != GetDesktopWindow())
412 SendMessageW( parent, WM_PARENTNOTIFY,
413 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
418 /*******************************************************************
419 * get_server_window_text
421 * Retrieve the window text from the server.
423 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
425 size_t len = 0;
427 SERVER_START_REQ( get_window_text )
429 req->handle = wine_server_user_handle( hwnd );
430 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
431 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
433 SERVER_END_REQ;
434 text[len / sizeof(WCHAR)] = 0;
438 /*******************************************************************
439 * get_hwnd_message_parent
441 * Return the parent for HWND_MESSAGE windows.
443 HWND get_hwnd_message_parent(void)
445 struct user_thread_info *thread_info = get_user_thread_info();
447 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
448 return thread_info->msg_window;
452 /*******************************************************************
453 * is_desktop_window
455 * Check if window is the desktop or the HWND_MESSAGE top parent.
457 BOOL is_desktop_window( HWND hwnd )
459 struct user_thread_info *thread_info = get_user_thread_info();
461 if (!hwnd) return FALSE;
462 if (hwnd == thread_info->top_window) return TRUE;
463 if (hwnd == thread_info->msg_window) return TRUE;
465 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
467 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
468 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
470 return FALSE;
474 /***********************************************************************
475 * WIN_GetPtr
477 * Return a pointer to the WND structure if local to the process,
478 * or WND_OTHER_PROCESS if handle may be valid in other process.
479 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
481 WND *WIN_GetPtr( HWND hwnd )
483 WND *ptr;
485 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
487 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
489 return ptr;
493 /***********************************************************************
494 * WIN_IsCurrentProcess
496 * Check whether a given window belongs to the current process (and return the full handle).
498 HWND WIN_IsCurrentProcess( HWND hwnd )
500 WND *ptr;
501 HWND ret;
503 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
504 ret = ptr->obj.handle;
505 WIN_ReleasePtr( ptr );
506 return ret;
510 /***********************************************************************
511 * WIN_IsCurrentThread
513 * Check whether a given window belongs to the current thread (and return the full handle).
515 HWND WIN_IsCurrentThread( HWND hwnd )
517 WND *ptr;
518 HWND ret = 0;
520 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
521 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
522 WIN_ReleasePtr( ptr );
523 return ret;
527 /***********************************************************************
528 * WIN_GetFullHandle
530 * Convert a possibly truncated window handle to a full 32-bit handle.
532 HWND WIN_GetFullHandle( HWND hwnd )
534 WND *ptr;
536 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
537 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
538 /* do sign extension for -2 and -3 */
539 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
541 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
543 if (ptr == WND_DESKTOP)
545 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
546 else return get_hwnd_message_parent();
549 if (ptr != WND_OTHER_PROCESS)
551 hwnd = ptr->obj.handle;
552 WIN_ReleasePtr( ptr );
554 else /* may belong to another process */
556 SERVER_START_REQ( get_window_info )
558 req->handle = wine_server_user_handle( hwnd );
559 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
561 SERVER_END_REQ;
563 return hwnd;
567 /***********************************************************************
568 * WIN_SetOwner
570 * Change the owner of a window.
572 HWND WIN_SetOwner( HWND hwnd, HWND owner )
574 WND *win = WIN_GetPtr( hwnd );
575 HWND ret = 0;
577 if (!win || win == WND_DESKTOP) return 0;
578 if (win == WND_OTHER_PROCESS)
580 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
581 return 0;
583 SERVER_START_REQ( set_window_owner )
585 req->handle = wine_server_user_handle( hwnd );
586 req->owner = wine_server_user_handle( owner );
587 if (!wine_server_call( req ))
589 win->owner = wine_server_ptr_handle( reply->full_owner );
590 ret = wine_server_ptr_handle( reply->prev_owner );
593 SERVER_END_REQ;
594 WIN_ReleasePtr( win );
595 return ret;
599 /***********************************************************************
600 * WIN_SetStyle
602 * Change the style of a window.
604 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
606 BOOL ok;
607 STYLESTRUCT style;
608 WND *win = WIN_GetPtr( hwnd );
610 if (!win || win == WND_DESKTOP) return 0;
611 if (win == WND_OTHER_PROCESS)
613 if (IsWindow(hwnd))
614 ERR( "cannot set style %x/%x on other process window %p\n",
615 set_bits, clear_bits, hwnd );
616 return 0;
618 style.styleOld = win->dwStyle;
619 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
620 if (style.styleNew == style.styleOld)
622 WIN_ReleasePtr( win );
623 return style.styleNew;
625 SERVER_START_REQ( set_window_info )
627 req->handle = wine_server_user_handle( hwnd );
628 req->flags = SET_WIN_STYLE;
629 req->style = style.styleNew;
630 req->extra_offset = -1;
631 if ((ok = !wine_server_call( req )))
633 style.styleOld = reply->old_style;
634 win->dwStyle = style.styleNew;
637 SERVER_END_REQ;
638 WIN_ReleasePtr( win );
639 if (ok)
641 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
642 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
644 return style.styleOld;
648 /***********************************************************************
649 * WIN_GetRectangles
651 * Get the window and client rectangles.
653 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
655 WND *win = WIN_GetPtr( hwnd );
656 BOOL ret = TRUE;
658 if (!win)
660 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
661 return FALSE;
663 if (win == WND_DESKTOP)
665 RECT rect;
666 rect.left = rect.top = 0;
667 if (hwnd == get_hwnd_message_parent())
669 rect.right = 100;
670 rect.bottom = 100;
672 else
674 rect.right = GetSystemMetrics(SM_CXSCREEN);
675 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
677 if (rectWindow) *rectWindow = rect;
678 if (rectClient) *rectClient = rect;
680 else if (win == WND_OTHER_PROCESS)
682 SERVER_START_REQ( get_window_rectangles )
684 req->handle = wine_server_user_handle( hwnd );
685 if ((ret = !wine_server_call_err( req )))
687 if (rectWindow)
689 rectWindow->left = reply->window.left;
690 rectWindow->top = reply->window.top;
691 rectWindow->right = reply->window.right;
692 rectWindow->bottom = reply->window.bottom;
694 if (rectClient)
696 rectClient->left = reply->client.left;
697 rectClient->top = reply->client.top;
698 rectClient->right = reply->client.right;
699 rectClient->bottom = reply->client.bottom;
703 SERVER_END_REQ;
705 else
707 if (rectWindow) *rectWindow = win->rectWindow;
708 if (rectClient) *rectClient = win->rectClient;
709 WIN_ReleasePtr( win );
711 return ret;
715 /***********************************************************************
716 * WIN_DestroyWindow
718 * Destroy storage associated to a window. "Internals" p.358
720 LRESULT WIN_DestroyWindow( HWND hwnd )
722 WND *wndPtr;
723 HWND *list;
724 HMENU menu = 0, sys_menu;
725 HWND icon_title;
727 TRACE("%p\n", hwnd );
729 /* free child windows */
730 if ((list = WIN_ListChildren( hwnd )))
732 int i;
733 for (i = 0; list[i]; i++)
735 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
736 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
738 HeapFree( GetProcessHeap(), 0, list );
741 /* Unlink now so we won't bother with the children later on */
742 SERVER_START_REQ( set_parent )
744 req->handle = wine_server_user_handle( hwnd );
745 req->parent = 0;
746 wine_server_call( req );
748 SERVER_END_REQ;
751 * Send the WM_NCDESTROY to the window being destroyed.
753 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
755 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
757 /* free resources associated with the window */
759 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
760 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
761 menu = (HMENU)wndPtr->wIDmenu;
762 sys_menu = wndPtr->hSysMenu;
763 free_dce( wndPtr->dce, hwnd );
764 wndPtr->dce = NULL;
765 icon_title = wndPtr->icon_title;
766 HeapFree( GetProcessHeap(), 0, wndPtr->text );
767 wndPtr->text = NULL;
768 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
769 wndPtr->pScroll = NULL;
770 WIN_ReleasePtr( wndPtr );
772 if (icon_title) DestroyWindow( icon_title );
773 if (menu) DestroyMenu( menu );
774 if (sys_menu) DestroyMenu( sys_menu );
776 USER_Driver->pDestroyWindow( hwnd );
778 free_window_handle( hwnd );
779 return 0;
783 /***********************************************************************
784 * destroy_thread_window
786 * Destroy a window upon exit of its thread.
788 static void destroy_thread_window( HWND hwnd )
790 WND *wndPtr;
791 HWND *list;
792 HMENU menu = 0, sys_menu = 0;
793 WORD index;
795 /* free child windows */
797 if ((list = WIN_ListChildren( hwnd )))
799 int i;
800 for (i = 0; list[i]; i++)
802 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
803 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
805 HeapFree( GetProcessHeap(), 0, list );
808 /* destroy the client-side storage */
810 index = USER_HANDLE_TO_INDEX(hwnd);
811 if (index >= NB_USER_HANDLES) return;
812 USER_Lock();
813 if ((wndPtr = user_handles[index]))
815 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
816 sys_menu = wndPtr->hSysMenu;
817 free_dce( wndPtr->dce, hwnd );
818 user_handles[index] = NULL;
820 USER_Unlock();
822 HeapFree( GetProcessHeap(), 0, wndPtr );
823 if (menu) DestroyMenu( menu );
824 if (sys_menu) DestroyMenu( sys_menu );
828 /***********************************************************************
829 * destroy_thread_child_windows
831 * Destroy child windows upon exit of its thread.
833 static void destroy_thread_child_windows( HWND hwnd )
835 HWND *list;
836 int i;
838 if (WIN_IsCurrentThread( hwnd ))
840 destroy_thread_window( hwnd );
842 else if ((list = WIN_ListChildren( hwnd )))
844 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
845 HeapFree( GetProcessHeap(), 0, list );
850 /***********************************************************************
851 * WIN_DestroyThreadWindows
853 * Destroy all children of 'wnd' owned by the current thread.
855 void WIN_DestroyThreadWindows( HWND hwnd )
857 HWND *list;
858 int i;
860 if (!(list = WIN_ListChildren( hwnd ))) return;
862 /* reset owners of top-level windows */
863 for (i = 0; list[i]; i++)
865 if (!WIN_IsCurrentThread( list[i] ))
867 HWND owner = GetWindow( list[i], GW_OWNER );
868 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
872 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
873 HeapFree( GetProcessHeap(), 0, list );
877 /***********************************************************************
878 * WIN_FixCoordinates
880 * Fix the coordinates - Helper for WIN_CreateWindowEx.
881 * returns default show mode in sw.
883 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
885 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
886 POINT pos[2];
888 if (cs->dwExStyle & WS_EX_MDICHILD)
890 UINT id = 0;
892 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
893 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
895 TRACE("MDI child id %04x\n", id);
898 if (cs->style & (WS_CHILD | WS_POPUP))
900 if (cs->dwExStyle & WS_EX_MDICHILD)
902 if (IS_DEFAULT(cs->x))
904 cs->x = pos[0].x;
905 cs->y = pos[0].y;
907 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
908 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
910 else
912 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
913 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
916 else /* overlapped window */
918 HMONITOR monitor;
919 MONITORINFO mon_info;
920 STARTUPINFOW info;
922 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
924 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
925 mon_info.cbSize = sizeof(mon_info);
926 GetMonitorInfoW( monitor, &mon_info );
927 GetStartupInfoW( &info );
929 if (IS_DEFAULT(cs->x))
931 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
932 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
933 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
936 if (IS_DEFAULT(cs->cx))
938 if (info.dwFlags & STARTF_USESIZE)
940 cs->cx = info.dwXSize;
941 cs->cy = info.dwYSize;
943 else
945 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
946 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
949 /* neither x nor cx are default. Check the y values .
950 * In the trace we see Outlook and Outlook Express using
951 * cy set to CW_USEDEFAULT when opening the address book.
953 else if (IS_DEFAULT(cs->cy))
955 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
956 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
959 #undef IS_DEFAULT
962 /***********************************************************************
963 * dump_window_styles
965 static void dump_window_styles( DWORD style, DWORD exstyle )
967 TRACE( "style:" );
968 if(style & WS_POPUP) TRACE(" WS_POPUP");
969 if(style & WS_CHILD) TRACE(" WS_CHILD");
970 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
971 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
972 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
973 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
974 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
975 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
976 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
977 else
979 if(style & WS_BORDER) TRACE(" WS_BORDER");
980 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
982 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
983 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
984 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
985 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
986 if (style & WS_CHILD)
988 if(style & WS_GROUP) TRACE(" WS_GROUP");
989 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
991 else
993 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
994 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
997 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
998 #define DUMPED_STYLES \
999 (WS_POPUP | \
1000 WS_CHILD | \
1001 WS_MINIMIZE | \
1002 WS_VISIBLE | \
1003 WS_DISABLED | \
1004 WS_CLIPSIBLINGS | \
1005 WS_CLIPCHILDREN | \
1006 WS_MAXIMIZE | \
1007 WS_BORDER | \
1008 WS_DLGFRAME | \
1009 WS_VSCROLL | \
1010 WS_HSCROLL | \
1011 WS_SYSMENU | \
1012 WS_THICKFRAME | \
1013 WS_GROUP | \
1014 WS_TABSTOP | \
1015 WS_MINIMIZEBOX | \
1016 WS_MAXIMIZEBOX)
1018 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1019 TRACE("\n");
1020 #undef DUMPED_STYLES
1022 TRACE( "exstyle:" );
1023 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1024 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1025 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1026 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1027 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1028 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1029 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1030 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1031 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1032 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1033 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1034 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1035 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1036 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1037 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1038 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1039 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1040 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1042 #define DUMPED_EX_STYLES \
1043 (WS_EX_DLGMODALFRAME | \
1044 WS_EX_DRAGDETECT | \
1045 WS_EX_NOPARENTNOTIFY | \
1046 WS_EX_TOPMOST | \
1047 WS_EX_ACCEPTFILES | \
1048 WS_EX_TRANSPARENT | \
1049 WS_EX_MDICHILD | \
1050 WS_EX_TOOLWINDOW | \
1051 WS_EX_WINDOWEDGE | \
1052 WS_EX_CLIENTEDGE | \
1053 WS_EX_CONTEXTHELP | \
1054 WS_EX_RIGHT | \
1055 WS_EX_RTLREADING | \
1056 WS_EX_LEFTSCROLLBAR | \
1057 WS_EX_CONTROLPARENT | \
1058 WS_EX_STATICEDGE | \
1059 WS_EX_APPWINDOW | \
1060 WS_EX_LAYERED)
1062 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1063 TRACE("\n");
1064 #undef DUMPED_EX_STYLES
1068 /***********************************************************************
1069 * WIN_CreateWindowEx
1071 * Implementation of CreateWindowEx().
1073 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1075 INT cx, cy, style, sw = SW_SHOW;
1076 LRESULT result;
1077 RECT rect;
1078 WND *wndPtr;
1079 HWND hwnd, parent, owner, top_child = 0;
1080 MDICREATESTRUCTW mdi_cs;
1081 CBT_CREATEWNDW cbtc;
1082 CREATESTRUCTW cbcs;
1084 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1085 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1086 debugstr_w(className),
1087 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1088 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1089 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1091 /* Fix the styles for MDI children */
1092 if (cs->dwExStyle & WS_EX_MDICHILD)
1094 UINT flags = 0;
1096 wndPtr = WIN_GetPtr(cs->hwndParent);
1097 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1099 flags = wndPtr->flags;
1100 WIN_ReleasePtr(wndPtr);
1103 if (!(flags & WIN_ISMDICLIENT))
1105 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1106 return 0;
1109 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1110 * MDICREATESTRUCT members have the originally passed values.
1112 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1113 * have the same layout.
1115 mdi_cs.szClass = cs->lpszClass;
1116 mdi_cs.szTitle = cs->lpszName;
1117 mdi_cs.hOwner = cs->hInstance;
1118 mdi_cs.x = cs->x;
1119 mdi_cs.y = cs->y;
1120 mdi_cs.cx = cs->cx;
1121 mdi_cs.cy = cs->cy;
1122 mdi_cs.style = cs->style;
1123 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1125 cs->lpCreateParams = &mdi_cs;
1127 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1129 if (cs->style & WS_POPUP)
1131 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1132 return 0;
1134 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1136 else
1138 cs->style &= ~WS_POPUP;
1139 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1140 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1143 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1145 if (top_child)
1147 /* Restore current maximized child */
1148 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1150 TRACE("Restoring current maximized child %p\n", top_child);
1151 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1152 ShowWindow( top_child, SW_SHOWNORMAL );
1153 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1158 /* Find the parent window */
1160 parent = cs->hwndParent;
1161 owner = 0;
1163 if (cs->hwndParent == HWND_MESSAGE)
1165 cs->hwndParent = parent = get_hwnd_message_parent();
1167 else if (cs->hwndParent)
1169 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1171 parent = GetDesktopWindow();
1172 owner = cs->hwndParent;
1175 else
1177 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1179 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1181 WARN("No parent for child window\n" );
1182 SetLastError(ERROR_TLW_WITH_WSCHILD);
1183 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1185 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1186 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1187 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1188 parent = GetDesktopWindow();
1191 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1193 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1194 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1195 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1196 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1197 else
1198 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1200 /* Create the window structure */
1202 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1203 return 0;
1204 hwnd = wndPtr->obj.handle;
1206 /* Fill the window structure */
1208 wndPtr->tid = GetCurrentThreadId();
1209 wndPtr->hInstance = cs->hInstance;
1210 wndPtr->text = NULL;
1211 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1212 wndPtr->dwExStyle = cs->dwExStyle;
1213 wndPtr->wIDmenu = 0;
1214 wndPtr->helpContext = 0;
1215 wndPtr->pScroll = NULL;
1216 wndPtr->userdata = 0;
1217 wndPtr->hIcon = 0;
1218 wndPtr->hIconSmall = 0;
1219 wndPtr->hSysMenu = 0;
1221 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1222 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1224 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1227 * Correct the window styles.
1229 * It affects only the style loaded into the WIN structure.
1232 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1234 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1235 if (!(wndPtr->dwStyle & WS_POPUP))
1236 wndPtr->dwStyle |= WS_CAPTION;
1240 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1241 * why does the user get to set it?
1244 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1245 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1246 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1247 else
1248 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1250 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1251 wndPtr->flags |= WIN_NEED_SIZE;
1253 SERVER_START_REQ( set_window_info )
1255 req->handle = wine_server_user_handle( hwnd );
1256 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1257 req->style = wndPtr->dwStyle;
1258 req->ex_style = wndPtr->dwExStyle;
1259 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1260 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1261 req->extra_offset = -1;
1262 wine_server_call( req );
1264 SERVER_END_REQ;
1266 /* Set the window menu */
1268 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1270 if (cs->hMenu)
1272 if (!MENU_SetMenu(hwnd, cs->hMenu))
1274 WIN_ReleasePtr( wndPtr );
1275 free_window_handle( hwnd );
1276 return 0;
1279 else
1281 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1282 if (menuName)
1284 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1285 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1289 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1291 /* call the WH_CBT hook */
1293 /* the window style passed to the hook must be the real window style,
1294 * rather than just the window style that the caller to CreateWindowEx
1295 * passed in, so we have to copy the original CREATESTRUCT and get the
1296 * the real style. */
1297 cbcs = *cs;
1298 cbcs.style = wndPtr->dwStyle;
1299 cbtc.lpcs = &cbcs;
1300 cbtc.hwndInsertAfter = HWND_TOP;
1301 WIN_ReleasePtr( wndPtr );
1302 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1304 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1306 cx = cs->cx;
1307 cy = cs->cy;
1308 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1310 POINT maxSize, maxPos, minTrack, maxTrack;
1311 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1312 if (maxTrack.x < cx) cx = maxTrack.x;
1313 if (maxTrack.y < cy) cy = maxTrack.y;
1314 if (minTrack.x > cx) cx = minTrack.x;
1315 if (minTrack.y > cy) cy = minTrack.y;
1318 if (cx < 0) cx = 0;
1319 if (cy < 0) cy = 0;
1320 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1321 /* check for wraparound */
1322 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1323 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1324 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1326 /* send WM_NCCREATE */
1328 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1329 if (unicode)
1330 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1331 else
1332 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1333 if (!result)
1335 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1336 goto failed;
1339 /* send WM_NCCALCSIZE */
1341 if ((wndPtr = WIN_GetPtr(hwnd)))
1343 /* yes, even if the CBT hook was called with HWND_TOP */
1344 POINT pt;
1345 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1346 RECT window_rect = wndPtr->rectWindow;
1347 RECT client_rect = window_rect;
1348 WIN_ReleasePtr( wndPtr );
1350 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1351 pt.x = pt.y = 0;
1352 MapWindowPoints( parent, 0, &pt, 1 );
1353 OffsetRect( &client_rect, pt.x, pt.y );
1354 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1355 OffsetRect( &client_rect, -pt.x, -pt.y );
1356 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1358 else return 0;
1360 /* send WM_CREATE */
1362 if (unicode)
1363 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1364 else
1365 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1366 if (result == -1) goto failed;
1368 /* call the driver */
1370 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1372 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1374 /* send the size messages */
1376 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1377 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1378 if (!(wndPtr->flags & WIN_NEED_SIZE))
1380 rect = wndPtr->rectClient;
1381 WIN_ReleasePtr( wndPtr );
1382 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1383 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1384 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1386 else WIN_ReleasePtr( wndPtr );
1388 /* Show the window, maximizing or minimizing if needed */
1390 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1391 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1393 RECT newPos;
1394 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1396 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1397 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1398 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1399 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1400 newPos.bottom - newPos.top, swFlag );
1403 /* Notify the parent window only */
1405 send_parent_notify( hwnd, WM_CREATE );
1406 if (!IsWindow( hwnd )) return 0;
1408 if (cs->style & WS_VISIBLE)
1410 if (cs->style & WS_MAXIMIZE)
1411 sw = SW_SHOW;
1412 else if (cs->style & WS_MINIMIZE)
1413 sw = SW_SHOWMINIMIZED;
1415 ShowWindow( hwnd, sw );
1416 if (cs->dwExStyle & WS_EX_MDICHILD)
1418 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1419 /* ShowWindow won't activate child windows */
1420 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1424 /* Call WH_SHELL hook */
1426 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1427 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1429 TRACE("created window %p\n", hwnd);
1430 return hwnd;
1432 failed:
1433 WIN_DestroyWindow( hwnd );
1434 return 0;
1438 /***********************************************************************
1439 * CreateWindowExA (USER32.@)
1441 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1442 LPCSTR windowName, DWORD style, INT x,
1443 INT y, INT width, INT height,
1444 HWND parent, HMENU menu,
1445 HINSTANCE instance, LPVOID data )
1447 CREATESTRUCTA cs;
1449 cs.lpCreateParams = data;
1450 cs.hInstance = instance;
1451 cs.hMenu = menu;
1452 cs.hwndParent = parent;
1453 cs.x = x;
1454 cs.y = y;
1455 cs.cx = width;
1456 cs.cy = height;
1457 cs.style = style;
1458 cs.lpszName = windowName;
1459 cs.lpszClass = className;
1460 cs.dwExStyle = exStyle;
1462 if (!IS_INTRESOURCE(className))
1464 WCHAR bufferW[256];
1465 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1466 return 0;
1467 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1469 /* Note: we rely on the fact that CREATESTRUCTA and */
1470 /* CREATESTRUCTW have the same layout. */
1471 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1475 /***********************************************************************
1476 * CreateWindowExW (USER32.@)
1478 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1479 LPCWSTR windowName, DWORD style, INT x,
1480 INT y, INT width, INT height,
1481 HWND parent, HMENU menu,
1482 HINSTANCE instance, LPVOID data )
1484 CREATESTRUCTW cs;
1486 cs.lpCreateParams = data;
1487 cs.hInstance = instance;
1488 cs.hMenu = menu;
1489 cs.hwndParent = parent;
1490 cs.x = x;
1491 cs.y = y;
1492 cs.cx = width;
1493 cs.cy = height;
1494 cs.style = style;
1495 cs.lpszName = windowName;
1496 cs.lpszClass = className;
1497 cs.dwExStyle = exStyle;
1499 return wow_handlers.create_window( &cs, className, instance, TRUE );
1503 /***********************************************************************
1504 * WIN_SendDestroyMsg
1506 static void WIN_SendDestroyMsg( HWND hwnd )
1508 GUITHREADINFO info;
1510 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1512 if (hwnd == info.hwndCaret) DestroyCaret();
1513 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1517 * Send the WM_DESTROY to the window.
1519 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1522 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1523 * make sure that the window still exists when we come back.
1525 if (IsWindow(hwnd))
1527 HWND* pWndArray;
1528 int i;
1530 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1532 for (i = 0; pWndArray[i]; i++)
1534 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1536 HeapFree( GetProcessHeap(), 0, pWndArray );
1538 else
1539 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1543 /***********************************************************************
1544 * DestroyWindow (USER32.@)
1546 BOOL WINAPI DestroyWindow( HWND hwnd )
1548 BOOL is_child;
1550 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1552 SetLastError( ERROR_ACCESS_DENIED );
1553 return FALSE;
1556 TRACE("(%p)\n", hwnd);
1558 /* Call hooks */
1560 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1562 if (MENU_IsMenuActive() == hwnd)
1563 EndMenu();
1565 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1567 if (is_child)
1569 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1570 send_parent_notify( hwnd, WM_DESTROY );
1572 else if (!GetWindow( hwnd, GW_OWNER ))
1574 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1575 /* FIXME: clean up palette - see "Internals" p.352 */
1578 if (!IsWindow(hwnd)) return TRUE;
1580 /* Hide the window */
1581 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1583 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1584 if (is_child)
1585 ShowWindow( hwnd, SW_HIDE );
1586 else
1587 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1588 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1591 if (!IsWindow(hwnd)) return TRUE;
1593 /* Recursively destroy owned windows */
1595 if (!is_child)
1597 for (;;)
1599 int i, got_one = 0;
1600 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1601 if (list)
1603 for (i = 0; list[i]; i++)
1605 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1606 if (WIN_IsCurrentThread( list[i] ))
1608 DestroyWindow( list[i] );
1609 got_one = 1;
1610 continue;
1612 WIN_SetOwner( list[i], 0 );
1614 HeapFree( GetProcessHeap(), 0, list );
1616 if (!got_one) break;
1620 /* Send destroy messages */
1622 WIN_SendDestroyMsg( hwnd );
1623 if (!IsWindow( hwnd )) return TRUE;
1625 if (GetClipboardOwner() == hwnd)
1626 CLIPBOARD_ReleaseOwner();
1628 /* Destroy the window storage */
1630 WIN_DestroyWindow( hwnd );
1631 return TRUE;
1635 /***********************************************************************
1636 * CloseWindow (USER32.@)
1638 BOOL WINAPI CloseWindow( HWND hwnd )
1640 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1641 ShowWindow( hwnd, SW_MINIMIZE );
1642 return TRUE;
1646 /***********************************************************************
1647 * OpenIcon (USER32.@)
1649 BOOL WINAPI OpenIcon( HWND hwnd )
1651 if (!IsIconic( hwnd )) return FALSE;
1652 ShowWindow( hwnd, SW_SHOWNORMAL );
1653 return TRUE;
1657 /***********************************************************************
1658 * FindWindowExW (USER32.@)
1660 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1662 HWND *list = NULL;
1663 HWND retvalue = 0;
1664 int i = 0, len = 0;
1665 WCHAR *buffer = NULL;
1667 if (!parent && child) parent = GetDesktopWindow();
1668 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1670 if (title)
1672 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1673 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1676 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1678 if (child)
1680 child = WIN_GetFullHandle( child );
1681 while (list[i] && list[i] != child) i++;
1682 if (!list[i]) goto done;
1683 i++; /* start from next window */
1686 if (title)
1688 while (list[i])
1690 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1691 i++;
1694 retvalue = list[i];
1696 done:
1697 HeapFree( GetProcessHeap(), 0, list );
1698 HeapFree( GetProcessHeap(), 0, buffer );
1699 return retvalue;
1704 /***********************************************************************
1705 * FindWindowA (USER32.@)
1707 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1709 HWND ret = FindWindowExA( 0, 0, className, title );
1710 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1711 return ret;
1715 /***********************************************************************
1716 * FindWindowExA (USER32.@)
1718 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1720 LPWSTR titleW = NULL;
1721 HWND hwnd = 0;
1723 if (title)
1725 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1726 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1727 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1730 if (!IS_INTRESOURCE(className))
1732 WCHAR classW[256];
1733 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1734 hwnd = FindWindowExW( parent, child, classW, titleW );
1736 else
1738 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1741 HeapFree( GetProcessHeap(), 0, titleW );
1742 return hwnd;
1746 /***********************************************************************
1747 * FindWindowW (USER32.@)
1749 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1751 return FindWindowExW( 0, 0, className, title );
1755 /**********************************************************************
1756 * GetDesktopWindow (USER32.@)
1758 HWND WINAPI GetDesktopWindow(void)
1760 struct user_thread_info *thread_info = get_user_thread_info();
1762 if (thread_info->top_window) return thread_info->top_window;
1764 SERVER_START_REQ( get_desktop_window )
1766 req->force = 0;
1767 if (!wine_server_call( req ))
1769 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1770 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1773 SERVER_END_REQ;
1775 if (!thread_info->top_window)
1777 USEROBJECTFLAGS flags;
1778 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1779 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1781 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1782 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1783 STARTUPINFOW si;
1784 PROCESS_INFORMATION pi;
1785 WCHAR windir[MAX_PATH];
1786 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1787 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1788 void *redir;
1790 memset( &si, 0, sizeof(si) );
1791 si.cb = sizeof(si);
1792 si.dwFlags = STARTF_USESTDHANDLES;
1793 si.hStdInput = 0;
1794 si.hStdOutput = 0;
1795 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1797 GetSystemDirectoryW( windir, MAX_PATH );
1798 strcpyW( app, windir );
1799 strcatW( app, explorer );
1800 strcpyW( cmdline, app );
1801 strcatW( cmdline, args );
1803 Wow64DisableWow64FsRedirection( &redir );
1804 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1805 NULL, windir, &si, &pi ))
1807 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1808 WaitForInputIdle( pi.hProcess, 10000 );
1809 CloseHandle( pi.hThread );
1810 CloseHandle( pi.hProcess );
1812 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1813 Wow64RevertWow64FsRedirection( redir );
1815 else TRACE( "not starting explorer since winstation is not visible\n" );
1817 SERVER_START_REQ( get_desktop_window )
1819 req->force = 1;
1820 if (!wine_server_call( req ))
1822 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1823 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1826 SERVER_END_REQ;
1829 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1830 ERR( "failed to create desktop window\n" );
1832 return thread_info->top_window;
1836 /*******************************************************************
1837 * EnableWindow (USER32.@)
1839 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1841 BOOL retvalue;
1842 HWND full_handle;
1844 if (is_broadcast(hwnd))
1846 SetLastError( ERROR_INVALID_PARAMETER );
1847 return FALSE;
1850 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1851 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1853 hwnd = full_handle;
1855 TRACE("( %p, %d )\n", hwnd, enable);
1857 retvalue = !IsWindowEnabled( hwnd );
1859 if (enable && retvalue)
1861 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1862 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1864 else if (!enable && !retvalue)
1866 HWND capture_wnd;
1868 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1870 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1872 if (hwnd == GetFocus())
1873 SetFocus( 0 ); /* A disabled window can't have the focus */
1875 capture_wnd = GetCapture();
1876 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1877 ReleaseCapture(); /* A disabled window can't capture the mouse */
1879 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1881 return retvalue;
1885 /***********************************************************************
1886 * IsWindowEnabled (USER32.@)
1888 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1890 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1894 /***********************************************************************
1895 * IsWindowUnicode (USER32.@)
1897 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1899 WND * wndPtr;
1900 BOOL retvalue = FALSE;
1902 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1904 if (wndPtr == WND_DESKTOP) return TRUE;
1906 if (wndPtr != WND_OTHER_PROCESS)
1908 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1909 WIN_ReleasePtr( wndPtr );
1911 else
1913 SERVER_START_REQ( get_window_info )
1915 req->handle = wine_server_user_handle( hwnd );
1916 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1918 SERVER_END_REQ;
1920 return retvalue;
1924 /**********************************************************************
1925 * WIN_GetWindowLong
1927 * Helper function for GetWindowLong().
1929 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1931 LONG_PTR retvalue = 0;
1932 WND *wndPtr;
1934 if (offset == GWLP_HWNDPARENT)
1936 HWND parent = GetAncestor( hwnd, GA_PARENT );
1937 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1938 return (ULONG_PTR)parent;
1941 if (!(wndPtr = WIN_GetPtr( hwnd )))
1943 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1944 return 0;
1947 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1949 if (offset == GWLP_WNDPROC)
1951 SetLastError( ERROR_ACCESS_DENIED );
1952 return 0;
1954 SERVER_START_REQ( set_window_info )
1956 req->handle = wine_server_user_handle( hwnd );
1957 req->flags = 0; /* don't set anything, just retrieve */
1958 req->extra_offset = (offset >= 0) ? offset : -1;
1959 req->extra_size = (offset >= 0) ? size : 0;
1960 if (!wine_server_call_err( req ))
1962 switch(offset)
1964 case GWL_STYLE: retvalue = reply->old_style; break;
1965 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1966 case GWLP_ID: retvalue = reply->old_id; break;
1967 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1968 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1969 default:
1970 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1971 else SetLastError( ERROR_INVALID_INDEX );
1972 break;
1976 SERVER_END_REQ;
1977 return retvalue;
1980 /* now we have a valid wndPtr */
1982 if (offset >= 0)
1984 if (offset > (int)(wndPtr->cbWndExtra - size))
1986 WARN("Invalid offset %d\n", offset );
1987 WIN_ReleasePtr( wndPtr );
1988 SetLastError( ERROR_INVALID_INDEX );
1989 return 0;
1991 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1993 /* Special case for dialog window procedure */
1994 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1995 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1996 WIN_ReleasePtr( wndPtr );
1997 return retvalue;
2000 switch(offset)
2002 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2003 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2004 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2005 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2006 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2007 case GWLP_WNDPROC:
2008 /* This looks like a hack only for the edit control (see tests). This makes these controls
2009 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2010 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2012 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2013 retvalue = (ULONG_PTR)wndPtr->winproc;
2014 else
2015 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2016 break;
2017 default:
2018 WARN("Unknown offset %d\n", offset );
2019 SetLastError( ERROR_INVALID_INDEX );
2020 break;
2022 WIN_ReleasePtr(wndPtr);
2023 return retvalue;
2027 /**********************************************************************
2028 * WIN_SetWindowLong
2030 * Helper function for SetWindowLong().
2032 * 0 is the failure code. However, in the case of failure SetLastError
2033 * must be set to distinguish between a 0 return value and a failure.
2035 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2037 STYLESTRUCT style;
2038 BOOL ok;
2039 LONG_PTR retval = 0;
2040 WND *wndPtr;
2042 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2044 if (is_broadcast(hwnd))
2046 SetLastError( ERROR_INVALID_PARAMETER );
2047 return FALSE;
2050 if (!(wndPtr = WIN_GetPtr( hwnd )))
2052 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2053 return 0;
2055 if (wndPtr == WND_DESKTOP)
2057 /* can't change anything on the desktop window */
2058 SetLastError( ERROR_ACCESS_DENIED );
2059 return 0;
2061 if (wndPtr == WND_OTHER_PROCESS)
2063 if (offset == GWLP_WNDPROC)
2065 SetLastError( ERROR_ACCESS_DENIED );
2066 return 0;
2068 if (offset > 32767 || offset < -32767)
2070 SetLastError( ERROR_INVALID_INDEX );
2071 return 0;
2073 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2076 /* first some special cases */
2077 switch( offset )
2079 case GWL_STYLE:
2080 case GWL_EXSTYLE:
2081 style.styleOld =
2082 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2083 style.styleNew = newval;
2084 WIN_ReleasePtr( wndPtr );
2085 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2086 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2087 newval = style.styleNew;
2088 break;
2089 case GWLP_HWNDPARENT:
2090 if (wndPtr->parent == GetDesktopWindow())
2092 WIN_ReleasePtr( wndPtr );
2093 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2095 else
2097 WIN_ReleasePtr( wndPtr );
2098 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2100 case GWLP_WNDPROC:
2102 WNDPROC proc;
2103 UINT old_flags = wndPtr->flags;
2104 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2105 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2106 if (proc) wndPtr->winproc = proc;
2107 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2108 else wndPtr->flags &= ~WIN_ISUNICODE;
2109 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2111 WIN_ReleasePtr( wndPtr );
2112 return retval;
2114 /* update is_unicode flag on the server side */
2115 break;
2117 case GWLP_ID:
2118 case GWLP_HINSTANCE:
2119 case GWLP_USERDATA:
2120 break;
2121 case DWLP_DLGPROC:
2122 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2123 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2125 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2126 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2127 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2128 WIN_ReleasePtr( wndPtr );
2129 return retval;
2131 /* fall through */
2132 default:
2133 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2135 WARN("Invalid offset %d\n", offset );
2136 WIN_ReleasePtr( wndPtr );
2137 SetLastError( ERROR_INVALID_INDEX );
2138 return 0;
2140 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2142 /* already set to the same value */
2143 WIN_ReleasePtr( wndPtr );
2144 return newval;
2146 break;
2149 SERVER_START_REQ( set_window_info )
2151 req->handle = wine_server_user_handle( hwnd );
2152 req->extra_offset = -1;
2153 switch(offset)
2155 case GWL_STYLE:
2156 req->flags = SET_WIN_STYLE;
2157 req->style = newval;
2158 break;
2159 case GWL_EXSTYLE:
2160 req->flags = SET_WIN_EXSTYLE;
2161 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2162 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2163 req->ex_style = newval;
2164 break;
2165 case GWLP_ID:
2166 req->flags = SET_WIN_ID;
2167 req->id = newval;
2168 break;
2169 case GWLP_HINSTANCE:
2170 req->flags = SET_WIN_INSTANCE;
2171 req->instance = wine_server_client_ptr( (void *)newval );
2172 break;
2173 case GWLP_WNDPROC:
2174 req->flags = SET_WIN_UNICODE;
2175 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2176 break;
2177 case GWLP_USERDATA:
2178 req->flags = SET_WIN_USERDATA;
2179 req->user_data = newval;
2180 break;
2181 default:
2182 req->flags = SET_WIN_EXTRA;
2183 req->extra_offset = offset;
2184 req->extra_size = size;
2185 set_win_data( &req->extra_value, newval, size );
2187 if ((ok = !wine_server_call_err( req )))
2189 switch(offset)
2191 case GWL_STYLE:
2192 wndPtr->dwStyle = newval;
2193 retval = reply->old_style;
2194 break;
2195 case GWL_EXSTYLE:
2196 wndPtr->dwExStyle = newval;
2197 retval = reply->old_ex_style;
2198 break;
2199 case GWLP_ID:
2200 wndPtr->wIDmenu = newval;
2201 retval = reply->old_id;
2202 break;
2203 case GWLP_HINSTANCE:
2204 wndPtr->hInstance = (HINSTANCE)newval;
2205 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2206 break;
2207 case GWLP_WNDPROC:
2208 break;
2209 case GWLP_USERDATA:
2210 wndPtr->userdata = newval;
2211 retval = reply->old_user_data;
2212 break;
2213 default:
2214 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2215 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2216 break;
2220 SERVER_END_REQ;
2221 WIN_ReleasePtr( wndPtr );
2223 if (!ok) return 0;
2225 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2227 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2228 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2231 return retval;
2235 /**********************************************************************
2236 * GetWindowWord (USER32.@)
2238 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2240 switch(offset)
2242 case GWLP_ID:
2243 case GWLP_HINSTANCE:
2244 case GWLP_HWNDPARENT:
2245 break;
2246 default:
2247 if (offset < 0)
2249 WARN("Invalid offset %d\n", offset );
2250 SetLastError( ERROR_INVALID_INDEX );
2251 return 0;
2253 break;
2255 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2259 /**********************************************************************
2260 * GetWindowLongA (USER32.@)
2262 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2264 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2268 /**********************************************************************
2269 * GetWindowLongW (USER32.@)
2271 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2273 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2277 /**********************************************************************
2278 * SetWindowWord (USER32.@)
2280 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2282 switch(offset)
2284 case GWLP_ID:
2285 case GWLP_HINSTANCE:
2286 case GWLP_HWNDPARENT:
2287 break;
2288 default:
2289 if (offset < 0)
2291 WARN("Invalid offset %d\n", offset );
2292 SetLastError( ERROR_INVALID_INDEX );
2293 return 0;
2295 break;
2297 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2301 /**********************************************************************
2302 * SetWindowLongA (USER32.@)
2304 * See SetWindowLongW.
2306 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2308 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2312 /**********************************************************************
2313 * SetWindowLongW (USER32.@) Set window attribute
2315 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2316 * value in a window's extra memory.
2318 * The _hwnd_ parameter specifies the window. is the handle to a
2319 * window that has extra memory. The _newval_ parameter contains the
2320 * new attribute or extra memory value. If positive, the _offset_
2321 * parameter is the byte-addressed location in the window's extra
2322 * memory to set. If negative, _offset_ specifies the window
2323 * attribute to set, and should be one of the following values:
2325 * GWL_EXSTYLE The window's extended window style
2327 * GWL_STYLE The window's window style.
2329 * GWLP_WNDPROC Pointer to the window's window procedure.
2331 * GWLP_HINSTANCE The window's pplication instance handle.
2333 * GWLP_ID The window's identifier.
2335 * GWLP_USERDATA The window's user-specified data.
2337 * If the window is a dialog box, the _offset_ parameter can be one of
2338 * the following values:
2340 * DWLP_DLGPROC The address of the window's dialog box procedure.
2342 * DWLP_MSGRESULT The return value of a message
2343 * that the dialog box procedure processed.
2345 * DWLP_USER Application specific information.
2347 * RETURNS
2349 * If successful, returns the previous value located at _offset_. Otherwise,
2350 * returns 0.
2352 * NOTES
2354 * Extra memory for a window class is specified by a nonzero cbWndExtra
2355 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2356 * time of class creation.
2358 * Using GWL_WNDPROC to set a new window procedure effectively creates
2359 * a window subclass. Use CallWindowProc() in the new windows procedure
2360 * to pass messages to the superclass's window procedure.
2362 * The user data is reserved for use by the application which created
2363 * the window.
2365 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2366 * instead, call the EnableWindow() function to change the window's
2367 * disabled state.
2369 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2370 * SetParent() instead.
2372 * Win95:
2373 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2374 * it sends WM_STYLECHANGING before changing the settings
2375 * and WM_STYLECHANGED afterwards.
2376 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2378 LONG WINAPI SetWindowLongW(
2379 HWND hwnd, /* [in] window to alter */
2380 INT offset, /* [in] offset, in bytes, of location to alter */
2381 LONG newval /* [in] new value of location */
2383 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2387 /*******************************************************************
2388 * GetWindowTextA (USER32.@)
2390 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2392 WCHAR *buffer;
2394 if (!lpString) return 0;
2396 if (WIN_IsCurrentProcess( hwnd ))
2397 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2399 /* when window belongs to other process, don't send a message */
2400 if (nMaxCount <= 0) return 0;
2401 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2402 get_server_window_text( hwnd, buffer, nMaxCount );
2403 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2404 lpString[nMaxCount-1] = 0;
2405 HeapFree( GetProcessHeap(), 0, buffer );
2406 return strlen(lpString);
2410 /*******************************************************************
2411 * InternalGetWindowText (USER32.@)
2413 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2415 WND *win;
2417 if (nMaxCount <= 0) return 0;
2418 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2419 if (win == WND_DESKTOP) lpString[0] = 0;
2420 else if (win != WND_OTHER_PROCESS)
2422 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2423 else lpString[0] = 0;
2424 WIN_ReleasePtr( win );
2426 else
2428 get_server_window_text( hwnd, lpString, nMaxCount );
2430 return strlenW(lpString);
2434 /*******************************************************************
2435 * GetWindowTextW (USER32.@)
2437 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2439 if (!lpString) return 0;
2441 if (WIN_IsCurrentProcess( hwnd ))
2442 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2444 /* when window belongs to other process, don't send a message */
2445 if (nMaxCount <= 0) return 0;
2446 get_server_window_text( hwnd, lpString, nMaxCount );
2447 return strlenW(lpString);
2451 /*******************************************************************
2452 * SetWindowTextA (USER32.@)
2453 * SetWindowText (USER32.@)
2455 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2457 if (is_broadcast(hwnd))
2459 SetLastError( ERROR_INVALID_PARAMETER );
2460 return FALSE;
2462 if (!WIN_IsCurrentProcess( hwnd ))
2463 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2464 debugstr_a(lpString), hwnd );
2465 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2469 /*******************************************************************
2470 * SetWindowTextW (USER32.@)
2472 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2474 if (is_broadcast(hwnd))
2476 SetLastError( ERROR_INVALID_PARAMETER );
2477 return FALSE;
2479 if (!WIN_IsCurrentProcess( hwnd ))
2480 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2481 debugstr_w(lpString), hwnd );
2482 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2486 /*******************************************************************
2487 * GetWindowTextLengthA (USER32.@)
2489 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2491 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2494 /*******************************************************************
2495 * GetWindowTextLengthW (USER32.@)
2497 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2499 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2503 /*******************************************************************
2504 * IsWindow (USER32.@)
2506 BOOL WINAPI IsWindow( HWND hwnd )
2508 WND *ptr;
2509 BOOL ret;
2511 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2512 if (ptr == WND_DESKTOP) return TRUE;
2514 if (ptr != WND_OTHER_PROCESS)
2516 WIN_ReleasePtr( ptr );
2517 return TRUE;
2520 /* check other processes */
2521 SERVER_START_REQ( get_window_info )
2523 req->handle = wine_server_user_handle( hwnd );
2524 ret = !wine_server_call_err( req );
2526 SERVER_END_REQ;
2527 return ret;
2531 /***********************************************************************
2532 * GetWindowThreadProcessId (USER32.@)
2534 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2536 WND *ptr;
2537 DWORD tid = 0;
2539 if (!(ptr = WIN_GetPtr( hwnd )))
2541 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2542 return 0;
2545 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2547 /* got a valid window */
2548 tid = ptr->tid;
2549 if (process) *process = GetCurrentProcessId();
2550 WIN_ReleasePtr( ptr );
2551 return tid;
2554 /* check other processes */
2555 SERVER_START_REQ( get_window_info )
2557 req->handle = wine_server_user_handle( hwnd );
2558 if (!wine_server_call_err( req ))
2560 tid = (DWORD)reply->tid;
2561 if (process) *process = (DWORD)reply->pid;
2564 SERVER_END_REQ;
2565 return tid;
2569 /*****************************************************************
2570 * GetParent (USER32.@)
2572 HWND WINAPI GetParent( HWND hwnd )
2574 WND *wndPtr;
2575 HWND retvalue = 0;
2577 if (!(wndPtr = WIN_GetPtr( hwnd )))
2579 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2580 return 0;
2582 if (wndPtr == WND_DESKTOP) return 0;
2583 if (wndPtr == WND_OTHER_PROCESS)
2585 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2586 if (style & (WS_POPUP | WS_CHILD))
2588 SERVER_START_REQ( get_window_tree )
2590 req->handle = wine_server_user_handle( hwnd );
2591 if (!wine_server_call_err( req ))
2593 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2594 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2597 SERVER_END_REQ;
2600 else
2602 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2603 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2604 WIN_ReleasePtr( wndPtr );
2606 return retvalue;
2610 /*****************************************************************
2611 * GetAncestor (USER32.@)
2613 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2615 WND *win;
2616 HWND *list, ret = 0;
2618 switch(type)
2620 case GA_PARENT:
2621 if (!(win = WIN_GetPtr( hwnd )))
2623 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2624 return 0;
2626 if (win == WND_DESKTOP) return 0;
2627 if (win != WND_OTHER_PROCESS)
2629 ret = win->parent;
2630 WIN_ReleasePtr( win );
2632 else /* need to query the server */
2634 SERVER_START_REQ( get_window_tree )
2636 req->handle = wine_server_user_handle( hwnd );
2637 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2639 SERVER_END_REQ;
2641 break;
2643 case GA_ROOT:
2644 if (!(list = list_window_parents( hwnd ))) return 0;
2646 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2647 else
2649 int count = 2;
2650 while (list[count]) count++;
2651 ret = list[count - 2]; /* get the one before the desktop */
2653 HeapFree( GetProcessHeap(), 0, list );
2654 break;
2656 case GA_ROOTOWNER:
2657 if (is_desktop_window( hwnd )) return 0;
2658 ret = WIN_GetFullHandle( hwnd );
2659 for (;;)
2661 HWND parent = GetParent( ret );
2662 if (!parent) break;
2663 ret = parent;
2665 break;
2667 return ret;
2671 /*****************************************************************
2672 * SetParent (USER32.@)
2674 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2676 HWND full_handle;
2677 HWND old_parent = 0;
2678 BOOL was_visible;
2679 WND *wndPtr;
2680 BOOL ret;
2682 if (is_broadcast(hwnd) || is_broadcast(parent))
2684 SetLastError(ERROR_INVALID_PARAMETER);
2685 return 0;
2688 if (!parent) parent = GetDesktopWindow();
2689 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2690 else parent = WIN_GetFullHandle( parent );
2692 if (!IsWindow( parent ))
2694 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2695 return 0;
2698 /* Some applications try to set a child as a parent */
2699 if (IsChild(hwnd, parent))
2701 SetLastError( ERROR_INVALID_PARAMETER );
2702 return 0;
2705 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2706 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2708 if (full_handle == parent)
2710 SetLastError( ERROR_INVALID_PARAMETER );
2711 return 0;
2714 /* Windows hides the window first, then shows it again
2715 * including the WM_SHOWWINDOW messages and all */
2716 was_visible = ShowWindow( hwnd, SW_HIDE );
2718 wndPtr = WIN_GetPtr( hwnd );
2719 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2721 SERVER_START_REQ( set_parent )
2723 req->handle = wine_server_user_handle( hwnd );
2724 req->parent = wine_server_user_handle( parent );
2725 if ((ret = !wine_server_call( req )))
2727 old_parent = wine_server_ptr_handle( reply->old_parent );
2728 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2732 SERVER_END_REQ;
2733 WIN_ReleasePtr( wndPtr );
2734 if (!ret) return 0;
2736 USER_Driver->pSetParent( full_handle, parent, old_parent );
2738 /* SetParent additionally needs to make hwnd the topmost window
2739 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2740 WM_WINDOWPOSCHANGED notification messages.
2742 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2743 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2744 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2745 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2747 return old_parent;
2751 /*******************************************************************
2752 * IsChild (USER32.@)
2754 BOOL WINAPI IsChild( HWND parent, HWND child )
2756 HWND *list = list_window_parents( child );
2757 int i;
2758 BOOL ret;
2760 if (!list) return FALSE;
2761 parent = WIN_GetFullHandle( parent );
2762 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2763 ret = list[i] && list[i+1];
2764 HeapFree( GetProcessHeap(), 0, list );
2765 return ret;
2769 /***********************************************************************
2770 * IsWindowVisible (USER32.@)
2772 BOOL WINAPI IsWindowVisible( HWND hwnd )
2774 HWND *list;
2775 BOOL retval = TRUE;
2776 int i;
2778 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2779 if (!(list = list_window_parents( hwnd ))) return TRUE;
2780 if (list[0])
2782 for (i = 0; list[i+1]; i++)
2783 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2784 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2786 HeapFree( GetProcessHeap(), 0, list );
2787 return retval;
2791 /***********************************************************************
2792 * WIN_IsWindowDrawable
2794 * hwnd is drawable when it is visible, all parents are not
2795 * minimized, and it is itself not minimized unless we are
2796 * trying to draw its default class icon.
2798 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2800 HWND *list;
2801 BOOL retval = TRUE;
2802 int i;
2803 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2805 if (!(style & WS_VISIBLE)) return FALSE;
2806 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2808 if (!(list = list_window_parents( hwnd ))) return TRUE;
2809 if (list[0])
2811 for (i = 0; list[i+1]; i++)
2812 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2813 break;
2814 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2816 HeapFree( GetProcessHeap(), 0, list );
2817 return retval;
2821 /*******************************************************************
2822 * GetTopWindow (USER32.@)
2824 HWND WINAPI GetTopWindow( HWND hwnd )
2826 if (!hwnd) hwnd = GetDesktopWindow();
2827 return GetWindow( hwnd, GW_CHILD );
2831 /*******************************************************************
2832 * GetWindow (USER32.@)
2834 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2836 HWND retval = 0;
2838 if (rel == GW_OWNER) /* this one may be available locally */
2840 WND *wndPtr = WIN_GetPtr( hwnd );
2841 if (!wndPtr)
2843 SetLastError( ERROR_INVALID_HANDLE );
2844 return 0;
2846 if (wndPtr == WND_DESKTOP) return 0;
2847 if (wndPtr != WND_OTHER_PROCESS)
2849 retval = wndPtr->owner;
2850 WIN_ReleasePtr( wndPtr );
2851 return retval;
2853 /* else fall through to server call */
2856 SERVER_START_REQ( get_window_tree )
2858 req->handle = wine_server_user_handle( hwnd );
2859 if (!wine_server_call_err( req ))
2861 switch(rel)
2863 case GW_HWNDFIRST:
2864 retval = wine_server_ptr_handle( reply->first_sibling );
2865 break;
2866 case GW_HWNDLAST:
2867 retval = wine_server_ptr_handle( reply->last_sibling );
2868 break;
2869 case GW_HWNDNEXT:
2870 retval = wine_server_ptr_handle( reply->next_sibling );
2871 break;
2872 case GW_HWNDPREV:
2873 retval = wine_server_ptr_handle( reply->prev_sibling );
2874 break;
2875 case GW_OWNER:
2876 retval = wine_server_ptr_handle( reply->owner );
2877 break;
2878 case GW_CHILD:
2879 retval = wine_server_ptr_handle( reply->first_child );
2880 break;
2884 SERVER_END_REQ;
2885 return retval;
2889 /*******************************************************************
2890 * ShowOwnedPopups (USER32.@)
2892 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2894 int count = 0;
2895 WND *pWnd;
2896 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2898 if (!win_array) return TRUE;
2900 while (win_array[count]) count++;
2901 while (--count >= 0)
2903 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2904 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2905 if (pWnd == WND_OTHER_PROCESS) continue;
2906 if (fShow)
2908 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2910 WIN_ReleasePtr( pWnd );
2911 /* In Windows, ShowOwnedPopups(TRUE) generates
2912 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2913 * regardless of the state of the owner
2915 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2916 continue;
2919 else
2921 if (pWnd->dwStyle & WS_VISIBLE)
2923 WIN_ReleasePtr( pWnd );
2924 /* In Windows, ShowOwnedPopups(FALSE) generates
2925 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2926 * regardless of the state of the owner
2928 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2929 continue;
2932 WIN_ReleasePtr( pWnd );
2934 HeapFree( GetProcessHeap(), 0, win_array );
2935 return TRUE;
2939 /*******************************************************************
2940 * GetLastActivePopup (USER32.@)
2942 HWND WINAPI GetLastActivePopup( HWND hwnd )
2944 HWND retval = hwnd;
2946 SERVER_START_REQ( get_window_info )
2948 req->handle = wine_server_user_handle( hwnd );
2949 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2951 SERVER_END_REQ;
2952 return retval;
2956 /*******************************************************************
2957 * WIN_ListChildren
2959 * Build an array of the children of a given window. The array must be
2960 * freed with HeapFree. Returns NULL when no windows are found.
2962 HWND *WIN_ListChildren( HWND hwnd )
2964 if (!hwnd)
2966 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2967 return NULL;
2969 return list_window_children( 0, hwnd, NULL, 0 );
2973 /*******************************************************************
2974 * EnumWindows (USER32.@)
2976 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2978 HWND *list;
2979 BOOL ret = TRUE;
2980 int i;
2982 USER_CheckNotLock();
2984 /* We have to build a list of all windows first, to avoid */
2985 /* unpleasant side-effects, for instance if the callback */
2986 /* function changes the Z-order of the windows. */
2988 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2990 /* Now call the callback function for every window */
2992 for (i = 0; list[i]; i++)
2994 /* Make sure that the window still exists */
2995 if (!IsWindow( list[i] )) continue;
2996 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2998 HeapFree( GetProcessHeap(), 0, list );
2999 return ret;
3003 /**********************************************************************
3004 * EnumThreadWindows (USER32.@)
3006 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3008 HWND *list;
3009 int i;
3010 BOOL ret = TRUE;
3012 USER_CheckNotLock();
3014 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3016 /* Now call the callback function for every window */
3018 for (i = 0; list[i]; i++)
3019 if (!(ret = func( list[i], lParam ))) break;
3020 HeapFree( GetProcessHeap(), 0, list );
3021 return ret;
3025 /***********************************************************************
3026 * EnumDesktopWindows (USER32.@)
3028 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3030 HWND *list;
3031 int i;
3033 USER_CheckNotLock();
3035 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3037 for (i = 0; list[i]; i++)
3038 if (!func( list[i], lparam )) break;
3039 HeapFree( GetProcessHeap(), 0, list );
3040 return TRUE;
3044 /**********************************************************************
3045 * WIN_EnumChildWindows
3047 * Helper function for EnumChildWindows().
3049 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3051 HWND *childList;
3052 BOOL ret = FALSE;
3054 for ( ; *list; list++)
3056 /* Make sure that the window still exists */
3057 if (!IsWindow( *list )) continue;
3058 /* Build children list first */
3059 childList = WIN_ListChildren( *list );
3061 ret = func( *list, lParam );
3063 if (childList)
3065 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3066 HeapFree( GetProcessHeap(), 0, childList );
3068 if (!ret) return FALSE;
3070 return TRUE;
3074 /**********************************************************************
3075 * EnumChildWindows (USER32.@)
3077 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3079 HWND *list;
3080 BOOL ret;
3082 USER_CheckNotLock();
3084 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3085 ret = WIN_EnumChildWindows( list, func, lParam );
3086 HeapFree( GetProcessHeap(), 0, list );
3087 return ret;
3091 /*******************************************************************
3092 * AnyPopup (USER32.@)
3094 BOOL WINAPI AnyPopup(void)
3096 int i;
3097 BOOL retvalue;
3098 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3100 if (!list) return FALSE;
3101 for (i = 0; list[i]; i++)
3103 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3105 retvalue = (list[i] != 0);
3106 HeapFree( GetProcessHeap(), 0, list );
3107 return retvalue;
3111 /*******************************************************************
3112 * FlashWindow (USER32.@)
3114 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3116 WND *wndPtr;
3118 TRACE("%p\n", hWnd);
3120 if (IsIconic( hWnd ))
3122 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3124 wndPtr = WIN_GetPtr(hWnd);
3125 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3126 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3128 wndPtr->flags |= WIN_NCACTIVATED;
3130 else
3132 wndPtr->flags &= ~WIN_NCACTIVATED;
3134 WIN_ReleasePtr( wndPtr );
3135 return TRUE;
3137 else
3139 WPARAM wparam;
3141 wndPtr = WIN_GetPtr(hWnd);
3142 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3143 hWnd = wndPtr->obj.handle; /* make it a full handle */
3145 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3146 else wparam = (hWnd == GetForegroundWindow());
3148 WIN_ReleasePtr( wndPtr );
3149 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3150 return wparam;
3154 /*******************************************************************
3155 * FlashWindowEx (USER32.@)
3157 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3159 FIXME("%p\n", pfwi);
3160 return TRUE;
3163 /*******************************************************************
3164 * GetWindowContextHelpId (USER32.@)
3166 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3168 DWORD retval;
3169 WND *wnd = WIN_GetPtr( hwnd );
3170 if (!wnd || wnd == WND_DESKTOP) return 0;
3171 if (wnd == WND_OTHER_PROCESS)
3173 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3174 return 0;
3176 retval = wnd->helpContext;
3177 WIN_ReleasePtr( wnd );
3178 return retval;
3182 /*******************************************************************
3183 * SetWindowContextHelpId (USER32.@)
3185 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3187 WND *wnd = WIN_GetPtr( hwnd );
3188 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3189 if (wnd == WND_OTHER_PROCESS)
3191 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3192 return 0;
3194 wnd->helpContext = id;
3195 WIN_ReleasePtr( wnd );
3196 return TRUE;
3200 /*******************************************************************
3201 * DragDetect (USER32.@)
3203 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3205 MSG msg;
3206 RECT rect;
3207 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3208 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3210 rect.left = pt.x - wDragWidth;
3211 rect.right = pt.x + wDragWidth;
3213 rect.top = pt.y - wDragHeight;
3214 rect.bottom = pt.y + wDragHeight;
3216 SetCapture(hWnd);
3218 while(1)
3220 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3222 if( msg.message == WM_LBUTTONUP )
3224 ReleaseCapture();
3225 return 0;
3227 if( msg.message == WM_MOUSEMOVE )
3229 POINT tmp;
3230 tmp.x = (short)LOWORD(msg.lParam);
3231 tmp.y = (short)HIWORD(msg.lParam);
3232 if( !PtInRect( &rect, tmp ))
3234 ReleaseCapture();
3235 return 1;
3239 WaitMessage();
3241 return 0;
3244 /******************************************************************************
3245 * GetWindowModuleFileNameA (USER32.@)
3247 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3249 WND *win;
3250 HINSTANCE hinst;
3252 TRACE( "%p, %p, %u\n", hwnd, module, size );
3254 win = WIN_GetPtr( hwnd );
3255 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3257 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3258 return 0;
3260 hinst = win->hInstance;
3261 WIN_ReleasePtr( win );
3263 return GetModuleFileNameA( hinst, module, size );
3266 /******************************************************************************
3267 * GetWindowModuleFileNameW (USER32.@)
3269 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3271 WND *win;
3272 HINSTANCE hinst;
3274 TRACE( "%p, %p, %u\n", hwnd, module, size );
3276 win = WIN_GetPtr( hwnd );
3277 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3279 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3280 return 0;
3282 hinst = win->hInstance;
3283 WIN_ReleasePtr( win );
3285 return GetModuleFileNameW( hinst, module, size );
3288 /******************************************************************************
3289 * GetWindowInfo (USER32.@)
3291 * Note: tests show that Windows doesn't check cbSize of the structure.
3293 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3295 if (!pwi) return FALSE;
3296 if (!IsWindow(hwnd)) return FALSE;
3298 GetWindowRect(hwnd, &pwi->rcWindow);
3299 GetClientRect(hwnd, &pwi->rcClient);
3300 /* translate to screen coordinates */
3301 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3303 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3304 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3305 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3307 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3308 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3310 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3311 pwi->wCreatorVersion = 0x0400;
3313 return TRUE;
3316 /******************************************************************************
3317 * SwitchDesktop (USER32.@)
3319 * NOTES: Sets the current input or interactive desktop.
3321 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3323 FIXME("(hwnd %p) stub!\n", hDesktop);
3324 return TRUE;
3327 /*****************************************************************************
3328 * SetLayeredWindowAttributes (USER32.@)
3330 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3332 BOOL ret;
3334 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3336 SERVER_START_REQ( set_window_layered_info )
3338 req->handle = wine_server_user_handle( hwnd );
3339 req->color_key = key;
3340 req->alpha = alpha;
3341 req->flags = flags;
3342 ret = !wine_server_call_err( req );
3344 SERVER_END_REQ;
3346 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3348 return ret;
3352 /*****************************************************************************
3353 * GetLayeredWindowAttributes (USER32.@)
3355 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3357 BOOL ret;
3359 SERVER_START_REQ( get_window_layered_info )
3361 req->handle = wine_server_user_handle( hwnd );
3362 if ((ret = !wine_server_call_err( req )))
3364 if (key) *key = reply->color_key;
3365 if (alpha) *alpha = reply->alpha;
3366 if (flags) *flags = reply->flags;
3369 SERVER_END_REQ;
3371 return ret;
3375 /*****************************************************************************
3376 * UpdateLayeredWindowIndirect (USER32.@)
3378 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3380 BYTE alpha = 0xff;
3382 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3384 int x = 0, y = 0, cx = 0, cy = 0;
3385 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3387 if (info->pptDst)
3389 x = info->pptDst->x;
3390 y = info->pptDst->y;
3391 flags &= ~SWP_NOMOVE;
3393 if (info->psize)
3395 cx = info->psize->cx;
3396 cy = info->psize->cy;
3397 flags &= ~SWP_NOSIZE;
3399 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3400 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3403 if (info->hdcSrc)
3405 HDC hdc = GetWindowDC( hwnd );
3407 if (hdc)
3409 int x = 0, y = 0;
3410 RECT rect;
3412 GetWindowRect( hwnd, &rect );
3413 OffsetRect( &rect, -rect.left, -rect.top);
3414 if (info->pptSrc)
3416 x = info->pptSrc->x;
3417 y = info->pptSrc->y;
3420 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3422 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3423 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3424 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3426 ReleaseDC( hwnd, hdc );
3430 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3431 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3432 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3433 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3434 return TRUE;
3438 /*****************************************************************************
3439 * UpdateLayeredWindow (USER32.@)
3441 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3442 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3443 DWORD dwFlags)
3445 UPDATELAYEREDWINDOWINFO info;
3447 info.cbSize = sizeof(info);
3448 info.hdcDst = hdcDst;
3449 info.pptDst = pptDst;
3450 info.psize = psize;
3451 info.hdcSrc = hdcSrc;
3452 info.pptSrc = pptSrc;
3453 info.crKey = crKey;
3454 info.pblend = pblend;
3455 info.dwFlags = dwFlags;
3456 info.prcDirty = NULL;
3457 return UpdateLayeredWindowIndirect( hwnd, &info );
3460 /* 64bit versions */
3462 #ifdef GetWindowLongPtrW
3463 #undef GetWindowLongPtrW
3464 #endif
3466 #ifdef GetWindowLongPtrA
3467 #undef GetWindowLongPtrA
3468 #endif
3470 #ifdef SetWindowLongPtrW
3471 #undef SetWindowLongPtrW
3472 #endif
3474 #ifdef SetWindowLongPtrA
3475 #undef SetWindowLongPtrA
3476 #endif
3478 /*****************************************************************************
3479 * GetWindowLongPtrW (USER32.@)
3481 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3483 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3486 /*****************************************************************************
3487 * GetWindowLongPtrA (USER32.@)
3489 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3491 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3494 /*****************************************************************************
3495 * SetWindowLongPtrW (USER32.@)
3497 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3499 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3502 /*****************************************************************************
3503 * SetWindowLongPtrA (USER32.@)
3505 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3507 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );