user32: Implement Get/SetProcessDefaultLayout.
[wine.git] / dlls / user32 / win.c
blobbbc7fc2e19143baa719a389dd0e04d971e0931e1
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 static DWORD process_layout;
45 /**********************************************************************/
47 /* helper for Get/SetWindowLong */
48 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
50 if (size == sizeof(WORD))
52 WORD ret;
53 memcpy( &ret, ptr, sizeof(ret) );
54 return ret;
56 else if (size == sizeof(DWORD))
58 DWORD ret;
59 memcpy( &ret, ptr, sizeof(ret) );
60 return ret;
62 else
64 LONG_PTR ret;
65 memcpy( &ret, ptr, sizeof(ret) );
66 return ret;
70 /* helper for Get/SetWindowLong */
71 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
73 if (size == sizeof(WORD))
75 WORD newval = val;
76 memcpy( ptr, &newval, sizeof(newval) );
78 else if (size == sizeof(DWORD))
80 DWORD newval = val;
81 memcpy( ptr, &newval, sizeof(newval) );
83 else
85 memcpy( ptr, &val, sizeof(val) );
90 static void *user_handles[NB_USER_HANDLES];
92 /***********************************************************************
93 * alloc_user_handle
95 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
97 HANDLE handle = 0;
99 SERVER_START_REQ( alloc_user_handle )
101 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
103 SERVER_END_REQ;
105 if (handle)
107 UINT index = USER_HANDLE_TO_INDEX( handle );
109 assert( index < NB_USER_HANDLES );
110 ptr->handle = handle;
111 ptr->type = type;
112 InterlockedExchangePointer( &user_handles[index], ptr );
114 return handle;
118 /***********************************************************************
119 * get_user_handle_ptr
121 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
123 struct user_object *ptr;
124 WORD index = USER_HANDLE_TO_INDEX( handle );
126 if (index >= NB_USER_HANDLES) return NULL;
128 USER_Lock();
129 if ((ptr = user_handles[index]))
131 if (ptr->type == type &&
132 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
133 !HIWORD(handle) || HIWORD(handle) == 0xffff))
134 return ptr;
135 ptr = NULL;
137 else ptr = OBJ_OTHER_PROCESS;
138 USER_Unlock();
139 return ptr;
143 /***********************************************************************
144 * release_user_handle_ptr
146 void release_user_handle_ptr( void *ptr )
148 assert( ptr && ptr != OBJ_OTHER_PROCESS );
149 USER_Unlock();
153 /***********************************************************************
154 * free_user_handle
156 void *free_user_handle( HANDLE handle, enum user_obj_type type )
158 struct user_object *ptr;
159 WORD index = USER_HANDLE_TO_INDEX( handle );
161 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
163 SERVER_START_REQ( free_user_handle )
165 req->handle = wine_server_user_handle( handle );
166 if (wine_server_call( req )) ptr = NULL;
167 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
169 SERVER_END_REQ;
170 release_user_handle_ptr( ptr );
172 return ptr;
176 /***********************************************************************
177 * create_window_handle
179 * Create a window handle with the server.
181 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
182 HINSTANCE instance, BOOL unicode )
184 WORD index;
185 WND *win;
186 HWND handle = 0, full_parent = 0, full_owner = 0;
187 struct tagCLASS *class = NULL;
188 int extra_bytes = 0;
190 SERVER_START_REQ( create_window )
192 req->parent = wine_server_user_handle( parent );
193 req->owner = wine_server_user_handle( owner );
194 req->instance = wine_server_client_ptr( instance );
195 if (!(req->atom = get_int_atom_value( name )) && name)
196 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
197 if (!wine_server_call_err( req ))
199 handle = wine_server_ptr_handle( reply->handle );
200 full_parent = wine_server_ptr_handle( reply->parent );
201 full_owner = wine_server_ptr_handle( reply->owner );
202 extra_bytes = reply->extra;
203 class = wine_server_get_ptr( reply->class_ptr );
206 SERVER_END_REQ;
208 if (!handle)
210 WARN( "error %d creating window\n", GetLastError() );
211 return NULL;
214 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
215 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
217 SERVER_START_REQ( destroy_window )
219 req->handle = wine_server_user_handle( handle );
220 wine_server_call( req );
222 SERVER_END_REQ;
223 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
224 return NULL;
227 if (!parent) /* if parent is 0 we don't have a desktop window yet */
229 struct user_thread_info *thread_info = get_user_thread_info();
231 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
233 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
234 else assert( full_parent == thread_info->top_window );
235 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
236 ERR( "failed to create desktop window\n" );
238 else /* HWND_MESSAGE parent */
240 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
244 USER_Lock();
246 index = USER_HANDLE_TO_INDEX(handle);
247 assert( index < NB_USER_HANDLES );
248 win->obj.handle = handle;
249 win->obj.type = USER_WINDOW;
250 win->parent = full_parent;
251 win->owner = full_owner;
252 win->class = class;
253 win->winproc = get_class_winproc( class );
254 win->cbWndExtra = extra_bytes;
255 InterlockedExchangePointer( &user_handles[index], win );
256 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
257 return win;
261 /***********************************************************************
262 * free_window_handle
264 * Free a window handle.
266 static void free_window_handle( HWND hwnd )
268 struct user_object *ptr;
269 WORD index = USER_HANDLE_TO_INDEX(hwnd);
271 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
273 SERVER_START_REQ( destroy_window )
275 req->handle = wine_server_user_handle( hwnd );
276 if (wine_server_call_err( req )) ptr = NULL;
277 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
279 SERVER_END_REQ;
280 release_user_handle_ptr( ptr );
281 HeapFree( GetProcessHeap(), 0, ptr );
286 /*******************************************************************
287 * list_window_children
289 * Build an array of the children of a given window. The array must be
290 * freed with HeapFree. Returns NULL when no windows are found.
292 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
294 HWND *list;
295 int i, size = 128;
296 ATOM atom = get_int_atom_value( class );
298 /* empty class is not the same as NULL class */
299 if (!atom && class && !class[0]) return NULL;
301 for (;;)
303 int count = 0;
305 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
307 SERVER_START_REQ( get_window_children )
309 req->desktop = wine_server_obj_handle( desktop );
310 req->parent = wine_server_user_handle( hwnd );
311 req->tid = tid;
312 req->atom = atom;
313 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
314 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
315 if (!wine_server_call( req )) count = reply->count;
317 SERVER_END_REQ;
318 if (count && count < size)
320 /* start from the end since HWND is potentially larger than user_handle_t */
321 for (i = count - 1; i >= 0; i--)
322 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
323 list[count] = 0;
324 return list;
326 HeapFree( GetProcessHeap(), 0, list );
327 if (!count) break;
328 size = count + 1; /* restart with a large enough buffer */
330 return NULL;
334 /*******************************************************************
335 * list_window_parents
337 * Build an array of all parents of a given window, starting with
338 * the immediate parent. The array must be freed with HeapFree.
340 static HWND *list_window_parents( HWND hwnd )
342 WND *win;
343 HWND current, *list;
344 int i, pos = 0, size = 16, count = 0;
346 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
348 current = hwnd;
349 for (;;)
351 if (!(win = WIN_GetPtr( current ))) goto empty;
352 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
353 if (win == WND_DESKTOP)
355 if (!pos) goto empty;
356 list[pos] = 0;
357 return list;
359 list[pos] = current = win->parent;
360 WIN_ReleasePtr( win );
361 if (!current) return list;
362 if (++pos == size - 1)
364 /* need to grow the list */
365 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
366 if (!new_list) goto empty;
367 list = new_list;
368 size += 16;
372 /* at least one parent belongs to another process, have to query the server */
374 for (;;)
376 count = 0;
377 SERVER_START_REQ( get_window_parents )
379 req->handle = wine_server_user_handle( hwnd );
380 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
381 if (!wine_server_call( req )) count = reply->count;
383 SERVER_END_REQ;
384 if (!count) goto empty;
385 if (size > count)
387 /* start from the end since HWND is potentially larger than user_handle_t */
388 for (i = count - 1; i >= 0; i--)
389 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
390 list[count] = 0;
391 return list;
393 HeapFree( GetProcessHeap(), 0, list );
394 size = count + 1;
395 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
398 empty:
399 HeapFree( GetProcessHeap(), 0, list );
400 return NULL;
404 /*******************************************************************
405 * send_parent_notify
407 static void send_parent_notify( HWND hwnd, UINT msg )
409 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
410 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
412 HWND parent = GetParent(hwnd);
413 if (parent && parent != GetDesktopWindow())
414 SendMessageW( parent, WM_PARENTNOTIFY,
415 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
420 /*******************************************************************
421 * get_server_window_text
423 * Retrieve the window text from the server.
425 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
427 size_t len = 0;
429 SERVER_START_REQ( get_window_text )
431 req->handle = wine_server_user_handle( hwnd );
432 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
433 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
435 SERVER_END_REQ;
436 text[len / sizeof(WCHAR)] = 0;
440 /*******************************************************************
441 * get_hwnd_message_parent
443 * Return the parent for HWND_MESSAGE windows.
445 HWND get_hwnd_message_parent(void)
447 struct user_thread_info *thread_info = get_user_thread_info();
449 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
450 return thread_info->msg_window;
454 /*******************************************************************
455 * is_desktop_window
457 * Check if window is the desktop or the HWND_MESSAGE top parent.
459 BOOL is_desktop_window( HWND hwnd )
461 struct user_thread_info *thread_info = get_user_thread_info();
463 if (!hwnd) return FALSE;
464 if (hwnd == thread_info->top_window) return TRUE;
465 if (hwnd == thread_info->msg_window) return TRUE;
467 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
469 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
470 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
472 return FALSE;
476 /***********************************************************************
477 * WIN_GetPtr
479 * Return a pointer to the WND structure if local to the process,
480 * or WND_OTHER_PROCESS if handle may be valid in other process.
481 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
483 WND *WIN_GetPtr( HWND hwnd )
485 WND *ptr;
487 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
489 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
491 return ptr;
495 /***********************************************************************
496 * WIN_IsCurrentProcess
498 * Check whether a given window belongs to the current process (and return the full handle).
500 HWND WIN_IsCurrentProcess( HWND hwnd )
502 WND *ptr;
503 HWND ret;
505 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
506 ret = ptr->obj.handle;
507 WIN_ReleasePtr( ptr );
508 return ret;
512 /***********************************************************************
513 * WIN_IsCurrentThread
515 * Check whether a given window belongs to the current thread (and return the full handle).
517 HWND WIN_IsCurrentThread( HWND hwnd )
519 WND *ptr;
520 HWND ret = 0;
522 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
523 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
524 WIN_ReleasePtr( ptr );
525 return ret;
529 /***********************************************************************
530 * WIN_GetFullHandle
532 * Convert a possibly truncated window handle to a full 32-bit handle.
534 HWND WIN_GetFullHandle( HWND hwnd )
536 WND *ptr;
538 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
539 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
540 /* do sign extension for -2 and -3 */
541 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
543 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
545 if (ptr == WND_DESKTOP)
547 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
548 else return get_hwnd_message_parent();
551 if (ptr != WND_OTHER_PROCESS)
553 hwnd = ptr->obj.handle;
554 WIN_ReleasePtr( ptr );
556 else /* may belong to another process */
558 SERVER_START_REQ( get_window_info )
560 req->handle = wine_server_user_handle( hwnd );
561 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
563 SERVER_END_REQ;
565 return hwnd;
569 /***********************************************************************
570 * WIN_SetOwner
572 * Change the owner of a window.
574 HWND WIN_SetOwner( HWND hwnd, HWND owner )
576 WND *win = WIN_GetPtr( hwnd );
577 HWND ret = 0;
579 if (!win || win == WND_DESKTOP) return 0;
580 if (win == WND_OTHER_PROCESS)
582 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
583 return 0;
585 SERVER_START_REQ( set_window_owner )
587 req->handle = wine_server_user_handle( hwnd );
588 req->owner = wine_server_user_handle( owner );
589 if (!wine_server_call( req ))
591 win->owner = wine_server_ptr_handle( reply->full_owner );
592 ret = wine_server_ptr_handle( reply->prev_owner );
595 SERVER_END_REQ;
596 WIN_ReleasePtr( win );
597 return ret;
601 /***********************************************************************
602 * WIN_SetStyle
604 * Change the style of a window.
606 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
608 BOOL ok;
609 STYLESTRUCT style;
610 WND *win = WIN_GetPtr( hwnd );
612 if (!win || win == WND_DESKTOP) return 0;
613 if (win == WND_OTHER_PROCESS)
615 if (IsWindow(hwnd))
616 ERR( "cannot set style %x/%x on other process window %p\n",
617 set_bits, clear_bits, hwnd );
618 return 0;
620 style.styleOld = win->dwStyle;
621 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
622 if (style.styleNew == style.styleOld)
624 WIN_ReleasePtr( win );
625 return style.styleNew;
627 SERVER_START_REQ( set_window_info )
629 req->handle = wine_server_user_handle( hwnd );
630 req->flags = SET_WIN_STYLE;
631 req->style = style.styleNew;
632 req->extra_offset = -1;
633 if ((ok = !wine_server_call( req )))
635 style.styleOld = reply->old_style;
636 win->dwStyle = style.styleNew;
639 SERVER_END_REQ;
640 WIN_ReleasePtr( win );
641 if (ok)
643 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
644 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
646 return style.styleOld;
650 /***********************************************************************
651 * WIN_GetRectangles
653 * Get the window and client rectangles.
655 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
657 WND *win = WIN_GetPtr( hwnd );
658 BOOL ret = TRUE;
660 if (!win)
662 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
663 return FALSE;
665 if (win == WND_DESKTOP)
667 RECT rect;
668 rect.left = rect.top = 0;
669 if (hwnd == get_hwnd_message_parent())
671 rect.right = 100;
672 rect.bottom = 100;
674 else
676 rect.right = GetSystemMetrics(SM_CXSCREEN);
677 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
679 if (rectWindow) *rectWindow = rect;
680 if (rectClient) *rectClient = rect;
682 else if (win == WND_OTHER_PROCESS)
684 SERVER_START_REQ( get_window_rectangles )
686 req->handle = wine_server_user_handle( hwnd );
687 if ((ret = !wine_server_call_err( req )))
689 if (rectWindow)
691 rectWindow->left = reply->window.left;
692 rectWindow->top = reply->window.top;
693 rectWindow->right = reply->window.right;
694 rectWindow->bottom = reply->window.bottom;
696 if (rectClient)
698 rectClient->left = reply->client.left;
699 rectClient->top = reply->client.top;
700 rectClient->right = reply->client.right;
701 rectClient->bottom = reply->client.bottom;
705 SERVER_END_REQ;
707 else
709 if (rectWindow) *rectWindow = win->rectWindow;
710 if (rectClient) *rectClient = win->rectClient;
711 WIN_ReleasePtr( win );
713 return ret;
717 /***********************************************************************
718 * WIN_DestroyWindow
720 * Destroy storage associated to a window. "Internals" p.358
722 LRESULT WIN_DestroyWindow( HWND hwnd )
724 WND *wndPtr;
725 HWND *list;
726 HMENU menu = 0, sys_menu;
727 HWND icon_title;
729 TRACE("%p\n", hwnd );
731 /* free child windows */
732 if ((list = WIN_ListChildren( hwnd )))
734 int i;
735 for (i = 0; list[i]; i++)
737 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
738 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
740 HeapFree( GetProcessHeap(), 0, list );
743 /* Unlink now so we won't bother with the children later on */
744 SERVER_START_REQ( set_parent )
746 req->handle = wine_server_user_handle( hwnd );
747 req->parent = 0;
748 wine_server_call( req );
750 SERVER_END_REQ;
753 * Send the WM_NCDESTROY to the window being destroyed.
755 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
757 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
759 /* free resources associated with the window */
761 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
762 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
763 menu = (HMENU)wndPtr->wIDmenu;
764 sys_menu = wndPtr->hSysMenu;
765 free_dce( wndPtr->dce, hwnd );
766 wndPtr->dce = NULL;
767 icon_title = wndPtr->icon_title;
768 HeapFree( GetProcessHeap(), 0, wndPtr->text );
769 wndPtr->text = NULL;
770 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
771 wndPtr->pScroll = NULL;
772 WIN_ReleasePtr( wndPtr );
774 if (icon_title) DestroyWindow( icon_title );
775 if (menu) DestroyMenu( menu );
776 if (sys_menu) DestroyMenu( sys_menu );
778 USER_Driver->pDestroyWindow( hwnd );
780 free_window_handle( hwnd );
781 return 0;
785 /***********************************************************************
786 * destroy_thread_window
788 * Destroy a window upon exit of its thread.
790 static void destroy_thread_window( HWND hwnd )
792 WND *wndPtr;
793 HWND *list;
794 HMENU menu = 0, sys_menu = 0;
795 WORD index;
797 /* free child windows */
799 if ((list = WIN_ListChildren( hwnd )))
801 int i;
802 for (i = 0; list[i]; i++)
804 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
805 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
807 HeapFree( GetProcessHeap(), 0, list );
810 /* destroy the client-side storage */
812 index = USER_HANDLE_TO_INDEX(hwnd);
813 if (index >= NB_USER_HANDLES) return;
814 USER_Lock();
815 if ((wndPtr = user_handles[index]))
817 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
818 sys_menu = wndPtr->hSysMenu;
819 free_dce( wndPtr->dce, hwnd );
820 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
822 USER_Unlock();
824 HeapFree( GetProcessHeap(), 0, wndPtr );
825 if (menu) DestroyMenu( menu );
826 if (sys_menu) DestroyMenu( sys_menu );
830 /***********************************************************************
831 * destroy_thread_child_windows
833 * Destroy child windows upon exit of its thread.
835 static void destroy_thread_child_windows( HWND hwnd )
837 HWND *list;
838 int i;
840 if (WIN_IsCurrentThread( hwnd ))
842 destroy_thread_window( hwnd );
844 else if ((list = WIN_ListChildren( hwnd )))
846 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
847 HeapFree( GetProcessHeap(), 0, list );
852 /***********************************************************************
853 * WIN_DestroyThreadWindows
855 * Destroy all children of 'wnd' owned by the current thread.
857 void WIN_DestroyThreadWindows( HWND hwnd )
859 HWND *list;
860 int i;
862 if (!(list = WIN_ListChildren( hwnd ))) return;
864 /* reset owners of top-level windows */
865 for (i = 0; list[i]; i++)
867 if (!WIN_IsCurrentThread( list[i] ))
869 HWND owner = GetWindow( list[i], GW_OWNER );
870 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
874 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
875 HeapFree( GetProcessHeap(), 0, list );
879 /***********************************************************************
880 * WIN_FixCoordinates
882 * Fix the coordinates - Helper for WIN_CreateWindowEx.
883 * returns default show mode in sw.
885 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
887 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
888 POINT pos[2];
890 if (cs->dwExStyle & WS_EX_MDICHILD)
892 UINT id = 0;
894 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
895 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
897 TRACE("MDI child id %04x\n", id);
900 if (cs->style & (WS_CHILD | WS_POPUP))
902 if (cs->dwExStyle & WS_EX_MDICHILD)
904 if (IS_DEFAULT(cs->x))
906 cs->x = pos[0].x;
907 cs->y = pos[0].y;
909 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
910 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
912 else
914 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
915 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
918 else /* overlapped window */
920 HMONITOR monitor;
921 MONITORINFO mon_info;
922 STARTUPINFOW info;
924 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
926 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
927 mon_info.cbSize = sizeof(mon_info);
928 GetMonitorInfoW( monitor, &mon_info );
929 GetStartupInfoW( &info );
931 if (IS_DEFAULT(cs->x))
933 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
934 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
935 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
938 if (IS_DEFAULT(cs->cx))
940 if (info.dwFlags & STARTF_USESIZE)
942 cs->cx = info.dwXSize;
943 cs->cy = info.dwYSize;
945 else
947 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
948 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
951 /* neither x nor cx are default. Check the y values .
952 * In the trace we see Outlook and Outlook Express using
953 * cy set to CW_USEDEFAULT when opening the address book.
955 else if (IS_DEFAULT(cs->cy))
957 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
958 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
961 #undef IS_DEFAULT
964 /***********************************************************************
965 * dump_window_styles
967 static void dump_window_styles( DWORD style, DWORD exstyle )
969 TRACE( "style:" );
970 if(style & WS_POPUP) TRACE(" WS_POPUP");
971 if(style & WS_CHILD) TRACE(" WS_CHILD");
972 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
973 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
974 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
975 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
976 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
977 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
978 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
979 else
981 if(style & WS_BORDER) TRACE(" WS_BORDER");
982 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
984 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
985 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
986 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
987 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
988 if (style & WS_CHILD)
990 if(style & WS_GROUP) TRACE(" WS_GROUP");
991 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
993 else
995 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
996 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
999 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1000 #define DUMPED_STYLES \
1001 (WS_POPUP | \
1002 WS_CHILD | \
1003 WS_MINIMIZE | \
1004 WS_VISIBLE | \
1005 WS_DISABLED | \
1006 WS_CLIPSIBLINGS | \
1007 WS_CLIPCHILDREN | \
1008 WS_MAXIMIZE | \
1009 WS_BORDER | \
1010 WS_DLGFRAME | \
1011 WS_VSCROLL | \
1012 WS_HSCROLL | \
1013 WS_SYSMENU | \
1014 WS_THICKFRAME | \
1015 WS_GROUP | \
1016 WS_TABSTOP | \
1017 WS_MINIMIZEBOX | \
1018 WS_MAXIMIZEBOX)
1020 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1021 TRACE("\n");
1022 #undef DUMPED_STYLES
1024 TRACE( "exstyle:" );
1025 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1026 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1027 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1028 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1029 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1030 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1031 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1032 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1033 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1034 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1035 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1036 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1037 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1038 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1039 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1040 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1041 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1042 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1043 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1045 #define DUMPED_EX_STYLES \
1046 (WS_EX_DLGMODALFRAME | \
1047 WS_EX_DRAGDETECT | \
1048 WS_EX_NOPARENTNOTIFY | \
1049 WS_EX_TOPMOST | \
1050 WS_EX_ACCEPTFILES | \
1051 WS_EX_TRANSPARENT | \
1052 WS_EX_MDICHILD | \
1053 WS_EX_TOOLWINDOW | \
1054 WS_EX_WINDOWEDGE | \
1055 WS_EX_CLIENTEDGE | \
1056 WS_EX_CONTEXTHELP | \
1057 WS_EX_RIGHT | \
1058 WS_EX_RTLREADING | \
1059 WS_EX_LEFTSCROLLBAR | \
1060 WS_EX_CONTROLPARENT | \
1061 WS_EX_STATICEDGE | \
1062 WS_EX_APPWINDOW | \
1063 WS_EX_LAYERED | \
1064 WS_EX_LAYOUTRTL)
1066 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1067 TRACE("\n");
1068 #undef DUMPED_EX_STYLES
1072 /***********************************************************************
1073 * WIN_CreateWindowEx
1075 * Implementation of CreateWindowEx().
1077 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1079 INT cx, cy, style, sw = SW_SHOW;
1080 LRESULT result;
1081 RECT rect;
1082 WND *wndPtr;
1083 HWND hwnd, parent, owner, top_child = 0;
1084 MDICREATESTRUCTW mdi_cs;
1085 CBT_CREATEWNDW cbtc;
1086 CREATESTRUCTW cbcs;
1088 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1089 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1090 debugstr_w(className),
1091 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1092 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1093 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1095 /* Fix the styles for MDI children */
1096 if (cs->dwExStyle & WS_EX_MDICHILD)
1098 UINT flags = 0;
1100 wndPtr = WIN_GetPtr(cs->hwndParent);
1101 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1103 flags = wndPtr->flags;
1104 WIN_ReleasePtr(wndPtr);
1107 if (!(flags & WIN_ISMDICLIENT))
1109 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1110 return 0;
1113 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1114 * MDICREATESTRUCT members have the originally passed values.
1116 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1117 * have the same layout.
1119 mdi_cs.szClass = cs->lpszClass;
1120 mdi_cs.szTitle = cs->lpszName;
1121 mdi_cs.hOwner = cs->hInstance;
1122 mdi_cs.x = cs->x;
1123 mdi_cs.y = cs->y;
1124 mdi_cs.cx = cs->cx;
1125 mdi_cs.cy = cs->cy;
1126 mdi_cs.style = cs->style;
1127 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1129 cs->lpCreateParams = &mdi_cs;
1131 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1133 if (cs->style & WS_POPUP)
1135 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1136 return 0;
1138 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1140 else
1142 cs->style &= ~WS_POPUP;
1143 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1144 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1147 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1149 if (top_child)
1151 /* Restore current maximized child */
1152 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1154 TRACE("Restoring current maximized child %p\n", top_child);
1155 if (cs->style & WS_MAXIMIZE)
1157 /* if the new window is maximized don't bother repainting */
1158 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1159 ShowWindow( top_child, SW_SHOWNORMAL );
1160 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1162 else ShowWindow( top_child, SW_SHOWNORMAL );
1167 /* Find the parent window */
1169 parent = cs->hwndParent;
1170 owner = 0;
1172 if (cs->hwndParent == HWND_MESSAGE)
1174 cs->hwndParent = parent = get_hwnd_message_parent();
1176 else if (cs->hwndParent)
1178 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1180 parent = GetDesktopWindow();
1181 owner = cs->hwndParent;
1183 else
1185 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1186 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1187 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1190 else
1192 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1194 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1196 WARN("No parent for child window\n" );
1197 SetLastError(ERROR_TLW_WITH_WSCHILD);
1198 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1200 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1201 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1202 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1203 parent = GetDesktopWindow();
1204 if (process_layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1207 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1209 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1210 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1211 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1212 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1213 else
1214 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1216 /* Create the window structure */
1218 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1219 return 0;
1220 hwnd = wndPtr->obj.handle;
1222 /* Fill the window structure */
1224 wndPtr->tid = GetCurrentThreadId();
1225 wndPtr->hInstance = cs->hInstance;
1226 wndPtr->text = NULL;
1227 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1228 wndPtr->dwExStyle = cs->dwExStyle;
1229 wndPtr->wIDmenu = 0;
1230 wndPtr->helpContext = 0;
1231 wndPtr->pScroll = NULL;
1232 wndPtr->userdata = 0;
1233 wndPtr->hIcon = 0;
1234 wndPtr->hIconSmall = 0;
1235 wndPtr->hSysMenu = 0;
1237 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1238 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1240 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1243 * Correct the window styles.
1245 * It affects only the style loaded into the WIN structure.
1248 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1250 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1251 if (!(wndPtr->dwStyle & WS_POPUP))
1252 wndPtr->dwStyle |= WS_CAPTION;
1256 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1257 * why does the user get to set it?
1260 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1261 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1262 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1263 else
1264 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1266 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1267 wndPtr->flags |= WIN_NEED_SIZE;
1269 SERVER_START_REQ( set_window_info )
1271 req->handle = wine_server_user_handle( hwnd );
1272 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1273 req->style = wndPtr->dwStyle;
1274 req->ex_style = wndPtr->dwExStyle;
1275 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1276 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1277 req->extra_offset = -1;
1278 wine_server_call( req );
1280 SERVER_END_REQ;
1282 /* Set the window menu */
1284 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1286 if (cs->hMenu)
1288 if (!MENU_SetMenu(hwnd, cs->hMenu))
1290 WIN_ReleasePtr( wndPtr );
1291 free_window_handle( hwnd );
1292 return 0;
1295 else
1297 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1298 if (menuName)
1300 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1301 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1305 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1307 /* call the WH_CBT hook */
1309 /* the window style passed to the hook must be the real window style,
1310 * rather than just the window style that the caller to CreateWindowEx
1311 * passed in, so we have to copy the original CREATESTRUCT and get the
1312 * the real style. */
1313 cbcs = *cs;
1314 cbcs.style = wndPtr->dwStyle;
1315 cbtc.lpcs = &cbcs;
1316 cbtc.hwndInsertAfter = HWND_TOP;
1317 WIN_ReleasePtr( wndPtr );
1318 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1320 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1322 cx = cs->cx;
1323 cy = cs->cy;
1324 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1326 POINT maxSize, maxPos, minTrack, maxTrack;
1327 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1328 if (maxTrack.x < cx) cx = maxTrack.x;
1329 if (maxTrack.y < cy) cy = maxTrack.y;
1330 if (minTrack.x > cx) cx = minTrack.x;
1331 if (minTrack.y > cy) cy = minTrack.y;
1334 if (cx < 0) cx = 0;
1335 if (cy < 0) cy = 0;
1336 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1337 /* check for wraparound */
1338 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1339 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1340 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1342 /* send WM_NCCREATE */
1344 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1345 if (unicode)
1346 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1347 else
1348 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1349 if (!result)
1351 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1352 goto failed;
1355 /* send WM_NCCALCSIZE */
1357 if ((wndPtr = WIN_GetPtr(hwnd)))
1359 /* yes, even if the CBT hook was called with HWND_TOP */
1360 POINT pt;
1361 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1362 RECT window_rect = wndPtr->rectWindow;
1363 RECT client_rect = window_rect;
1364 WIN_ReleasePtr( wndPtr );
1366 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1367 pt.x = pt.y = 0;
1368 MapWindowPoints( parent, 0, &pt, 1 );
1369 OffsetRect( &client_rect, pt.x, pt.y );
1370 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1371 OffsetRect( &client_rect, -pt.x, -pt.y );
1372 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1374 else return 0;
1376 /* send WM_CREATE */
1378 if (unicode)
1379 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1380 else
1381 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1382 if (result == -1) goto failed;
1384 /* call the driver */
1386 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1388 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1390 /* send the size messages */
1392 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1393 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1394 if (!(wndPtr->flags & WIN_NEED_SIZE))
1396 rect = wndPtr->rectClient;
1397 WIN_ReleasePtr( wndPtr );
1398 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1399 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1400 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1402 else WIN_ReleasePtr( wndPtr );
1404 /* Show the window, maximizing or minimizing if needed */
1406 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1407 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1409 RECT newPos;
1410 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1412 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1413 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1414 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1415 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1416 newPos.bottom - newPos.top, swFlag );
1419 /* Notify the parent window only */
1421 send_parent_notify( hwnd, WM_CREATE );
1422 if (!IsWindow( hwnd )) return 0;
1424 if (cs->style & WS_VISIBLE)
1426 if (cs->style & WS_MAXIMIZE)
1427 sw = SW_SHOW;
1428 else if (cs->style & WS_MINIMIZE)
1429 sw = SW_SHOWMINIMIZED;
1431 ShowWindow( hwnd, sw );
1432 if (cs->dwExStyle & WS_EX_MDICHILD)
1434 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1435 /* ShowWindow won't activate child windows */
1436 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1440 /* Call WH_SHELL hook */
1442 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1443 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1445 TRACE("created window %p\n", hwnd);
1446 return hwnd;
1448 failed:
1449 WIN_DestroyWindow( hwnd );
1450 return 0;
1454 /***********************************************************************
1455 * CreateWindowExA (USER32.@)
1457 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1458 LPCSTR windowName, DWORD style, INT x,
1459 INT y, INT width, INT height,
1460 HWND parent, HMENU menu,
1461 HINSTANCE instance, LPVOID data )
1463 CREATESTRUCTA cs;
1465 cs.lpCreateParams = data;
1466 cs.hInstance = instance;
1467 cs.hMenu = menu;
1468 cs.hwndParent = parent;
1469 cs.x = x;
1470 cs.y = y;
1471 cs.cx = width;
1472 cs.cy = height;
1473 cs.style = style;
1474 cs.lpszName = windowName;
1475 cs.lpszClass = className;
1476 cs.dwExStyle = exStyle;
1478 if (!IS_INTRESOURCE(className))
1480 WCHAR bufferW[256];
1481 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1482 return 0;
1483 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1485 /* Note: we rely on the fact that CREATESTRUCTA and */
1486 /* CREATESTRUCTW have the same layout. */
1487 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1491 /***********************************************************************
1492 * CreateWindowExW (USER32.@)
1494 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1495 LPCWSTR windowName, DWORD style, INT x,
1496 INT y, INT width, INT height,
1497 HWND parent, HMENU menu,
1498 HINSTANCE instance, LPVOID data )
1500 CREATESTRUCTW cs;
1502 cs.lpCreateParams = data;
1503 cs.hInstance = instance;
1504 cs.hMenu = menu;
1505 cs.hwndParent = parent;
1506 cs.x = x;
1507 cs.y = y;
1508 cs.cx = width;
1509 cs.cy = height;
1510 cs.style = style;
1511 cs.lpszName = windowName;
1512 cs.lpszClass = className;
1513 cs.dwExStyle = exStyle;
1515 return wow_handlers.create_window( &cs, className, instance, TRUE );
1519 /***********************************************************************
1520 * WIN_SendDestroyMsg
1522 static void WIN_SendDestroyMsg( HWND hwnd )
1524 GUITHREADINFO info;
1526 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1528 if (hwnd == info.hwndCaret) DestroyCaret();
1529 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1533 * Send the WM_DESTROY to the window.
1535 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1538 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1539 * make sure that the window still exists when we come back.
1541 if (IsWindow(hwnd))
1543 HWND* pWndArray;
1544 int i;
1546 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1548 for (i = 0; pWndArray[i]; i++)
1550 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1552 HeapFree( GetProcessHeap(), 0, pWndArray );
1554 else
1555 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1559 /***********************************************************************
1560 * DestroyWindow (USER32.@)
1562 BOOL WINAPI DestroyWindow( HWND hwnd )
1564 BOOL is_child;
1566 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1568 SetLastError( ERROR_ACCESS_DENIED );
1569 return FALSE;
1572 TRACE("(%p)\n", hwnd);
1574 /* Call hooks */
1576 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1578 if (MENU_IsMenuActive() == hwnd)
1579 EndMenu();
1581 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1583 if (is_child)
1585 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1586 send_parent_notify( hwnd, WM_DESTROY );
1588 else if (!GetWindow( hwnd, GW_OWNER ))
1590 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1591 /* FIXME: clean up palette - see "Internals" p.352 */
1594 if (!IsWindow(hwnd)) return TRUE;
1596 /* Hide the window */
1597 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1599 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1600 if (is_child)
1601 ShowWindow( hwnd, SW_HIDE );
1602 else
1603 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1604 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1607 if (!IsWindow(hwnd)) return TRUE;
1609 /* Recursively destroy owned windows */
1611 if (!is_child)
1613 for (;;)
1615 int i, got_one = 0;
1616 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1617 if (list)
1619 for (i = 0; list[i]; i++)
1621 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1622 if (WIN_IsCurrentThread( list[i] ))
1624 DestroyWindow( list[i] );
1625 got_one = 1;
1626 continue;
1628 WIN_SetOwner( list[i], 0 );
1630 HeapFree( GetProcessHeap(), 0, list );
1632 if (!got_one) break;
1636 /* Send destroy messages */
1638 WIN_SendDestroyMsg( hwnd );
1639 if (!IsWindow( hwnd )) return TRUE;
1641 if (GetClipboardOwner() == hwnd)
1642 CLIPBOARD_ReleaseOwner();
1644 /* Destroy the window storage */
1646 WIN_DestroyWindow( hwnd );
1647 return TRUE;
1651 /***********************************************************************
1652 * CloseWindow (USER32.@)
1654 BOOL WINAPI CloseWindow( HWND hwnd )
1656 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1657 ShowWindow( hwnd, SW_MINIMIZE );
1658 return TRUE;
1662 /***********************************************************************
1663 * OpenIcon (USER32.@)
1665 BOOL WINAPI OpenIcon( HWND hwnd )
1667 if (!IsIconic( hwnd )) return FALSE;
1668 ShowWindow( hwnd, SW_SHOWNORMAL );
1669 return TRUE;
1673 /***********************************************************************
1674 * FindWindowExW (USER32.@)
1676 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1678 HWND *list = NULL;
1679 HWND retvalue = 0;
1680 int i = 0, len = 0;
1681 WCHAR *buffer = NULL;
1683 if (!parent && child) parent = GetDesktopWindow();
1684 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1686 if (title)
1688 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1689 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1692 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1694 if (child)
1696 child = WIN_GetFullHandle( child );
1697 while (list[i] && list[i] != child) i++;
1698 if (!list[i]) goto done;
1699 i++; /* start from next window */
1702 if (title)
1704 while (list[i])
1706 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1707 i++;
1710 retvalue = list[i];
1712 done:
1713 HeapFree( GetProcessHeap(), 0, list );
1714 HeapFree( GetProcessHeap(), 0, buffer );
1715 return retvalue;
1720 /***********************************************************************
1721 * FindWindowA (USER32.@)
1723 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1725 HWND ret = FindWindowExA( 0, 0, className, title );
1726 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1727 return ret;
1731 /***********************************************************************
1732 * FindWindowExA (USER32.@)
1734 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1736 LPWSTR titleW = NULL;
1737 HWND hwnd = 0;
1739 if (title)
1741 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1742 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1743 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1746 if (!IS_INTRESOURCE(className))
1748 WCHAR classW[256];
1749 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1750 hwnd = FindWindowExW( parent, child, classW, titleW );
1752 else
1754 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1757 HeapFree( GetProcessHeap(), 0, titleW );
1758 return hwnd;
1762 /***********************************************************************
1763 * FindWindowW (USER32.@)
1765 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1767 return FindWindowExW( 0, 0, className, title );
1771 /**********************************************************************
1772 * GetDesktopWindow (USER32.@)
1774 HWND WINAPI GetDesktopWindow(void)
1776 struct user_thread_info *thread_info = get_user_thread_info();
1778 if (thread_info->top_window) return thread_info->top_window;
1780 SERVER_START_REQ( get_desktop_window )
1782 req->force = 0;
1783 if (!wine_server_call( req ))
1785 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1786 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1789 SERVER_END_REQ;
1791 if (!thread_info->top_window)
1793 USEROBJECTFLAGS flags;
1794 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1795 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1797 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1798 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1799 STARTUPINFOW si;
1800 PROCESS_INFORMATION pi;
1801 WCHAR windir[MAX_PATH];
1802 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1803 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1804 void *redir;
1806 memset( &si, 0, sizeof(si) );
1807 si.cb = sizeof(si);
1808 si.dwFlags = STARTF_USESTDHANDLES;
1809 si.hStdInput = 0;
1810 si.hStdOutput = 0;
1811 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1813 GetSystemDirectoryW( windir, MAX_PATH );
1814 strcpyW( app, windir );
1815 strcatW( app, explorer );
1816 strcpyW( cmdline, app );
1817 strcatW( cmdline, args );
1819 Wow64DisableWow64FsRedirection( &redir );
1820 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1821 NULL, windir, &si, &pi ))
1823 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1824 WaitForInputIdle( pi.hProcess, 10000 );
1825 CloseHandle( pi.hThread );
1826 CloseHandle( pi.hProcess );
1828 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1829 Wow64RevertWow64FsRedirection( redir );
1831 else TRACE( "not starting explorer since winstation is not visible\n" );
1833 SERVER_START_REQ( get_desktop_window )
1835 req->force = 1;
1836 if (!wine_server_call( req ))
1838 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1839 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1842 SERVER_END_REQ;
1845 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1846 ERR( "failed to create desktop window\n" );
1848 return thread_info->top_window;
1852 /*******************************************************************
1853 * EnableWindow (USER32.@)
1855 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1857 BOOL retvalue;
1858 HWND full_handle;
1860 if (is_broadcast(hwnd))
1862 SetLastError( ERROR_INVALID_PARAMETER );
1863 return FALSE;
1866 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1867 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1869 hwnd = full_handle;
1871 TRACE("( %p, %d )\n", hwnd, enable);
1873 retvalue = !IsWindowEnabled( hwnd );
1875 if (enable && retvalue)
1877 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1878 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1880 else if (!enable && !retvalue)
1882 HWND capture_wnd;
1884 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1886 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1888 if (hwnd == GetFocus())
1889 SetFocus( 0 ); /* A disabled window can't have the focus */
1891 capture_wnd = GetCapture();
1892 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1893 ReleaseCapture(); /* A disabled window can't capture the mouse */
1895 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1897 return retvalue;
1901 /***********************************************************************
1902 * IsWindowEnabled (USER32.@)
1904 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1906 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1910 /***********************************************************************
1911 * IsWindowUnicode (USER32.@)
1913 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1915 WND * wndPtr;
1916 BOOL retvalue = FALSE;
1918 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1920 if (wndPtr == WND_DESKTOP) return TRUE;
1922 if (wndPtr != WND_OTHER_PROCESS)
1924 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1925 WIN_ReleasePtr( wndPtr );
1927 else
1929 SERVER_START_REQ( get_window_info )
1931 req->handle = wine_server_user_handle( hwnd );
1932 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1934 SERVER_END_REQ;
1936 return retvalue;
1940 /**********************************************************************
1941 * WIN_GetWindowLong
1943 * Helper function for GetWindowLong().
1945 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1947 LONG_PTR retvalue = 0;
1948 WND *wndPtr;
1950 if (offset == GWLP_HWNDPARENT)
1952 HWND parent = GetAncestor( hwnd, GA_PARENT );
1953 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1954 return (ULONG_PTR)parent;
1957 if (!(wndPtr = WIN_GetPtr( hwnd )))
1959 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1960 return 0;
1963 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1965 if (offset == GWLP_WNDPROC)
1967 SetLastError( ERROR_ACCESS_DENIED );
1968 return 0;
1970 SERVER_START_REQ( set_window_info )
1972 req->handle = wine_server_user_handle( hwnd );
1973 req->flags = 0; /* don't set anything, just retrieve */
1974 req->extra_offset = (offset >= 0) ? offset : -1;
1975 req->extra_size = (offset >= 0) ? size : 0;
1976 if (!wine_server_call_err( req ))
1978 switch(offset)
1980 case GWL_STYLE: retvalue = reply->old_style; break;
1981 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1982 case GWLP_ID: retvalue = reply->old_id; break;
1983 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1984 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1985 default:
1986 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1987 else SetLastError( ERROR_INVALID_INDEX );
1988 break;
1992 SERVER_END_REQ;
1993 return retvalue;
1996 /* now we have a valid wndPtr */
1998 if (offset >= 0)
2000 if (offset > (int)(wndPtr->cbWndExtra - size))
2002 WARN("Invalid offset %d\n", offset );
2003 WIN_ReleasePtr( wndPtr );
2004 SetLastError( ERROR_INVALID_INDEX );
2005 return 0;
2007 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2009 /* Special case for dialog window procedure */
2010 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2011 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2012 WIN_ReleasePtr( wndPtr );
2013 return retvalue;
2016 switch(offset)
2018 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2019 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2020 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2021 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2022 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2023 case GWLP_WNDPROC:
2024 /* This looks like a hack only for the edit control (see tests). This makes these controls
2025 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2026 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2028 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2029 retvalue = (ULONG_PTR)wndPtr->winproc;
2030 else
2031 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2032 break;
2033 default:
2034 WARN("Unknown offset %d\n", offset );
2035 SetLastError( ERROR_INVALID_INDEX );
2036 break;
2038 WIN_ReleasePtr(wndPtr);
2039 return retvalue;
2043 /**********************************************************************
2044 * WIN_SetWindowLong
2046 * Helper function for SetWindowLong().
2048 * 0 is the failure code. However, in the case of failure SetLastError
2049 * must be set to distinguish between a 0 return value and a failure.
2051 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2053 STYLESTRUCT style;
2054 BOOL ok;
2055 LONG_PTR retval = 0;
2056 WND *wndPtr;
2058 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2060 if (is_broadcast(hwnd))
2062 SetLastError( ERROR_INVALID_PARAMETER );
2063 return FALSE;
2066 if (!(wndPtr = WIN_GetPtr( hwnd )))
2068 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2069 return 0;
2071 if (wndPtr == WND_DESKTOP)
2073 /* can't change anything on the desktop window */
2074 SetLastError( ERROR_ACCESS_DENIED );
2075 return 0;
2077 if (wndPtr == WND_OTHER_PROCESS)
2079 if (offset == GWLP_WNDPROC)
2081 SetLastError( ERROR_ACCESS_DENIED );
2082 return 0;
2084 if (offset > 32767 || offset < -32767)
2086 SetLastError( ERROR_INVALID_INDEX );
2087 return 0;
2089 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2092 /* first some special cases */
2093 switch( offset )
2095 case GWL_STYLE:
2096 style.styleOld = wndPtr->dwStyle;
2097 style.styleNew = newval;
2098 WIN_ReleasePtr( wndPtr );
2099 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2100 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2101 newval = style.styleNew;
2102 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2103 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2104 break;
2105 case GWL_EXSTYLE:
2106 style.styleOld = wndPtr->dwExStyle;
2107 style.styleNew = newval;
2108 WIN_ReleasePtr( wndPtr );
2109 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2110 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2111 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2112 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2113 /* WS_EX_WINDOWEDGE depends on some other styles */
2114 if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2115 newval |= WS_EX_WINDOWEDGE;
2116 else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2117 newval &= ~WS_EX_WINDOWEDGE;
2118 break;
2119 case GWLP_HWNDPARENT:
2120 if (wndPtr->parent == GetDesktopWindow())
2122 WIN_ReleasePtr( wndPtr );
2123 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2125 else
2127 WIN_ReleasePtr( wndPtr );
2128 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2130 case GWLP_WNDPROC:
2132 WNDPROC proc;
2133 UINT old_flags = wndPtr->flags;
2134 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2135 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2136 if (proc) wndPtr->winproc = proc;
2137 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2138 else wndPtr->flags &= ~WIN_ISUNICODE;
2139 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2141 WIN_ReleasePtr( wndPtr );
2142 return retval;
2144 /* update is_unicode flag on the server side */
2145 break;
2147 case GWLP_ID:
2148 case GWLP_HINSTANCE:
2149 case GWLP_USERDATA:
2150 break;
2151 case DWLP_DLGPROC:
2152 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2153 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2155 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2156 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2157 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2158 WIN_ReleasePtr( wndPtr );
2159 return retval;
2161 /* fall through */
2162 default:
2163 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2165 WARN("Invalid offset %d\n", offset );
2166 WIN_ReleasePtr( wndPtr );
2167 SetLastError( ERROR_INVALID_INDEX );
2168 return 0;
2170 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2172 /* already set to the same value */
2173 WIN_ReleasePtr( wndPtr );
2174 return newval;
2176 break;
2179 SERVER_START_REQ( set_window_info )
2181 req->handle = wine_server_user_handle( hwnd );
2182 req->extra_offset = -1;
2183 switch(offset)
2185 case GWL_STYLE:
2186 req->flags = SET_WIN_STYLE;
2187 req->style = newval;
2188 break;
2189 case GWL_EXSTYLE:
2190 req->flags = SET_WIN_EXSTYLE;
2191 req->ex_style = newval;
2192 break;
2193 case GWLP_ID:
2194 req->flags = SET_WIN_ID;
2195 req->id = newval;
2196 break;
2197 case GWLP_HINSTANCE:
2198 req->flags = SET_WIN_INSTANCE;
2199 req->instance = wine_server_client_ptr( (void *)newval );
2200 break;
2201 case GWLP_WNDPROC:
2202 req->flags = SET_WIN_UNICODE;
2203 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2204 break;
2205 case GWLP_USERDATA:
2206 req->flags = SET_WIN_USERDATA;
2207 req->user_data = newval;
2208 break;
2209 default:
2210 req->flags = SET_WIN_EXTRA;
2211 req->extra_offset = offset;
2212 req->extra_size = size;
2213 set_win_data( &req->extra_value, newval, size );
2215 if ((ok = !wine_server_call_err( req )))
2217 switch(offset)
2219 case GWL_STYLE:
2220 wndPtr->dwStyle = newval;
2221 retval = reply->old_style;
2222 break;
2223 case GWL_EXSTYLE:
2224 wndPtr->dwExStyle = newval;
2225 retval = reply->old_ex_style;
2226 break;
2227 case GWLP_ID:
2228 wndPtr->wIDmenu = newval;
2229 retval = reply->old_id;
2230 break;
2231 case GWLP_HINSTANCE:
2232 wndPtr->hInstance = (HINSTANCE)newval;
2233 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2234 break;
2235 case GWLP_WNDPROC:
2236 break;
2237 case GWLP_USERDATA:
2238 wndPtr->userdata = newval;
2239 retval = reply->old_user_data;
2240 break;
2241 default:
2242 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2243 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2244 break;
2248 SERVER_END_REQ;
2249 WIN_ReleasePtr( wndPtr );
2251 if (!ok) return 0;
2253 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2255 style.styleOld = retval;
2256 style.styleNew = newval;
2257 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2258 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2261 return retval;
2265 /**********************************************************************
2266 * GetWindowWord (USER32.@)
2268 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2270 switch(offset)
2272 case GWLP_ID:
2273 case GWLP_HINSTANCE:
2274 case GWLP_HWNDPARENT:
2275 break;
2276 default:
2277 if (offset < 0)
2279 WARN("Invalid offset %d\n", offset );
2280 SetLastError( ERROR_INVALID_INDEX );
2281 return 0;
2283 break;
2285 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2289 /**********************************************************************
2290 * GetWindowLongA (USER32.@)
2292 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2294 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2298 /**********************************************************************
2299 * GetWindowLongW (USER32.@)
2301 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2303 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2307 /**********************************************************************
2308 * SetWindowWord (USER32.@)
2310 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2312 switch(offset)
2314 case GWLP_ID:
2315 case GWLP_HINSTANCE:
2316 case GWLP_HWNDPARENT:
2317 break;
2318 default:
2319 if (offset < 0)
2321 WARN("Invalid offset %d\n", offset );
2322 SetLastError( ERROR_INVALID_INDEX );
2323 return 0;
2325 break;
2327 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2331 /**********************************************************************
2332 * SetWindowLongA (USER32.@)
2334 * See SetWindowLongW.
2336 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2338 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2342 /**********************************************************************
2343 * SetWindowLongW (USER32.@) Set window attribute
2345 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2346 * value in a window's extra memory.
2348 * The _hwnd_ parameter specifies the window. is the handle to a
2349 * window that has extra memory. The _newval_ parameter contains the
2350 * new attribute or extra memory value. If positive, the _offset_
2351 * parameter is the byte-addressed location in the window's extra
2352 * memory to set. If negative, _offset_ specifies the window
2353 * attribute to set, and should be one of the following values:
2355 * GWL_EXSTYLE The window's extended window style
2357 * GWL_STYLE The window's window style.
2359 * GWLP_WNDPROC Pointer to the window's window procedure.
2361 * GWLP_HINSTANCE The window's pplication instance handle.
2363 * GWLP_ID The window's identifier.
2365 * GWLP_USERDATA The window's user-specified data.
2367 * If the window is a dialog box, the _offset_ parameter can be one of
2368 * the following values:
2370 * DWLP_DLGPROC The address of the window's dialog box procedure.
2372 * DWLP_MSGRESULT The return value of a message
2373 * that the dialog box procedure processed.
2375 * DWLP_USER Application specific information.
2377 * RETURNS
2379 * If successful, returns the previous value located at _offset_. Otherwise,
2380 * returns 0.
2382 * NOTES
2384 * Extra memory for a window class is specified by a nonzero cbWndExtra
2385 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2386 * time of class creation.
2388 * Using GWL_WNDPROC to set a new window procedure effectively creates
2389 * a window subclass. Use CallWindowProc() in the new windows procedure
2390 * to pass messages to the superclass's window procedure.
2392 * The user data is reserved for use by the application which created
2393 * the window.
2395 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2396 * instead, call the EnableWindow() function to change the window's
2397 * disabled state.
2399 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2400 * SetParent() instead.
2402 * Win95:
2403 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2404 * it sends WM_STYLECHANGING before changing the settings
2405 * and WM_STYLECHANGED afterwards.
2406 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2408 LONG WINAPI SetWindowLongW(
2409 HWND hwnd, /* [in] window to alter */
2410 INT offset, /* [in] offset, in bytes, of location to alter */
2411 LONG newval /* [in] new value of location */
2413 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2417 /*******************************************************************
2418 * GetWindowTextA (USER32.@)
2420 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2422 WCHAR *buffer;
2424 if (!lpString) return 0;
2426 if (WIN_IsCurrentProcess( hwnd ))
2427 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2429 /* when window belongs to other process, don't send a message */
2430 if (nMaxCount <= 0) return 0;
2431 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2432 get_server_window_text( hwnd, buffer, nMaxCount );
2433 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2434 lpString[nMaxCount-1] = 0;
2435 HeapFree( GetProcessHeap(), 0, buffer );
2436 return strlen(lpString);
2440 /*******************************************************************
2441 * InternalGetWindowText (USER32.@)
2443 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2445 WND *win;
2447 if (nMaxCount <= 0) return 0;
2448 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2449 if (win == WND_DESKTOP) lpString[0] = 0;
2450 else if (win != WND_OTHER_PROCESS)
2452 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2453 else lpString[0] = 0;
2454 WIN_ReleasePtr( win );
2456 else
2458 get_server_window_text( hwnd, lpString, nMaxCount );
2460 return strlenW(lpString);
2464 /*******************************************************************
2465 * GetWindowTextW (USER32.@)
2467 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2469 if (!lpString) return 0;
2471 if (WIN_IsCurrentProcess( hwnd ))
2472 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2474 /* when window belongs to other process, don't send a message */
2475 if (nMaxCount <= 0) return 0;
2476 get_server_window_text( hwnd, lpString, nMaxCount );
2477 return strlenW(lpString);
2481 /*******************************************************************
2482 * SetWindowTextA (USER32.@)
2483 * SetWindowText (USER32.@)
2485 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2487 if (is_broadcast(hwnd))
2489 SetLastError( ERROR_INVALID_PARAMETER );
2490 return FALSE;
2492 if (!WIN_IsCurrentProcess( hwnd ))
2493 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2494 debugstr_a(lpString), hwnd );
2495 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2499 /*******************************************************************
2500 * SetWindowTextW (USER32.@)
2502 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2504 if (is_broadcast(hwnd))
2506 SetLastError( ERROR_INVALID_PARAMETER );
2507 return FALSE;
2509 if (!WIN_IsCurrentProcess( hwnd ))
2510 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2511 debugstr_w(lpString), hwnd );
2512 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2516 /*******************************************************************
2517 * GetWindowTextLengthA (USER32.@)
2519 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2521 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2524 /*******************************************************************
2525 * GetWindowTextLengthW (USER32.@)
2527 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2529 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2533 /*******************************************************************
2534 * IsWindow (USER32.@)
2536 BOOL WINAPI IsWindow( HWND hwnd )
2538 WND *ptr;
2539 BOOL ret;
2541 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2542 if (ptr == WND_DESKTOP) return TRUE;
2544 if (ptr != WND_OTHER_PROCESS)
2546 WIN_ReleasePtr( ptr );
2547 return TRUE;
2550 /* check other processes */
2551 SERVER_START_REQ( get_window_info )
2553 req->handle = wine_server_user_handle( hwnd );
2554 ret = !wine_server_call_err( req );
2556 SERVER_END_REQ;
2557 return ret;
2561 /***********************************************************************
2562 * GetWindowThreadProcessId (USER32.@)
2564 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2566 WND *ptr;
2567 DWORD tid = 0;
2569 if (!(ptr = WIN_GetPtr( hwnd )))
2571 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2572 return 0;
2575 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2577 /* got a valid window */
2578 tid = ptr->tid;
2579 if (process) *process = GetCurrentProcessId();
2580 WIN_ReleasePtr( ptr );
2581 return tid;
2584 /* check other processes */
2585 SERVER_START_REQ( get_window_info )
2587 req->handle = wine_server_user_handle( hwnd );
2588 if (!wine_server_call_err( req ))
2590 tid = (DWORD)reply->tid;
2591 if (process) *process = (DWORD)reply->pid;
2594 SERVER_END_REQ;
2595 return tid;
2599 /*****************************************************************
2600 * GetParent (USER32.@)
2602 HWND WINAPI GetParent( HWND hwnd )
2604 WND *wndPtr;
2605 HWND retvalue = 0;
2607 if (!(wndPtr = WIN_GetPtr( hwnd )))
2609 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2610 return 0;
2612 if (wndPtr == WND_DESKTOP) return 0;
2613 if (wndPtr == WND_OTHER_PROCESS)
2615 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2616 if (style & (WS_POPUP | WS_CHILD))
2618 SERVER_START_REQ( get_window_tree )
2620 req->handle = wine_server_user_handle( hwnd );
2621 if (!wine_server_call_err( req ))
2623 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2624 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2627 SERVER_END_REQ;
2630 else
2632 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2633 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2634 WIN_ReleasePtr( wndPtr );
2636 return retvalue;
2640 /*****************************************************************
2641 * GetAncestor (USER32.@)
2643 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2645 WND *win;
2646 HWND *list, ret = 0;
2648 switch(type)
2650 case GA_PARENT:
2651 if (!(win = WIN_GetPtr( hwnd )))
2653 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2654 return 0;
2656 if (win == WND_DESKTOP) return 0;
2657 if (win != WND_OTHER_PROCESS)
2659 ret = win->parent;
2660 WIN_ReleasePtr( win );
2662 else /* need to query the server */
2664 SERVER_START_REQ( get_window_tree )
2666 req->handle = wine_server_user_handle( hwnd );
2667 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2669 SERVER_END_REQ;
2671 break;
2673 case GA_ROOT:
2674 if (!(list = list_window_parents( hwnd ))) return 0;
2676 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2677 else
2679 int count = 2;
2680 while (list[count]) count++;
2681 ret = list[count - 2]; /* get the one before the desktop */
2683 HeapFree( GetProcessHeap(), 0, list );
2684 break;
2686 case GA_ROOTOWNER:
2687 if (is_desktop_window( hwnd )) return 0;
2688 ret = WIN_GetFullHandle( hwnd );
2689 for (;;)
2691 HWND parent = GetParent( ret );
2692 if (!parent) break;
2693 ret = parent;
2695 break;
2697 return ret;
2701 /*****************************************************************
2702 * SetParent (USER32.@)
2704 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2706 HWND full_handle;
2707 HWND old_parent = 0;
2708 BOOL was_visible;
2709 WND *wndPtr;
2710 BOOL ret;
2712 if (is_broadcast(hwnd) || is_broadcast(parent))
2714 SetLastError(ERROR_INVALID_PARAMETER);
2715 return 0;
2718 if (!parent) parent = GetDesktopWindow();
2719 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2720 else parent = WIN_GetFullHandle( parent );
2722 if (!IsWindow( parent ))
2724 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2725 return 0;
2728 /* Some applications try to set a child as a parent */
2729 if (IsChild(hwnd, parent))
2731 SetLastError( ERROR_INVALID_PARAMETER );
2732 return 0;
2735 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2736 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2738 if (full_handle == parent)
2740 SetLastError( ERROR_INVALID_PARAMETER );
2741 return 0;
2744 /* Windows hides the window first, then shows it again
2745 * including the WM_SHOWWINDOW messages and all */
2746 was_visible = ShowWindow( hwnd, SW_HIDE );
2748 wndPtr = WIN_GetPtr( hwnd );
2749 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2751 SERVER_START_REQ( set_parent )
2753 req->handle = wine_server_user_handle( hwnd );
2754 req->parent = wine_server_user_handle( parent );
2755 if ((ret = !wine_server_call( req )))
2757 old_parent = wine_server_ptr_handle( reply->old_parent );
2758 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2762 SERVER_END_REQ;
2763 WIN_ReleasePtr( wndPtr );
2764 if (!ret) return 0;
2766 USER_Driver->pSetParent( full_handle, parent, old_parent );
2768 /* SetParent additionally needs to make hwnd the topmost window
2769 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2770 WM_WINDOWPOSCHANGED notification messages.
2772 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2773 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2774 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2775 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2777 return old_parent;
2781 /*******************************************************************
2782 * IsChild (USER32.@)
2784 BOOL WINAPI IsChild( HWND parent, HWND child )
2786 HWND *list = list_window_parents( child );
2787 int i;
2788 BOOL ret;
2790 if (!list) return FALSE;
2791 parent = WIN_GetFullHandle( parent );
2792 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2793 ret = list[i] && list[i+1];
2794 HeapFree( GetProcessHeap(), 0, list );
2795 return ret;
2799 /***********************************************************************
2800 * IsWindowVisible (USER32.@)
2802 BOOL WINAPI IsWindowVisible( HWND hwnd )
2804 HWND *list;
2805 BOOL retval = TRUE;
2806 int i;
2808 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2809 if (!(list = list_window_parents( hwnd ))) return TRUE;
2810 if (list[0])
2812 for (i = 0; list[i+1]; i++)
2813 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2814 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2816 HeapFree( GetProcessHeap(), 0, list );
2817 return retval;
2821 /***********************************************************************
2822 * WIN_IsWindowDrawable
2824 * hwnd is drawable when it is visible, all parents are not
2825 * minimized, and it is itself not minimized unless we are
2826 * trying to draw its default class icon.
2828 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2830 HWND *list;
2831 BOOL retval = TRUE;
2832 int i;
2833 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2835 if (!(style & WS_VISIBLE)) return FALSE;
2836 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2838 if (!(list = list_window_parents( hwnd ))) return TRUE;
2839 if (list[0])
2841 for (i = 0; list[i+1]; i++)
2842 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2843 break;
2844 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2846 HeapFree( GetProcessHeap(), 0, list );
2847 return retval;
2851 /*******************************************************************
2852 * GetTopWindow (USER32.@)
2854 HWND WINAPI GetTopWindow( HWND hwnd )
2856 if (!hwnd) hwnd = GetDesktopWindow();
2857 return GetWindow( hwnd, GW_CHILD );
2861 /*******************************************************************
2862 * GetWindow (USER32.@)
2864 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2866 HWND retval = 0;
2868 if (rel == GW_OWNER) /* this one may be available locally */
2870 WND *wndPtr = WIN_GetPtr( hwnd );
2871 if (!wndPtr)
2873 SetLastError( ERROR_INVALID_HANDLE );
2874 return 0;
2876 if (wndPtr == WND_DESKTOP) return 0;
2877 if (wndPtr != WND_OTHER_PROCESS)
2879 retval = wndPtr->owner;
2880 WIN_ReleasePtr( wndPtr );
2881 return retval;
2883 /* else fall through to server call */
2886 SERVER_START_REQ( get_window_tree )
2888 req->handle = wine_server_user_handle( hwnd );
2889 if (!wine_server_call_err( req ))
2891 switch(rel)
2893 case GW_HWNDFIRST:
2894 retval = wine_server_ptr_handle( reply->first_sibling );
2895 break;
2896 case GW_HWNDLAST:
2897 retval = wine_server_ptr_handle( reply->last_sibling );
2898 break;
2899 case GW_HWNDNEXT:
2900 retval = wine_server_ptr_handle( reply->next_sibling );
2901 break;
2902 case GW_HWNDPREV:
2903 retval = wine_server_ptr_handle( reply->prev_sibling );
2904 break;
2905 case GW_OWNER:
2906 retval = wine_server_ptr_handle( reply->owner );
2907 break;
2908 case GW_CHILD:
2909 retval = wine_server_ptr_handle( reply->first_child );
2910 break;
2914 SERVER_END_REQ;
2915 return retval;
2919 /*******************************************************************
2920 * ShowOwnedPopups (USER32.@)
2922 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2924 int count = 0;
2925 WND *pWnd;
2926 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2928 if (!win_array) return TRUE;
2930 while (win_array[count]) count++;
2931 while (--count >= 0)
2933 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2934 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2935 if (pWnd == WND_OTHER_PROCESS) continue;
2936 if (fShow)
2938 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2940 WIN_ReleasePtr( pWnd );
2941 /* In Windows, ShowOwnedPopups(TRUE) generates
2942 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2943 * regardless of the state of the owner
2945 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2946 continue;
2949 else
2951 if (pWnd->dwStyle & WS_VISIBLE)
2953 WIN_ReleasePtr( pWnd );
2954 /* In Windows, ShowOwnedPopups(FALSE) generates
2955 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2956 * regardless of the state of the owner
2958 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2959 continue;
2962 WIN_ReleasePtr( pWnd );
2964 HeapFree( GetProcessHeap(), 0, win_array );
2965 return TRUE;
2969 /*******************************************************************
2970 * GetLastActivePopup (USER32.@)
2972 HWND WINAPI GetLastActivePopup( HWND hwnd )
2974 HWND retval = hwnd;
2976 SERVER_START_REQ( get_window_info )
2978 req->handle = wine_server_user_handle( hwnd );
2979 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2981 SERVER_END_REQ;
2982 return retval;
2986 /*******************************************************************
2987 * WIN_ListChildren
2989 * Build an array of the children of a given window. The array must be
2990 * freed with HeapFree. Returns NULL when no windows are found.
2992 HWND *WIN_ListChildren( HWND hwnd )
2994 if (!hwnd)
2996 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2997 return NULL;
2999 return list_window_children( 0, hwnd, NULL, 0 );
3003 /*******************************************************************
3004 * EnumWindows (USER32.@)
3006 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3008 HWND *list;
3009 BOOL ret = TRUE;
3010 int i;
3012 USER_CheckNotLock();
3014 /* We have to build a list of all windows first, to avoid */
3015 /* unpleasant side-effects, for instance if the callback */
3016 /* function changes the Z-order of the windows. */
3018 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3020 /* Now call the callback function for every window */
3022 for (i = 0; list[i]; i++)
3024 /* Make sure that the window still exists */
3025 if (!IsWindow( list[i] )) continue;
3026 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3028 HeapFree( GetProcessHeap(), 0, list );
3029 return ret;
3033 /**********************************************************************
3034 * EnumThreadWindows (USER32.@)
3036 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3038 HWND *list;
3039 int i;
3040 BOOL ret = TRUE;
3042 USER_CheckNotLock();
3044 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3046 /* Now call the callback function for every window */
3048 for (i = 0; list[i]; i++)
3049 if (!(ret = func( list[i], lParam ))) break;
3050 HeapFree( GetProcessHeap(), 0, list );
3051 return ret;
3055 /***********************************************************************
3056 * EnumDesktopWindows (USER32.@)
3058 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3060 HWND *list;
3061 int i;
3063 USER_CheckNotLock();
3065 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3067 for (i = 0; list[i]; i++)
3068 if (!func( list[i], lparam )) break;
3069 HeapFree( GetProcessHeap(), 0, list );
3070 return TRUE;
3074 /**********************************************************************
3075 * WIN_EnumChildWindows
3077 * Helper function for EnumChildWindows().
3079 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3081 HWND *childList;
3082 BOOL ret = FALSE;
3084 for ( ; *list; list++)
3086 /* Make sure that the window still exists */
3087 if (!IsWindow( *list )) continue;
3088 /* Build children list first */
3089 childList = WIN_ListChildren( *list );
3091 ret = func( *list, lParam );
3093 if (childList)
3095 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3096 HeapFree( GetProcessHeap(), 0, childList );
3098 if (!ret) return FALSE;
3100 return TRUE;
3104 /**********************************************************************
3105 * EnumChildWindows (USER32.@)
3107 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3109 HWND *list;
3110 BOOL ret;
3112 USER_CheckNotLock();
3114 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3115 ret = WIN_EnumChildWindows( list, func, lParam );
3116 HeapFree( GetProcessHeap(), 0, list );
3117 return ret;
3121 /*******************************************************************
3122 * AnyPopup (USER32.@)
3124 BOOL WINAPI AnyPopup(void)
3126 int i;
3127 BOOL retvalue;
3128 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3130 if (!list) return FALSE;
3131 for (i = 0; list[i]; i++)
3133 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3135 retvalue = (list[i] != 0);
3136 HeapFree( GetProcessHeap(), 0, list );
3137 return retvalue;
3141 /*******************************************************************
3142 * FlashWindow (USER32.@)
3144 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3146 WND *wndPtr;
3148 TRACE("%p\n", hWnd);
3150 if (IsIconic( hWnd ))
3152 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3154 wndPtr = WIN_GetPtr(hWnd);
3155 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3156 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3158 wndPtr->flags |= WIN_NCACTIVATED;
3160 else
3162 wndPtr->flags &= ~WIN_NCACTIVATED;
3164 WIN_ReleasePtr( wndPtr );
3165 return TRUE;
3167 else
3169 WPARAM wparam;
3171 wndPtr = WIN_GetPtr(hWnd);
3172 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3173 hWnd = wndPtr->obj.handle; /* make it a full handle */
3175 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3176 else wparam = (hWnd == GetForegroundWindow());
3178 WIN_ReleasePtr( wndPtr );
3179 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3180 return wparam;
3184 /*******************************************************************
3185 * FlashWindowEx (USER32.@)
3187 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3189 FIXME("%p\n", pfwi);
3190 return TRUE;
3193 /*******************************************************************
3194 * GetWindowContextHelpId (USER32.@)
3196 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3198 DWORD retval;
3199 WND *wnd = WIN_GetPtr( hwnd );
3200 if (!wnd || wnd == WND_DESKTOP) return 0;
3201 if (wnd == WND_OTHER_PROCESS)
3203 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3204 return 0;
3206 retval = wnd->helpContext;
3207 WIN_ReleasePtr( wnd );
3208 return retval;
3212 /*******************************************************************
3213 * SetWindowContextHelpId (USER32.@)
3215 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3217 WND *wnd = WIN_GetPtr( hwnd );
3218 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3219 if (wnd == WND_OTHER_PROCESS)
3221 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3222 return 0;
3224 wnd->helpContext = id;
3225 WIN_ReleasePtr( wnd );
3226 return TRUE;
3230 /*******************************************************************
3231 * DragDetect (USER32.@)
3233 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3235 MSG msg;
3236 RECT rect;
3237 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3238 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3240 rect.left = pt.x - wDragWidth;
3241 rect.right = pt.x + wDragWidth;
3243 rect.top = pt.y - wDragHeight;
3244 rect.bottom = pt.y + wDragHeight;
3246 SetCapture(hWnd);
3248 while(1)
3250 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3252 if( msg.message == WM_LBUTTONUP )
3254 ReleaseCapture();
3255 return 0;
3257 if( msg.message == WM_MOUSEMOVE )
3259 POINT tmp;
3260 tmp.x = (short)LOWORD(msg.lParam);
3261 tmp.y = (short)HIWORD(msg.lParam);
3262 if( !PtInRect( &rect, tmp ))
3264 ReleaseCapture();
3265 return 1;
3269 WaitMessage();
3271 return 0;
3274 /******************************************************************************
3275 * GetWindowModuleFileNameA (USER32.@)
3277 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3279 WND *win;
3280 HINSTANCE hinst;
3282 TRACE( "%p, %p, %u\n", hwnd, module, size );
3284 win = WIN_GetPtr( hwnd );
3285 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3287 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3288 return 0;
3290 hinst = win->hInstance;
3291 WIN_ReleasePtr( win );
3293 return GetModuleFileNameA( hinst, module, size );
3296 /******************************************************************************
3297 * GetWindowModuleFileNameW (USER32.@)
3299 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3301 WND *win;
3302 HINSTANCE hinst;
3304 TRACE( "%p, %p, %u\n", hwnd, module, size );
3306 win = WIN_GetPtr( hwnd );
3307 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3309 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3310 return 0;
3312 hinst = win->hInstance;
3313 WIN_ReleasePtr( win );
3315 return GetModuleFileNameW( hinst, module, size );
3318 /******************************************************************************
3319 * GetWindowInfo (USER32.@)
3321 * Note: tests show that Windows doesn't check cbSize of the structure.
3323 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3325 if (!pwi) return FALSE;
3326 if (!IsWindow(hwnd)) return FALSE;
3328 GetWindowRect(hwnd, &pwi->rcWindow);
3329 GetClientRect(hwnd, &pwi->rcClient);
3330 /* translate to screen coordinates */
3331 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3333 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3334 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3335 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3337 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3338 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3340 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3341 pwi->wCreatorVersion = 0x0400;
3343 return TRUE;
3346 /******************************************************************************
3347 * SwitchDesktop (USER32.@)
3349 * NOTES: Sets the current input or interactive desktop.
3351 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3353 FIXME("(hwnd %p) stub!\n", hDesktop);
3354 return TRUE;
3357 /*****************************************************************************
3358 * SetLayeredWindowAttributes (USER32.@)
3360 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3362 BOOL ret;
3364 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3366 SERVER_START_REQ( set_window_layered_info )
3368 req->handle = wine_server_user_handle( hwnd );
3369 req->color_key = key;
3370 req->alpha = alpha;
3371 req->flags = flags;
3372 ret = !wine_server_call_err( req );
3374 SERVER_END_REQ;
3376 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3378 return ret;
3382 /*****************************************************************************
3383 * GetLayeredWindowAttributes (USER32.@)
3385 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3387 BOOL ret;
3389 SERVER_START_REQ( get_window_layered_info )
3391 req->handle = wine_server_user_handle( hwnd );
3392 if ((ret = !wine_server_call_err( req )))
3394 if (key) *key = reply->color_key;
3395 if (alpha) *alpha = reply->alpha;
3396 if (flags) *flags = reply->flags;
3399 SERVER_END_REQ;
3401 return ret;
3405 /*****************************************************************************
3406 * UpdateLayeredWindowIndirect (USER32.@)
3408 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3410 BYTE alpha = 0xff;
3412 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3414 int x = 0, y = 0, cx = 0, cy = 0;
3415 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3417 if (info->pptDst)
3419 x = info->pptDst->x;
3420 y = info->pptDst->y;
3421 flags &= ~SWP_NOMOVE;
3423 if (info->psize)
3425 cx = info->psize->cx;
3426 cy = info->psize->cy;
3427 flags &= ~SWP_NOSIZE;
3429 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3430 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3433 if (info->hdcSrc)
3435 HDC hdc = GetWindowDC( hwnd );
3437 if (hdc)
3439 int x = 0, y = 0;
3440 RECT rect;
3442 GetWindowRect( hwnd, &rect );
3443 OffsetRect( &rect, -rect.left, -rect.top);
3444 if (info->pptSrc)
3446 x = info->pptSrc->x;
3447 y = info->pptSrc->y;
3450 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3452 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3453 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3454 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3456 ReleaseDC( hwnd, hdc );
3460 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3461 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3462 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3463 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3464 return TRUE;
3468 /*****************************************************************************
3469 * UpdateLayeredWindow (USER32.@)
3471 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3472 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3473 DWORD dwFlags)
3475 UPDATELAYEREDWINDOWINFO info;
3477 info.cbSize = sizeof(info);
3478 info.hdcDst = hdcDst;
3479 info.pptDst = pptDst;
3480 info.psize = psize;
3481 info.hdcSrc = hdcSrc;
3482 info.pptSrc = pptSrc;
3483 info.crKey = crKey;
3484 info.pblend = pblend;
3485 info.dwFlags = dwFlags;
3486 info.prcDirty = NULL;
3487 return UpdateLayeredWindowIndirect( hwnd, &info );
3491 /******************************************************************************
3492 * GetProcessDefaultLayout [USER32.@]
3494 * Gets the default layout for parentless windows.
3496 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3498 if (!layout)
3500 SetLastError( ERROR_NOACCESS );
3501 return FALSE;
3503 *layout = process_layout;
3504 return TRUE;
3508 /******************************************************************************
3509 * SetProcessDefaultLayout [USER32.@]
3511 * Sets the default layout for parentless windows.
3513 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3515 process_layout = layout;
3516 return TRUE;
3520 /* 64bit versions */
3522 #ifdef GetWindowLongPtrW
3523 #undef GetWindowLongPtrW
3524 #endif
3526 #ifdef GetWindowLongPtrA
3527 #undef GetWindowLongPtrA
3528 #endif
3530 #ifdef SetWindowLongPtrW
3531 #undef SetWindowLongPtrW
3532 #endif
3534 #ifdef SetWindowLongPtrA
3535 #undef SetWindowLongPtrA
3536 #endif
3538 /*****************************************************************************
3539 * GetWindowLongPtrW (USER32.@)
3541 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3543 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3546 /*****************************************************************************
3547 * GetWindowLongPtrA (USER32.@)
3549 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3551 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3554 /*****************************************************************************
3555 * SetWindowLongPtrW (USER32.@)
3557 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3559 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3562 /*****************************************************************************
3563 * SetWindowLongPtrA (USER32.@)
3565 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3567 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );