user32: Don't print the function name twice in a FIXME.
[wine/multimedia.git] / dlls / user32 / win.c
blob9a19b2ade41de974691893696f58b9bfd6e18c7c
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)];
1789 memset( &si, 0, sizeof(si) );
1790 si.cb = sizeof(si);
1791 si.dwFlags = STARTF_USESTDHANDLES;
1792 si.hStdInput = 0;
1793 si.hStdOutput = 0;
1794 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1796 GetWindowsDirectoryW( windir, MAX_PATH );
1797 strcpyW( app, windir );
1798 strcatW( app, explorer );
1799 strcpyW( cmdline, app );
1800 strcatW( cmdline, args );
1801 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1802 NULL, windir, &si, &pi ))
1804 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1805 WaitForInputIdle( pi.hProcess, 10000 );
1806 CloseHandle( pi.hThread );
1807 CloseHandle( pi.hProcess );
1809 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1811 else TRACE( "not starting explorer since winstation is not visible\n" );
1813 SERVER_START_REQ( get_desktop_window )
1815 req->force = 1;
1816 if (!wine_server_call( req ))
1818 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1819 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1822 SERVER_END_REQ;
1825 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1826 ERR( "failed to create desktop window\n" );
1828 return thread_info->top_window;
1832 /*******************************************************************
1833 * EnableWindow (USER32.@)
1835 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1837 BOOL retvalue;
1838 HWND full_handle;
1840 if (is_broadcast(hwnd))
1842 SetLastError( ERROR_INVALID_PARAMETER );
1843 return FALSE;
1846 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1847 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1849 hwnd = full_handle;
1851 TRACE("( %p, %d )\n", hwnd, enable);
1853 retvalue = !IsWindowEnabled( hwnd );
1855 if (enable && retvalue)
1857 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1858 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1860 else if (!enable && !retvalue)
1862 HWND capture_wnd;
1864 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1866 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1868 if (hwnd == GetFocus())
1869 SetFocus( 0 ); /* A disabled window can't have the focus */
1871 capture_wnd = GetCapture();
1872 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1873 ReleaseCapture(); /* A disabled window can't capture the mouse */
1875 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1877 return retvalue;
1881 /***********************************************************************
1882 * IsWindowEnabled (USER32.@)
1884 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1886 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1890 /***********************************************************************
1891 * IsWindowUnicode (USER32.@)
1893 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1895 WND * wndPtr;
1896 BOOL retvalue = FALSE;
1898 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1900 if (wndPtr == WND_DESKTOP) return TRUE;
1902 if (wndPtr != WND_OTHER_PROCESS)
1904 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1905 WIN_ReleasePtr( wndPtr );
1907 else
1909 SERVER_START_REQ( get_window_info )
1911 req->handle = wine_server_user_handle( hwnd );
1912 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1914 SERVER_END_REQ;
1916 return retvalue;
1920 /**********************************************************************
1921 * WIN_GetWindowLong
1923 * Helper function for GetWindowLong().
1925 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1927 LONG_PTR retvalue = 0;
1928 WND *wndPtr;
1930 if (offset == GWLP_HWNDPARENT)
1932 HWND parent = GetAncestor( hwnd, GA_PARENT );
1933 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1934 return (ULONG_PTR)parent;
1937 if (!(wndPtr = WIN_GetPtr( hwnd )))
1939 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1940 return 0;
1943 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1945 if (offset == GWLP_WNDPROC)
1947 SetLastError( ERROR_ACCESS_DENIED );
1948 return 0;
1950 SERVER_START_REQ( set_window_info )
1952 req->handle = wine_server_user_handle( hwnd );
1953 req->flags = 0; /* don't set anything, just retrieve */
1954 req->extra_offset = (offset >= 0) ? offset : -1;
1955 req->extra_size = (offset >= 0) ? size : 0;
1956 if (!wine_server_call_err( req ))
1958 switch(offset)
1960 case GWL_STYLE: retvalue = reply->old_style; break;
1961 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1962 case GWLP_ID: retvalue = reply->old_id; break;
1963 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1964 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1965 default:
1966 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1967 else SetLastError( ERROR_INVALID_INDEX );
1968 break;
1972 SERVER_END_REQ;
1973 return retvalue;
1976 /* now we have a valid wndPtr */
1978 if (offset >= 0)
1980 if (offset > (int)(wndPtr->cbWndExtra - size))
1982 WARN("Invalid offset %d\n", offset );
1983 WIN_ReleasePtr( wndPtr );
1984 SetLastError( ERROR_INVALID_INDEX );
1985 return 0;
1987 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1989 /* Special case for dialog window procedure */
1990 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1991 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1992 WIN_ReleasePtr( wndPtr );
1993 return retvalue;
1996 switch(offset)
1998 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1999 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2000 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2001 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2002 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2003 case GWLP_WNDPROC:
2004 /* This looks like a hack only for the edit control (see tests). This makes these controls
2005 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2006 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2008 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2009 retvalue = (ULONG_PTR)wndPtr->winproc;
2010 else
2011 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2012 break;
2013 default:
2014 WARN("Unknown offset %d\n", offset );
2015 SetLastError( ERROR_INVALID_INDEX );
2016 break;
2018 WIN_ReleasePtr(wndPtr);
2019 return retvalue;
2023 /**********************************************************************
2024 * WIN_SetWindowLong
2026 * Helper function for SetWindowLong().
2028 * 0 is the failure code. However, in the case of failure SetLastError
2029 * must be set to distinguish between a 0 return value and a failure.
2031 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2033 STYLESTRUCT style;
2034 BOOL ok;
2035 LONG_PTR retval = 0;
2036 WND *wndPtr;
2038 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2040 if (is_broadcast(hwnd))
2042 SetLastError( ERROR_INVALID_PARAMETER );
2043 return FALSE;
2046 if (!(wndPtr = WIN_GetPtr( hwnd )))
2048 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2049 return 0;
2051 if (wndPtr == WND_DESKTOP)
2053 /* can't change anything on the desktop window */
2054 SetLastError( ERROR_ACCESS_DENIED );
2055 return 0;
2057 if (wndPtr == WND_OTHER_PROCESS)
2059 if (offset == GWLP_WNDPROC)
2061 SetLastError( ERROR_ACCESS_DENIED );
2062 return 0;
2064 if (offset > 32767 || offset < -32767)
2066 SetLastError( ERROR_INVALID_INDEX );
2067 return 0;
2069 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2072 /* first some special cases */
2073 switch( offset )
2075 case GWL_STYLE:
2076 case GWL_EXSTYLE:
2077 style.styleOld =
2078 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2079 style.styleNew = newval;
2080 WIN_ReleasePtr( wndPtr );
2081 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2082 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2083 newval = style.styleNew;
2084 break;
2085 case GWLP_HWNDPARENT:
2086 if (wndPtr->parent == GetDesktopWindow())
2088 WIN_ReleasePtr( wndPtr );
2089 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2091 else
2093 WIN_ReleasePtr( wndPtr );
2094 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2096 case GWLP_WNDPROC:
2098 WNDPROC proc;
2099 UINT old_flags = wndPtr->flags;
2100 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2101 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2102 if (proc) wndPtr->winproc = proc;
2103 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2104 else wndPtr->flags &= ~WIN_ISUNICODE;
2105 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2107 WIN_ReleasePtr( wndPtr );
2108 return retval;
2110 /* update is_unicode flag on the server side */
2111 break;
2113 case GWLP_ID:
2114 case GWLP_HINSTANCE:
2115 case GWLP_USERDATA:
2116 break;
2117 case DWLP_DLGPROC:
2118 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2119 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2121 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2122 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2123 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2124 WIN_ReleasePtr( wndPtr );
2125 return retval;
2127 /* fall through */
2128 default:
2129 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2131 WARN("Invalid offset %d\n", offset );
2132 WIN_ReleasePtr( wndPtr );
2133 SetLastError( ERROR_INVALID_INDEX );
2134 return 0;
2136 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2138 /* already set to the same value */
2139 WIN_ReleasePtr( wndPtr );
2140 return newval;
2142 break;
2145 SERVER_START_REQ( set_window_info )
2147 req->handle = wine_server_user_handle( hwnd );
2148 req->extra_offset = -1;
2149 switch(offset)
2151 case GWL_STYLE:
2152 req->flags = SET_WIN_STYLE;
2153 req->style = newval;
2154 break;
2155 case GWL_EXSTYLE:
2156 req->flags = SET_WIN_EXSTYLE;
2157 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2158 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2159 req->ex_style = newval;
2160 break;
2161 case GWLP_ID:
2162 req->flags = SET_WIN_ID;
2163 req->id = newval;
2164 break;
2165 case GWLP_HINSTANCE:
2166 req->flags = SET_WIN_INSTANCE;
2167 req->instance = wine_server_client_ptr( (void *)newval );
2168 break;
2169 case GWLP_WNDPROC:
2170 req->flags = SET_WIN_UNICODE;
2171 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2172 break;
2173 case GWLP_USERDATA:
2174 req->flags = SET_WIN_USERDATA;
2175 req->user_data = newval;
2176 break;
2177 default:
2178 req->flags = SET_WIN_EXTRA;
2179 req->extra_offset = offset;
2180 req->extra_size = size;
2181 set_win_data( &req->extra_value, newval, size );
2183 if ((ok = !wine_server_call_err( req )))
2185 switch(offset)
2187 case GWL_STYLE:
2188 wndPtr->dwStyle = newval;
2189 retval = reply->old_style;
2190 break;
2191 case GWL_EXSTYLE:
2192 wndPtr->dwExStyle = newval;
2193 retval = reply->old_ex_style;
2194 break;
2195 case GWLP_ID:
2196 wndPtr->wIDmenu = newval;
2197 retval = reply->old_id;
2198 break;
2199 case GWLP_HINSTANCE:
2200 wndPtr->hInstance = (HINSTANCE)newval;
2201 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2202 break;
2203 case GWLP_WNDPROC:
2204 break;
2205 case GWLP_USERDATA:
2206 wndPtr->userdata = newval;
2207 retval = reply->old_user_data;
2208 break;
2209 default:
2210 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2211 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2212 break;
2216 SERVER_END_REQ;
2217 WIN_ReleasePtr( wndPtr );
2219 if (!ok) return 0;
2221 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2223 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2224 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2227 return retval;
2231 /**********************************************************************
2232 * GetWindowWord (USER32.@)
2234 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2236 switch(offset)
2238 case GWLP_ID:
2239 case GWLP_HINSTANCE:
2240 case GWLP_HWNDPARENT:
2241 break;
2242 default:
2243 if (offset < 0)
2245 WARN("Invalid offset %d\n", offset );
2246 SetLastError( ERROR_INVALID_INDEX );
2247 return 0;
2249 break;
2251 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2255 /**********************************************************************
2256 * GetWindowLongA (USER32.@)
2258 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2260 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2264 /**********************************************************************
2265 * GetWindowLongW (USER32.@)
2267 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2269 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2273 /**********************************************************************
2274 * SetWindowWord (USER32.@)
2276 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2278 switch(offset)
2280 case GWLP_ID:
2281 case GWLP_HINSTANCE:
2282 case GWLP_HWNDPARENT:
2283 break;
2284 default:
2285 if (offset < 0)
2287 WARN("Invalid offset %d\n", offset );
2288 SetLastError( ERROR_INVALID_INDEX );
2289 return 0;
2291 break;
2293 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2297 /**********************************************************************
2298 * SetWindowLongA (USER32.@)
2300 * See SetWindowLongW.
2302 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2304 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2308 /**********************************************************************
2309 * SetWindowLongW (USER32.@) Set window attribute
2311 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2312 * value in a window's extra memory.
2314 * The _hwnd_ parameter specifies the window. is the handle to a
2315 * window that has extra memory. The _newval_ parameter contains the
2316 * new attribute or extra memory value. If positive, the _offset_
2317 * parameter is the byte-addressed location in the window's extra
2318 * memory to set. If negative, _offset_ specifies the window
2319 * attribute to set, and should be one of the following values:
2321 * GWL_EXSTYLE The window's extended window style
2323 * GWL_STYLE The window's window style.
2325 * GWLP_WNDPROC Pointer to the window's window procedure.
2327 * GWLP_HINSTANCE The window's pplication instance handle.
2329 * GWLP_ID The window's identifier.
2331 * GWLP_USERDATA The window's user-specified data.
2333 * If the window is a dialog box, the _offset_ parameter can be one of
2334 * the following values:
2336 * DWLP_DLGPROC The address of the window's dialog box procedure.
2338 * DWLP_MSGRESULT The return value of a message
2339 * that the dialog box procedure processed.
2341 * DWLP_USER Application specific information.
2343 * RETURNS
2345 * If successful, returns the previous value located at _offset_. Otherwise,
2346 * returns 0.
2348 * NOTES
2350 * Extra memory for a window class is specified by a nonzero cbWndExtra
2351 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2352 * time of class creation.
2354 * Using GWL_WNDPROC to set a new window procedure effectively creates
2355 * a window subclass. Use CallWindowProc() in the new windows procedure
2356 * to pass messages to the superclass's window procedure.
2358 * The user data is reserved for use by the application which created
2359 * the window.
2361 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2362 * instead, call the EnableWindow() function to change the window's
2363 * disabled state.
2365 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2366 * SetParent() instead.
2368 * Win95:
2369 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2370 * it sends WM_STYLECHANGING before changing the settings
2371 * and WM_STYLECHANGED afterwards.
2372 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2374 LONG WINAPI SetWindowLongW(
2375 HWND hwnd, /* [in] window to alter */
2376 INT offset, /* [in] offset, in bytes, of location to alter */
2377 LONG newval /* [in] new value of location */
2379 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2383 /*******************************************************************
2384 * GetWindowTextA (USER32.@)
2386 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2388 WCHAR *buffer;
2390 if (!lpString) return 0;
2392 if (WIN_IsCurrentProcess( hwnd ))
2393 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2395 /* when window belongs to other process, don't send a message */
2396 if (nMaxCount <= 0) return 0;
2397 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2398 get_server_window_text( hwnd, buffer, nMaxCount );
2399 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2400 lpString[nMaxCount-1] = 0;
2401 HeapFree( GetProcessHeap(), 0, buffer );
2402 return strlen(lpString);
2406 /*******************************************************************
2407 * InternalGetWindowText (USER32.@)
2409 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2411 WND *win;
2413 if (nMaxCount <= 0) return 0;
2414 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2415 if (win == WND_DESKTOP) lpString[0] = 0;
2416 else if (win != WND_OTHER_PROCESS)
2418 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2419 else lpString[0] = 0;
2420 WIN_ReleasePtr( win );
2422 else
2424 get_server_window_text( hwnd, lpString, nMaxCount );
2426 return strlenW(lpString);
2430 /*******************************************************************
2431 * GetWindowTextW (USER32.@)
2433 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2435 if (!lpString) return 0;
2437 if (WIN_IsCurrentProcess( hwnd ))
2438 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2440 /* when window belongs to other process, don't send a message */
2441 if (nMaxCount <= 0) return 0;
2442 get_server_window_text( hwnd, lpString, nMaxCount );
2443 return strlenW(lpString);
2447 /*******************************************************************
2448 * SetWindowTextA (USER32.@)
2449 * SetWindowText (USER32.@)
2451 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2453 if (is_broadcast(hwnd))
2455 SetLastError( ERROR_INVALID_PARAMETER );
2456 return FALSE;
2458 if (!WIN_IsCurrentProcess( hwnd ))
2459 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2460 debugstr_a(lpString), hwnd );
2461 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2465 /*******************************************************************
2466 * SetWindowTextW (USER32.@)
2468 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2470 if (is_broadcast(hwnd))
2472 SetLastError( ERROR_INVALID_PARAMETER );
2473 return FALSE;
2475 if (!WIN_IsCurrentProcess( hwnd ))
2476 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2477 debugstr_w(lpString), hwnd );
2478 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2482 /*******************************************************************
2483 * GetWindowTextLengthA (USER32.@)
2485 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2487 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2490 /*******************************************************************
2491 * GetWindowTextLengthW (USER32.@)
2493 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2495 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2499 /*******************************************************************
2500 * IsWindow (USER32.@)
2502 BOOL WINAPI IsWindow( HWND hwnd )
2504 WND *ptr;
2505 BOOL ret;
2507 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2508 if (ptr == WND_DESKTOP) return TRUE;
2510 if (ptr != WND_OTHER_PROCESS)
2512 WIN_ReleasePtr( ptr );
2513 return TRUE;
2516 /* check other processes */
2517 SERVER_START_REQ( get_window_info )
2519 req->handle = wine_server_user_handle( hwnd );
2520 ret = !wine_server_call_err( req );
2522 SERVER_END_REQ;
2523 return ret;
2527 /***********************************************************************
2528 * GetWindowThreadProcessId (USER32.@)
2530 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2532 WND *ptr;
2533 DWORD tid = 0;
2535 if (!(ptr = WIN_GetPtr( hwnd )))
2537 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2538 return 0;
2541 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2543 /* got a valid window */
2544 tid = ptr->tid;
2545 if (process) *process = GetCurrentProcessId();
2546 WIN_ReleasePtr( ptr );
2547 return tid;
2550 /* check other processes */
2551 SERVER_START_REQ( get_window_info )
2553 req->handle = wine_server_user_handle( hwnd );
2554 if (!wine_server_call_err( req ))
2556 tid = (DWORD)reply->tid;
2557 if (process) *process = (DWORD)reply->pid;
2560 SERVER_END_REQ;
2561 return tid;
2565 /*****************************************************************
2566 * GetParent (USER32.@)
2568 HWND WINAPI GetParent( HWND hwnd )
2570 WND *wndPtr;
2571 HWND retvalue = 0;
2573 if (!(wndPtr = WIN_GetPtr( hwnd )))
2575 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2576 return 0;
2578 if (wndPtr == WND_DESKTOP) return 0;
2579 if (wndPtr == WND_OTHER_PROCESS)
2581 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2582 if (style & (WS_POPUP | WS_CHILD))
2584 SERVER_START_REQ( get_window_tree )
2586 req->handle = wine_server_user_handle( hwnd );
2587 if (!wine_server_call_err( req ))
2589 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2590 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2593 SERVER_END_REQ;
2596 else
2598 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2599 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2600 WIN_ReleasePtr( wndPtr );
2602 return retvalue;
2606 /*****************************************************************
2607 * GetAncestor (USER32.@)
2609 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2611 WND *win;
2612 HWND *list, ret = 0;
2614 switch(type)
2616 case GA_PARENT:
2617 if (!(win = WIN_GetPtr( hwnd )))
2619 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2620 return 0;
2622 if (win == WND_DESKTOP) return 0;
2623 if (win != WND_OTHER_PROCESS)
2625 ret = win->parent;
2626 WIN_ReleasePtr( win );
2628 else /* need to query the server */
2630 SERVER_START_REQ( get_window_tree )
2632 req->handle = wine_server_user_handle( hwnd );
2633 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2635 SERVER_END_REQ;
2637 break;
2639 case GA_ROOT:
2640 if (!(list = list_window_parents( hwnd ))) return 0;
2642 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2643 else
2645 int count = 2;
2646 while (list[count]) count++;
2647 ret = list[count - 2]; /* get the one before the desktop */
2649 HeapFree( GetProcessHeap(), 0, list );
2650 break;
2652 case GA_ROOTOWNER:
2653 if (is_desktop_window( hwnd )) return 0;
2654 ret = WIN_GetFullHandle( hwnd );
2655 for (;;)
2657 HWND parent = GetParent( ret );
2658 if (!parent) break;
2659 ret = parent;
2661 break;
2663 return ret;
2667 /*****************************************************************
2668 * SetParent (USER32.@)
2670 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2672 HWND full_handle;
2673 HWND old_parent = 0;
2674 BOOL was_visible;
2675 WND *wndPtr;
2676 BOOL ret;
2678 if (is_broadcast(hwnd) || is_broadcast(parent))
2680 SetLastError(ERROR_INVALID_PARAMETER);
2681 return 0;
2684 if (!parent) parent = GetDesktopWindow();
2685 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2686 else parent = WIN_GetFullHandle( parent );
2688 if (!IsWindow( parent ))
2690 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2691 return 0;
2694 /* Some applications try to set a child as a parent */
2695 if (IsChild(hwnd, parent))
2697 SetLastError( ERROR_INVALID_PARAMETER );
2698 return 0;
2701 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2702 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2704 /* Windows hides the window first, then shows it again
2705 * including the WM_SHOWWINDOW messages and all */
2706 was_visible = ShowWindow( hwnd, SW_HIDE );
2708 wndPtr = WIN_GetPtr( hwnd );
2709 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2711 SERVER_START_REQ( set_parent )
2713 req->handle = wine_server_user_handle( hwnd );
2714 req->parent = wine_server_user_handle( parent );
2715 if ((ret = !wine_server_call( req )))
2717 old_parent = wine_server_ptr_handle( reply->old_parent );
2718 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2722 SERVER_END_REQ;
2723 WIN_ReleasePtr( wndPtr );
2724 if (!ret) return 0;
2726 USER_Driver->pSetParent( full_handle, parent, old_parent );
2728 /* SetParent additionally needs to make hwnd the topmost window
2729 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2730 WM_WINDOWPOSCHANGED notification messages.
2732 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2733 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2734 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2735 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2737 return old_parent;
2741 /*******************************************************************
2742 * IsChild (USER32.@)
2744 BOOL WINAPI IsChild( HWND parent, HWND child )
2746 HWND *list = list_window_parents( child );
2747 int i;
2748 BOOL ret;
2750 if (!list) return FALSE;
2751 parent = WIN_GetFullHandle( parent );
2752 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2753 ret = list[i] && list[i+1];
2754 HeapFree( GetProcessHeap(), 0, list );
2755 return ret;
2759 /***********************************************************************
2760 * IsWindowVisible (USER32.@)
2762 BOOL WINAPI IsWindowVisible( HWND hwnd )
2764 HWND *list;
2765 BOOL retval = TRUE;
2766 int i;
2768 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2769 if (!(list = list_window_parents( hwnd ))) return TRUE;
2770 if (list[0])
2772 for (i = 0; list[i+1]; i++)
2773 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2774 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2776 HeapFree( GetProcessHeap(), 0, list );
2777 return retval;
2781 /***********************************************************************
2782 * WIN_IsWindowDrawable
2784 * hwnd is drawable when it is visible, all parents are not
2785 * minimized, and it is itself not minimized unless we are
2786 * trying to draw its default class icon.
2788 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2790 HWND *list;
2791 BOOL retval = TRUE;
2792 int i;
2793 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2795 if (!(style & WS_VISIBLE)) return FALSE;
2796 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2798 if (!(list = list_window_parents( hwnd ))) return TRUE;
2799 if (list[0])
2801 for (i = 0; list[i+1]; i++)
2802 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2803 break;
2804 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2806 HeapFree( GetProcessHeap(), 0, list );
2807 return retval;
2811 /*******************************************************************
2812 * GetTopWindow (USER32.@)
2814 HWND WINAPI GetTopWindow( HWND hwnd )
2816 if (!hwnd) hwnd = GetDesktopWindow();
2817 return GetWindow( hwnd, GW_CHILD );
2821 /*******************************************************************
2822 * GetWindow (USER32.@)
2824 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2826 HWND retval = 0;
2828 if (rel == GW_OWNER) /* this one may be available locally */
2830 WND *wndPtr = WIN_GetPtr( hwnd );
2831 if (!wndPtr)
2833 SetLastError( ERROR_INVALID_HANDLE );
2834 return 0;
2836 if (wndPtr == WND_DESKTOP) return 0;
2837 if (wndPtr != WND_OTHER_PROCESS)
2839 retval = wndPtr->owner;
2840 WIN_ReleasePtr( wndPtr );
2841 return retval;
2843 /* else fall through to server call */
2846 SERVER_START_REQ( get_window_tree )
2848 req->handle = wine_server_user_handle( hwnd );
2849 if (!wine_server_call_err( req ))
2851 switch(rel)
2853 case GW_HWNDFIRST:
2854 retval = wine_server_ptr_handle( reply->first_sibling );
2855 break;
2856 case GW_HWNDLAST:
2857 retval = wine_server_ptr_handle( reply->last_sibling );
2858 break;
2859 case GW_HWNDNEXT:
2860 retval = wine_server_ptr_handle( reply->next_sibling );
2861 break;
2862 case GW_HWNDPREV:
2863 retval = wine_server_ptr_handle( reply->prev_sibling );
2864 break;
2865 case GW_OWNER:
2866 retval = wine_server_ptr_handle( reply->owner );
2867 break;
2868 case GW_CHILD:
2869 retval = wine_server_ptr_handle( reply->first_child );
2870 break;
2874 SERVER_END_REQ;
2875 return retval;
2879 /*******************************************************************
2880 * ShowOwnedPopups (USER32.@)
2882 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2884 int count = 0;
2885 WND *pWnd;
2886 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2888 if (!win_array) return TRUE;
2890 while (win_array[count]) count++;
2891 while (--count >= 0)
2893 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2894 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2895 if (pWnd == WND_OTHER_PROCESS) continue;
2896 if (fShow)
2898 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2900 WIN_ReleasePtr( pWnd );
2901 /* In Windows, ShowOwnedPopups(TRUE) generates
2902 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2903 * regardless of the state of the owner
2905 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2906 continue;
2909 else
2911 if (pWnd->dwStyle & WS_VISIBLE)
2913 WIN_ReleasePtr( pWnd );
2914 /* In Windows, ShowOwnedPopups(FALSE) generates
2915 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2916 * regardless of the state of the owner
2918 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2919 continue;
2922 WIN_ReleasePtr( pWnd );
2924 HeapFree( GetProcessHeap(), 0, win_array );
2925 return TRUE;
2929 /*******************************************************************
2930 * GetLastActivePopup (USER32.@)
2932 HWND WINAPI GetLastActivePopup( HWND hwnd )
2934 HWND retval = hwnd;
2936 SERVER_START_REQ( get_window_info )
2938 req->handle = wine_server_user_handle( hwnd );
2939 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2941 SERVER_END_REQ;
2942 return retval;
2946 /*******************************************************************
2947 * WIN_ListChildren
2949 * Build an array of the children of a given window. The array must be
2950 * freed with HeapFree. Returns NULL when no windows are found.
2952 HWND *WIN_ListChildren( HWND hwnd )
2954 if (!hwnd)
2956 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2957 return NULL;
2959 return list_window_children( 0, hwnd, NULL, 0 );
2963 /*******************************************************************
2964 * EnumWindows (USER32.@)
2966 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2968 HWND *list;
2969 BOOL ret = TRUE;
2970 int i;
2972 USER_CheckNotLock();
2974 /* We have to build a list of all windows first, to avoid */
2975 /* unpleasant side-effects, for instance if the callback */
2976 /* function changes the Z-order of the windows. */
2978 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2980 /* Now call the callback function for every window */
2982 for (i = 0; list[i]; i++)
2984 /* Make sure that the window still exists */
2985 if (!IsWindow( list[i] )) continue;
2986 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2988 HeapFree( GetProcessHeap(), 0, list );
2989 return ret;
2993 /**********************************************************************
2994 * EnumThreadWindows (USER32.@)
2996 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2998 HWND *list;
2999 int i;
3000 BOOL ret = TRUE;
3002 USER_CheckNotLock();
3004 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3006 /* Now call the callback function for every window */
3008 for (i = 0; list[i]; i++)
3009 if (!(ret = func( list[i], lParam ))) break;
3010 HeapFree( GetProcessHeap(), 0, list );
3011 return ret;
3015 /***********************************************************************
3016 * EnumDesktopWindows (USER32.@)
3018 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3020 HWND *list;
3021 int i;
3023 USER_CheckNotLock();
3025 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3027 for (i = 0; list[i]; i++)
3028 if (!func( list[i], lparam )) break;
3029 HeapFree( GetProcessHeap(), 0, list );
3030 return TRUE;
3034 /**********************************************************************
3035 * WIN_EnumChildWindows
3037 * Helper function for EnumChildWindows().
3039 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3041 HWND *childList;
3042 BOOL ret = FALSE;
3044 for ( ; *list; list++)
3046 /* Make sure that the window still exists */
3047 if (!IsWindow( *list )) continue;
3048 /* Build children list first */
3049 childList = WIN_ListChildren( *list );
3051 ret = func( *list, lParam );
3053 if (childList)
3055 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3056 HeapFree( GetProcessHeap(), 0, childList );
3058 if (!ret) return FALSE;
3060 return TRUE;
3064 /**********************************************************************
3065 * EnumChildWindows (USER32.@)
3067 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3069 HWND *list;
3070 BOOL ret;
3072 USER_CheckNotLock();
3074 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3075 ret = WIN_EnumChildWindows( list, func, lParam );
3076 HeapFree( GetProcessHeap(), 0, list );
3077 return ret;
3081 /*******************************************************************
3082 * AnyPopup (USER32.@)
3084 BOOL WINAPI AnyPopup(void)
3086 int i;
3087 BOOL retvalue;
3088 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3090 if (!list) return FALSE;
3091 for (i = 0; list[i]; i++)
3093 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3095 retvalue = (list[i] != 0);
3096 HeapFree( GetProcessHeap(), 0, list );
3097 return retvalue;
3101 /*******************************************************************
3102 * FlashWindow (USER32.@)
3104 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3106 WND *wndPtr;
3108 TRACE("%p\n", hWnd);
3110 if (IsIconic( hWnd ))
3112 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3114 wndPtr = WIN_GetPtr(hWnd);
3115 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3116 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3118 wndPtr->flags |= WIN_NCACTIVATED;
3120 else
3122 wndPtr->flags &= ~WIN_NCACTIVATED;
3124 WIN_ReleasePtr( wndPtr );
3125 return TRUE;
3127 else
3129 WPARAM wparam;
3131 wndPtr = WIN_GetPtr(hWnd);
3132 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3133 hWnd = wndPtr->obj.handle; /* make it a full handle */
3135 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3136 else wparam = (hWnd == GetForegroundWindow());
3138 WIN_ReleasePtr( wndPtr );
3139 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3140 return wparam;
3144 /*******************************************************************
3145 * FlashWindowEx (USER32.@)
3147 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3149 FIXME("%p\n", pfwi);
3150 return TRUE;
3153 /*******************************************************************
3154 * GetWindowContextHelpId (USER32.@)
3156 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3158 DWORD retval;
3159 WND *wnd = WIN_GetPtr( hwnd );
3160 if (!wnd || wnd == WND_DESKTOP) return 0;
3161 if (wnd == WND_OTHER_PROCESS)
3163 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3164 return 0;
3166 retval = wnd->helpContext;
3167 WIN_ReleasePtr( wnd );
3168 return retval;
3172 /*******************************************************************
3173 * SetWindowContextHelpId (USER32.@)
3175 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3177 WND *wnd = WIN_GetPtr( hwnd );
3178 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3179 if (wnd == WND_OTHER_PROCESS)
3181 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3182 return 0;
3184 wnd->helpContext = id;
3185 WIN_ReleasePtr( wnd );
3186 return TRUE;
3190 /*******************************************************************
3191 * DragDetect (USER32.@)
3193 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3195 MSG msg;
3196 RECT rect;
3197 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3198 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3200 rect.left = pt.x - wDragWidth;
3201 rect.right = pt.x + wDragWidth;
3203 rect.top = pt.y - wDragHeight;
3204 rect.bottom = pt.y + wDragHeight;
3206 SetCapture(hWnd);
3208 while(1)
3210 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3212 if( msg.message == WM_LBUTTONUP )
3214 ReleaseCapture();
3215 return 0;
3217 if( msg.message == WM_MOUSEMOVE )
3219 POINT tmp;
3220 tmp.x = (short)LOWORD(msg.lParam);
3221 tmp.y = (short)HIWORD(msg.lParam);
3222 if( !PtInRect( &rect, tmp ))
3224 ReleaseCapture();
3225 return 1;
3229 WaitMessage();
3231 return 0;
3234 /******************************************************************************
3235 * GetWindowModuleFileNameA (USER32.@)
3237 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3239 WND *win;
3240 HINSTANCE hinst;
3242 TRACE( "%p, %p, %u\n", hwnd, module, size );
3244 win = WIN_GetPtr( hwnd );
3245 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3247 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3248 return 0;
3250 hinst = win->hInstance;
3251 WIN_ReleasePtr( win );
3253 return GetModuleFileNameA( hinst, module, size );
3256 /******************************************************************************
3257 * GetWindowModuleFileNameW (USER32.@)
3259 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3261 WND *win;
3262 HINSTANCE hinst;
3264 TRACE( "%p, %p, %u\n", hwnd, module, size );
3266 win = WIN_GetPtr( hwnd );
3267 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3269 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3270 return 0;
3272 hinst = win->hInstance;
3273 WIN_ReleasePtr( win );
3275 return GetModuleFileNameW( hinst, module, size );
3278 /******************************************************************************
3279 * GetWindowInfo (USER32.@)
3281 * Note: tests show that Windows doesn't check cbSize of the structure.
3283 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3285 if (!pwi) return FALSE;
3286 if (!IsWindow(hwnd)) return FALSE;
3288 GetWindowRect(hwnd, &pwi->rcWindow);
3289 GetClientRect(hwnd, &pwi->rcClient);
3290 /* translate to screen coordinates */
3291 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3293 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3294 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3295 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3297 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3298 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3300 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3301 pwi->wCreatorVersion = 0x0400;
3303 return TRUE;
3306 /******************************************************************************
3307 * SwitchDesktop (USER32.@)
3309 * NOTES: Sets the current input or interactive desktop.
3311 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3313 FIXME("(hwnd %p) stub!\n", hDesktop);
3314 return TRUE;
3317 /*****************************************************************************
3318 * SetLayeredWindowAttributes (USER32.@)
3320 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3322 BOOL ret;
3324 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3326 SERVER_START_REQ( set_window_layered_info )
3328 req->handle = wine_server_user_handle( hwnd );
3329 req->color_key = key;
3330 req->alpha = alpha;
3331 req->flags = flags;
3332 ret = !wine_server_call_err( req );
3334 SERVER_END_REQ;
3336 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3338 return ret;
3342 /*****************************************************************************
3343 * GetLayeredWindowAttributes (USER32.@)
3345 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3347 BOOL ret;
3349 SERVER_START_REQ( get_window_layered_info )
3351 req->handle = wine_server_user_handle( hwnd );
3352 if ((ret = !wine_server_call_err( req )))
3354 if (key) *key = reply->color_key;
3355 if (alpha) *alpha = reply->alpha;
3356 if (flags) *flags = reply->flags;
3359 SERVER_END_REQ;
3361 return ret;
3365 /*****************************************************************************
3366 * UpdateLayeredWindowIndirect (USER32.@)
3368 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3370 BYTE alpha = 0xff;
3372 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3374 int x = 0, y = 0, cx = 0, cy = 0;
3375 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3377 if (info->pptDst)
3379 x = info->pptDst->x;
3380 y = info->pptDst->y;
3381 flags &= ~SWP_NOMOVE;
3383 if (info->psize)
3385 cx = info->psize->cx;
3386 cy = info->psize->cy;
3387 flags &= ~SWP_NOSIZE;
3389 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3390 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3393 if (info->hdcSrc)
3395 RECT rect;
3396 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3398 if (hdc)
3400 int x = 0, y = 0;
3402 GetClientRect( hwnd, &rect );
3403 if (info->pptSrc)
3405 x = info->pptSrc->x;
3406 y = info->pptSrc->y;
3408 /* FIXME: intersect rect with info->prcDirty */
3409 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3410 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3411 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3412 ReleaseDC( hwnd, hdc );
3416 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3417 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3418 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3419 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3420 return TRUE;
3424 /*****************************************************************************
3425 * UpdateLayeredWindow (USER32.@)
3427 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3428 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3429 DWORD dwFlags)
3431 UPDATELAYEREDWINDOWINFO info;
3433 info.cbSize = sizeof(info);
3434 info.hdcDst = hdcDst;
3435 info.pptDst = pptDst;
3436 info.psize = psize;
3437 info.hdcSrc = hdcSrc;
3438 info.pptSrc = pptSrc;
3439 info.crKey = crKey;
3440 info.pblend = pblend;
3441 info.dwFlags = dwFlags;
3442 info.prcDirty = NULL;
3443 return UpdateLayeredWindowIndirect( hwnd, &info );
3446 /* 64bit versions */
3448 #ifdef GetWindowLongPtrW
3449 #undef GetWindowLongPtrW
3450 #endif
3452 #ifdef GetWindowLongPtrA
3453 #undef GetWindowLongPtrA
3454 #endif
3456 #ifdef SetWindowLongPtrW
3457 #undef SetWindowLongPtrW
3458 #endif
3460 #ifdef SetWindowLongPtrA
3461 #undef SetWindowLongPtrA
3462 #endif
3464 /*****************************************************************************
3465 * GetWindowLongPtrW (USER32.@)
3467 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3469 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3472 /*****************************************************************************
3473 * GetWindowLongPtrA (USER32.@)
3475 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3477 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3480 /*****************************************************************************
3481 * SetWindowLongPtrW (USER32.@)
3483 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3485 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3488 /*****************************************************************************
3489 * SetWindowLongPtrA (USER32.@)
3491 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3493 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );