user32: Call the SetWindowStyle driver entry point before updating the window position.
[wine.git] / dlls / user32 / win.c
blob0dbe29e4ae13e3657dc705c9e731bd58c35e70e5
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 "winver.h"
31 #include "wine/server.h"
32 #include "wine/unicode.h"
33 #include "win.h"
34 #include "user_private.h"
35 #include "controls.h"
36 #include "winerror.h"
37 #include "wine/gdi_driver.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
42 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
43 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
45 static DWORD process_layout = ~0u;
47 static struct list window_surfaces = LIST_INIT( window_surfaces );
49 static CRITICAL_SECTION surfaces_section;
50 static CRITICAL_SECTION_DEBUG critsect_debug =
52 0, 0, &surfaces_section,
53 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
54 0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
56 static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };
58 /**********************************************************************/
60 /* helper for Get/SetWindowLong */
61 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
63 if (size == sizeof(WORD))
65 WORD ret;
66 memcpy( &ret, ptr, sizeof(ret) );
67 return ret;
69 else if (size == sizeof(DWORD))
71 DWORD ret;
72 memcpy( &ret, ptr, sizeof(ret) );
73 return ret;
75 else
77 LONG_PTR ret;
78 memcpy( &ret, ptr, sizeof(ret) );
79 return ret;
83 /* helper for Get/SetWindowLong */
84 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
86 if (size == sizeof(WORD))
88 WORD newval = val;
89 memcpy( ptr, &newval, sizeof(newval) );
91 else if (size == sizeof(DWORD))
93 DWORD newval = val;
94 memcpy( ptr, &newval, sizeof(newval) );
96 else
98 memcpy( ptr, &val, sizeof(val) );
103 static void *user_handles[NB_USER_HANDLES];
105 /***********************************************************************
106 * alloc_user_handle
108 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
110 HANDLE handle = 0;
112 SERVER_START_REQ( alloc_user_handle )
114 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
116 SERVER_END_REQ;
118 if (handle)
120 UINT index = USER_HANDLE_TO_INDEX( handle );
122 assert( index < NB_USER_HANDLES );
123 ptr->handle = handle;
124 ptr->type = type;
125 InterlockedExchangePointer( &user_handles[index], ptr );
127 return handle;
131 /***********************************************************************
132 * get_user_handle_ptr
134 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
136 struct user_object *ptr;
137 WORD index = USER_HANDLE_TO_INDEX( handle );
139 if (index >= NB_USER_HANDLES) return NULL;
141 USER_Lock();
142 if ((ptr = user_handles[index]))
144 if (ptr->type == type &&
145 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
146 !HIWORD(handle) || HIWORD(handle) == 0xffff))
147 return ptr;
148 ptr = NULL;
150 else ptr = OBJ_OTHER_PROCESS;
151 USER_Unlock();
152 return ptr;
156 /***********************************************************************
157 * release_user_handle_ptr
159 void release_user_handle_ptr( void *ptr )
161 assert( ptr && ptr != OBJ_OTHER_PROCESS );
162 USER_Unlock();
166 /***********************************************************************
167 * free_user_handle
169 void *free_user_handle( HANDLE handle, enum user_obj_type type )
171 struct user_object *ptr;
172 WORD index = USER_HANDLE_TO_INDEX( handle );
174 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
176 SERVER_START_REQ( free_user_handle )
178 req->handle = wine_server_user_handle( handle );
179 if (wine_server_call( req )) ptr = NULL;
180 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
182 SERVER_END_REQ;
183 release_user_handle_ptr( ptr );
185 return ptr;
189 /***********************************************************************
190 * create_window_handle
192 * Create a window handle with the server.
194 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
195 HINSTANCE instance, BOOL unicode )
197 WORD index;
198 WND *win;
199 HWND handle = 0, full_parent = 0, full_owner = 0;
200 struct tagCLASS *class = NULL;
201 int extra_bytes = 0;
203 SERVER_START_REQ( create_window )
205 req->parent = wine_server_user_handle( parent );
206 req->owner = wine_server_user_handle( owner );
207 req->instance = wine_server_client_ptr( instance );
208 if (!(req->atom = get_int_atom_value( name )) && name)
209 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
210 if (!wine_server_call_err( req ))
212 handle = wine_server_ptr_handle( reply->handle );
213 full_parent = wine_server_ptr_handle( reply->parent );
214 full_owner = wine_server_ptr_handle( reply->owner );
215 extra_bytes = reply->extra;
216 class = wine_server_get_ptr( reply->class_ptr );
219 SERVER_END_REQ;
221 if (!handle)
223 WARN( "error %d creating window\n", GetLastError() );
224 return NULL;
227 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
228 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
230 SERVER_START_REQ( destroy_window )
232 req->handle = wine_server_user_handle( handle );
233 wine_server_call( req );
235 SERVER_END_REQ;
236 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
237 return NULL;
240 if (!parent) /* if parent is 0 we don't have a desktop window yet */
242 struct user_thread_info *thread_info = get_user_thread_info();
244 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
246 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
247 else assert( full_parent == thread_info->top_window );
248 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
249 ERR( "failed to create desktop window\n" );
251 else /* HWND_MESSAGE parent */
253 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
257 USER_Lock();
259 index = USER_HANDLE_TO_INDEX(handle);
260 assert( index < NB_USER_HANDLES );
261 win->obj.handle = handle;
262 win->obj.type = USER_WINDOW;
263 win->parent = full_parent;
264 win->owner = full_owner;
265 win->class = class;
266 win->winproc = get_class_winproc( class );
267 win->cbWndExtra = extra_bytes;
268 InterlockedExchangePointer( &user_handles[index], win );
269 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
270 return win;
274 /***********************************************************************
275 * free_window_handle
277 * Free a window handle.
279 static void free_window_handle( HWND hwnd )
281 struct user_object *ptr;
282 WORD index = USER_HANDLE_TO_INDEX(hwnd);
284 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
286 SERVER_START_REQ( destroy_window )
288 req->handle = wine_server_user_handle( hwnd );
289 if (wine_server_call_err( req )) ptr = NULL;
290 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
292 SERVER_END_REQ;
293 release_user_handle_ptr( ptr );
294 HeapFree( GetProcessHeap(), 0, ptr );
299 /*******************************************************************
300 * list_window_children
302 * Build an array of the children of a given window. The array must be
303 * freed with HeapFree. Returns NULL when no windows are found.
305 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
307 HWND *list;
308 int i, size = 128;
309 ATOM atom = get_int_atom_value( class );
311 /* empty class is not the same as NULL class */
312 if (!atom && class && !class[0]) return NULL;
314 for (;;)
316 int count = 0;
318 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
320 SERVER_START_REQ( get_window_children )
322 req->desktop = wine_server_obj_handle( desktop );
323 req->parent = wine_server_user_handle( hwnd );
324 req->tid = tid;
325 req->atom = atom;
326 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
327 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
328 if (!wine_server_call( req )) count = reply->count;
330 SERVER_END_REQ;
331 if (count && count < size)
333 /* start from the end since HWND is potentially larger than user_handle_t */
334 for (i = count - 1; i >= 0; i--)
335 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
336 list[count] = 0;
337 return list;
339 HeapFree( GetProcessHeap(), 0, list );
340 if (!count) break;
341 size = count + 1; /* restart with a large enough buffer */
343 return NULL;
347 /*******************************************************************
348 * list_window_parents
350 * Build an array of all parents of a given window, starting with
351 * the immediate parent. The array must be freed with HeapFree.
353 static HWND *list_window_parents( HWND hwnd )
355 WND *win;
356 HWND current, *list;
357 int i, pos = 0, size = 16, count = 0;
359 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
361 current = hwnd;
362 for (;;)
364 if (!(win = WIN_GetPtr( current ))) goto empty;
365 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
366 if (win == WND_DESKTOP)
368 if (!pos) goto empty;
369 list[pos] = 0;
370 return list;
372 list[pos] = current = win->parent;
373 WIN_ReleasePtr( win );
374 if (!current) return list;
375 if (++pos == size - 1)
377 /* need to grow the list */
378 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
379 if (!new_list) goto empty;
380 list = new_list;
381 size += 16;
385 /* at least one parent belongs to another process, have to query the server */
387 for (;;)
389 count = 0;
390 SERVER_START_REQ( get_window_parents )
392 req->handle = wine_server_user_handle( hwnd );
393 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
394 if (!wine_server_call( req )) count = reply->count;
396 SERVER_END_REQ;
397 if (!count) goto empty;
398 if (size > count)
400 /* start from the end since HWND is potentially larger than user_handle_t */
401 for (i = count - 1; i >= 0; i--)
402 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
403 list[count] = 0;
404 return list;
406 HeapFree( GetProcessHeap(), 0, list );
407 size = count + 1;
408 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
411 empty:
412 HeapFree( GetProcessHeap(), 0, list );
413 return NULL;
417 /*******************************************************************
418 * send_parent_notify
420 static void send_parent_notify( HWND hwnd, UINT msg )
422 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
423 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
425 HWND parent = GetParent(hwnd);
426 if (parent && parent != GetDesktopWindow())
427 SendMessageW( parent, WM_PARENTNOTIFY,
428 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
433 /*******************************************************************
434 * get_server_window_text
436 * Retrieve the window text from the server.
438 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
440 size_t len = 0;
442 SERVER_START_REQ( get_window_text )
444 req->handle = wine_server_user_handle( hwnd );
445 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
446 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
448 SERVER_END_REQ;
449 text[len / sizeof(WCHAR)] = 0;
453 /*******************************************************************
454 * get_hwnd_message_parent
456 * Return the parent for HWND_MESSAGE windows.
458 HWND get_hwnd_message_parent(void)
460 struct user_thread_info *thread_info = get_user_thread_info();
462 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
463 return thread_info->msg_window;
467 /*******************************************************************
468 * is_desktop_window
470 * Check if window is the desktop or the HWND_MESSAGE top parent.
472 BOOL is_desktop_window( HWND hwnd )
474 struct user_thread_info *thread_info = get_user_thread_info();
476 if (!hwnd) return FALSE;
477 if (hwnd == thread_info->top_window) return TRUE;
478 if (hwnd == thread_info->msg_window) return TRUE;
480 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
482 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
483 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
485 return FALSE;
489 /*******************************************************************
490 * Dummy window surface for windows that shouldn't get painted.
493 static void dummy_surface_lock( struct window_surface *window_surface )
495 /* nothing to do */
498 static void dummy_surface_unlock( struct window_surface *window_surface )
500 /* nothing to do */
503 static void *dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
505 static DWORD dummy_data;
507 info->bmiHeader.biSize = sizeof( info->bmiHeader );
508 info->bmiHeader.biWidth = dummy_surface.rect.right;
509 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
510 info->bmiHeader.biPlanes = 1;
511 info->bmiHeader.biBitCount = 32;
512 info->bmiHeader.biCompression = BI_RGB;
513 info->bmiHeader.biSizeImage = 0;
514 info->bmiHeader.biXPelsPerMeter = 0;
515 info->bmiHeader.biYPelsPerMeter = 0;
516 info->bmiHeader.biClrUsed = 0;
517 info->bmiHeader.biClrImportant = 0;
518 return &dummy_data;
521 static RECT *dummy_surface_get_bounds( struct window_surface *window_surface )
523 static RECT dummy_bounds;
524 return &dummy_bounds;
527 static void dummy_surface_flush( struct window_surface *window_surface )
529 /* nothing to do */
532 static void dummy_surface_destroy( struct window_surface *window_surface )
534 /* nothing to do */
537 static const struct window_surface_funcs dummy_surface_funcs =
539 dummy_surface_lock,
540 dummy_surface_unlock,
541 dummy_surface_get_bitmap_info,
542 dummy_surface_get_bounds,
543 dummy_surface_flush,
544 dummy_surface_destroy
547 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
550 /*******************************************************************
551 * register_window_surface
553 * Register a window surface in the global list, possibly replacing another one.
555 void register_window_surface( struct window_surface *old, struct window_surface *new )
557 if (old == new) return;
558 EnterCriticalSection( &surfaces_section );
559 if (old && old != &dummy_surface) list_remove( &old->entry );
560 if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
561 LeaveCriticalSection( &surfaces_section );
565 /*******************************************************************
566 * flush_window_surfaces
568 * Flush pending output from all window surfaces.
570 void flush_window_surfaces( BOOL idle )
572 static DWORD last_idle;
573 DWORD now;
574 struct window_surface *surface;
576 EnterCriticalSection( &surfaces_section );
577 now = GetTickCount();
578 if (idle) last_idle = now;
579 /* if not idle, we only flush if there's evidence that the app never goes idle */
580 else if ((int)(now - last_idle) < 1000) goto done;
582 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
583 surface->funcs->flush( surface );
584 done:
585 LeaveCriticalSection( &surfaces_section );
589 /***********************************************************************
590 * WIN_GetPtr
592 * Return a pointer to the WND structure if local to the process,
593 * or WND_OTHER_PROCESS if handle may be valid in other process.
594 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
596 WND *WIN_GetPtr( HWND hwnd )
598 WND *ptr;
600 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
602 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
604 return ptr;
608 /***********************************************************************
609 * WIN_IsCurrentProcess
611 * Check whether a given window belongs to the current process (and return the full handle).
613 HWND WIN_IsCurrentProcess( HWND hwnd )
615 WND *ptr;
616 HWND ret;
618 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
619 ret = ptr->obj.handle;
620 WIN_ReleasePtr( ptr );
621 return ret;
625 /***********************************************************************
626 * WIN_IsCurrentThread
628 * Check whether a given window belongs to the current thread (and return the full handle).
630 HWND WIN_IsCurrentThread( HWND hwnd )
632 WND *ptr;
633 HWND ret = 0;
635 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
636 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
637 WIN_ReleasePtr( ptr );
638 return ret;
642 /***********************************************************************
643 * WIN_GetFullHandle
645 * Convert a possibly truncated window handle to a full 32-bit handle.
647 HWND WIN_GetFullHandle( HWND hwnd )
649 WND *ptr;
651 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
652 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
653 /* do sign extension for -2 and -3 */
654 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
656 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
658 if (ptr == WND_DESKTOP)
660 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
661 else return get_hwnd_message_parent();
664 if (ptr != WND_OTHER_PROCESS)
666 hwnd = ptr->obj.handle;
667 WIN_ReleasePtr( ptr );
669 else /* may belong to another process */
671 SERVER_START_REQ( get_window_info )
673 req->handle = wine_server_user_handle( hwnd );
674 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
676 SERVER_END_REQ;
678 return hwnd;
682 /***********************************************************************
683 * WIN_SetOwner
685 * Change the owner of a window.
687 HWND WIN_SetOwner( HWND hwnd, HWND owner )
689 WND *win = WIN_GetPtr( hwnd );
690 HWND ret = 0;
692 if (!win || win == WND_DESKTOP) return 0;
693 if (win == WND_OTHER_PROCESS)
695 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
696 return 0;
698 SERVER_START_REQ( set_window_owner )
700 req->handle = wine_server_user_handle( hwnd );
701 req->owner = wine_server_user_handle( owner );
702 if (!wine_server_call( req ))
704 win->owner = wine_server_ptr_handle( reply->full_owner );
705 ret = wine_server_ptr_handle( reply->prev_owner );
708 SERVER_END_REQ;
709 WIN_ReleasePtr( win );
710 return ret;
714 /***********************************************************************
715 * WIN_SetStyle
717 * Change the style of a window.
719 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
721 BOOL ok, needs_show = FALSE;
722 STYLESTRUCT style;
723 WND *win = WIN_GetPtr( hwnd );
725 if (!win || win == WND_DESKTOP) return 0;
726 if (win == WND_OTHER_PROCESS)
728 if (IsWindow(hwnd))
729 ERR( "cannot set style %x/%x on other process window %p\n",
730 set_bits, clear_bits, hwnd );
731 return 0;
733 style.styleOld = win->dwStyle;
734 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
735 if (style.styleNew == style.styleOld)
737 WIN_ReleasePtr( win );
738 return style.styleNew;
740 SERVER_START_REQ( set_window_info )
742 req->handle = wine_server_user_handle( hwnd );
743 req->flags = SET_WIN_STYLE;
744 req->style = style.styleNew;
745 req->extra_offset = -1;
746 if ((ok = !wine_server_call( req )))
748 style.styleOld = reply->old_style;
749 win->dwStyle = style.styleNew;
752 SERVER_END_REQ;
754 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
756 /* Some apps try to make their window visible through WM_SETREDRAW.
757 * Only do that if the window was never explicitly hidden,
758 * because Steam messes with WM_SETREDRAW after hiding its windows. */
759 needs_show = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
760 invalidate_dce( win, NULL );
762 WIN_ReleasePtr( win );
764 if (!ok) return 0;
766 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
767 if (needs_show)
769 RECT window_rect, client_rect;
770 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
771 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
772 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
773 &window_rect, &client_rect, NULL );
776 return style.styleOld;
780 /***********************************************************************
781 * WIN_GetRectangles
783 * Get the window and client rectangles.
785 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
787 WND *win = WIN_GetPtr( hwnd );
788 BOOL ret = TRUE;
790 if (!win)
792 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
793 return FALSE;
795 if (win == WND_DESKTOP)
797 RECT rect;
798 rect.left = rect.top = 0;
799 if (hwnd == get_hwnd_message_parent())
801 rect.right = 100;
802 rect.bottom = 100;
804 else
806 rect.right = GetSystemMetrics(SM_CXSCREEN);
807 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
809 if (rectWindow) *rectWindow = rect;
810 if (rectClient) *rectClient = rect;
811 return TRUE;
813 if (win != WND_OTHER_PROCESS)
815 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
817 switch (relative)
819 case COORDS_CLIENT:
820 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
821 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
822 if (win->dwExStyle & WS_EX_LAYOUTRTL)
823 mirror_rect( &win->rectClient, &window_rect );
824 break;
825 case COORDS_WINDOW:
826 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
827 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
828 if (win->dwExStyle & WS_EX_LAYOUTRTL)
829 mirror_rect( &win->rectWindow, &client_rect );
830 break;
831 case COORDS_PARENT:
832 if (win->parent)
834 WND *parent = WIN_GetPtr( win->parent );
835 if (parent == WND_DESKTOP) break;
836 if (!parent || parent == WND_OTHER_PROCESS)
838 WIN_ReleasePtr( win );
839 goto other_process;
841 if (parent->flags & WIN_CHILDREN_MOVED)
843 WIN_ReleasePtr( parent );
844 WIN_ReleasePtr( win );
845 goto other_process;
847 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
849 mirror_rect( &parent->rectClient, &window_rect );
850 mirror_rect( &parent->rectClient, &client_rect );
852 WIN_ReleasePtr( parent );
854 break;
855 case COORDS_SCREEN:
856 while (win->parent)
858 WND *parent = WIN_GetPtr( win->parent );
859 if (parent == WND_DESKTOP) break;
860 if (!parent || parent == WND_OTHER_PROCESS)
862 WIN_ReleasePtr( win );
863 goto other_process;
865 WIN_ReleasePtr( win );
866 if (parent->flags & WIN_CHILDREN_MOVED)
868 WIN_ReleasePtr( parent );
869 goto other_process;
871 win = parent;
872 if (win->parent)
874 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
875 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
878 break;
880 if (rectWindow) *rectWindow = window_rect;
881 if (rectClient) *rectClient = client_rect;
882 WIN_ReleasePtr( win );
883 return TRUE;
886 other_process:
887 SERVER_START_REQ( get_window_rectangles )
889 req->handle = wine_server_user_handle( hwnd );
890 req->relative = relative;
891 if ((ret = !wine_server_call_err( req )))
893 if (rectWindow)
895 rectWindow->left = reply->window.left;
896 rectWindow->top = reply->window.top;
897 rectWindow->right = reply->window.right;
898 rectWindow->bottom = reply->window.bottom;
900 if (rectClient)
902 rectClient->left = reply->client.left;
903 rectClient->top = reply->client.top;
904 rectClient->right = reply->client.right;
905 rectClient->bottom = reply->client.bottom;
909 SERVER_END_REQ;
910 return ret;
914 /***********************************************************************
915 * WIN_DestroyWindow
917 * Destroy storage associated to a window. "Internals" p.358
919 LRESULT WIN_DestroyWindow( HWND hwnd )
921 WND *wndPtr;
922 HWND *list;
923 HMENU menu = 0, sys_menu;
924 HWND icon_title;
925 struct window_surface *surface;
927 TRACE("%p\n", hwnd );
929 /* free child windows */
930 if ((list = WIN_ListChildren( hwnd )))
932 int i;
933 for (i = 0; list[i]; i++)
935 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
936 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
938 HeapFree( GetProcessHeap(), 0, list );
941 /* Unlink now so we won't bother with the children later on */
942 SERVER_START_REQ( set_parent )
944 req->handle = wine_server_user_handle( hwnd );
945 req->parent = 0;
946 wine_server_call( req );
948 SERVER_END_REQ;
951 * Send the WM_NCDESTROY to the window being destroyed.
953 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
955 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
957 /* free resources associated with the window */
959 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
960 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
961 menu = (HMENU)wndPtr->wIDmenu;
962 sys_menu = wndPtr->hSysMenu;
963 free_dce( wndPtr->dce, hwnd );
964 wndPtr->dce = NULL;
965 icon_title = wndPtr->icon_title;
966 HeapFree( GetProcessHeap(), 0, wndPtr->text );
967 wndPtr->text = NULL;
968 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
969 wndPtr->pScroll = NULL;
970 surface = wndPtr->surface;
971 wndPtr->surface = NULL;
972 WIN_ReleasePtr( wndPtr );
974 if (icon_title) DestroyWindow( icon_title );
975 if (menu) DestroyMenu( menu );
976 if (sys_menu) DestroyMenu( sys_menu );
977 if (surface)
979 register_window_surface( surface, NULL );
980 window_surface_release( surface );
983 USER_Driver->pDestroyWindow( hwnd );
985 free_window_handle( hwnd );
986 return 0;
990 /***********************************************************************
991 * destroy_thread_window
993 * Destroy a window upon exit of its thread.
995 static void destroy_thread_window( HWND hwnd )
997 WND *wndPtr;
998 HWND *list;
999 HMENU menu = 0, sys_menu = 0;
1000 struct window_surface *surface = NULL;
1001 WORD index;
1003 /* free child windows */
1005 if ((list = WIN_ListChildren( hwnd )))
1007 int i;
1008 for (i = 0; list[i]; i++)
1010 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
1011 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1013 HeapFree( GetProcessHeap(), 0, list );
1016 /* destroy the client-side storage */
1018 index = USER_HANDLE_TO_INDEX(hwnd);
1019 if (index >= NB_USER_HANDLES) return;
1020 USER_Lock();
1021 if ((wndPtr = user_handles[index]))
1023 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
1024 sys_menu = wndPtr->hSysMenu;
1025 free_dce( wndPtr->dce, hwnd );
1026 surface = wndPtr->surface;
1027 wndPtr->surface = NULL;
1028 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
1030 USER_Unlock();
1032 HeapFree( GetProcessHeap(), 0, wndPtr );
1033 if (menu) DestroyMenu( menu );
1034 if (sys_menu) DestroyMenu( sys_menu );
1035 if (surface)
1037 register_window_surface( surface, NULL );
1038 window_surface_release( surface );
1043 /***********************************************************************
1044 * destroy_thread_child_windows
1046 * Destroy child windows upon exit of its thread.
1048 static void destroy_thread_child_windows( HWND hwnd )
1050 HWND *list;
1051 int i;
1053 if (WIN_IsCurrentThread( hwnd ))
1055 destroy_thread_window( hwnd );
1057 else if ((list = WIN_ListChildren( hwnd )))
1059 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1060 HeapFree( GetProcessHeap(), 0, list );
1065 /***********************************************************************
1066 * WIN_DestroyThreadWindows
1068 * Destroy all children of 'wnd' owned by the current thread.
1070 void WIN_DestroyThreadWindows( HWND hwnd )
1072 HWND *list;
1073 int i;
1075 if (!(list = WIN_ListChildren( hwnd ))) return;
1077 /* reset owners of top-level windows */
1078 for (i = 0; list[i]; i++)
1080 if (!WIN_IsCurrentThread( list[i] ))
1082 HWND owner = GetWindow( list[i], GW_OWNER );
1083 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1087 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1088 HeapFree( GetProcessHeap(), 0, list );
1092 /***********************************************************************
1093 * WIN_FixCoordinates
1095 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1096 * returns default show mode in sw.
1098 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1100 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1101 POINT pos[2];
1103 if (cs->dwExStyle & WS_EX_MDICHILD)
1105 UINT id = 0;
1107 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1108 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1110 TRACE("MDI child id %04x\n", id);
1113 if (cs->style & (WS_CHILD | WS_POPUP))
1115 if (cs->dwExStyle & WS_EX_MDICHILD)
1117 if (IS_DEFAULT(cs->x))
1119 cs->x = pos[0].x;
1120 cs->y = pos[0].y;
1122 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1123 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1125 else
1127 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1128 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1131 else /* overlapped window */
1133 HMONITOR monitor;
1134 MONITORINFO mon_info;
1135 STARTUPINFOW info;
1137 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1139 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1140 mon_info.cbSize = sizeof(mon_info);
1141 GetMonitorInfoW( monitor, &mon_info );
1142 GetStartupInfoW( &info );
1144 if (IS_DEFAULT(cs->x))
1146 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1147 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1148 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1151 if (IS_DEFAULT(cs->cx))
1153 if (info.dwFlags & STARTF_USESIZE)
1155 cs->cx = info.dwXSize;
1156 cs->cy = info.dwYSize;
1158 else
1160 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1161 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1164 /* neither x nor cx are default. Check the y values .
1165 * In the trace we see Outlook and Outlook Express using
1166 * cy set to CW_USEDEFAULT when opening the address book.
1168 else if (IS_DEFAULT(cs->cy))
1170 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1171 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1174 #undef IS_DEFAULT
1177 /***********************************************************************
1178 * dump_window_styles
1180 static void dump_window_styles( DWORD style, DWORD exstyle )
1182 TRACE( "style:" );
1183 if(style & WS_POPUP) TRACE(" WS_POPUP");
1184 if(style & WS_CHILD) TRACE(" WS_CHILD");
1185 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1186 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1187 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1188 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1189 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1190 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1191 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1192 else
1194 if(style & WS_BORDER) TRACE(" WS_BORDER");
1195 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1197 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1198 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1199 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1200 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1201 if (style & WS_CHILD)
1203 if(style & WS_GROUP) TRACE(" WS_GROUP");
1204 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1206 else
1208 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1209 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1212 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1213 #define DUMPED_STYLES \
1214 ((DWORD)(WS_POPUP | \
1215 WS_CHILD | \
1216 WS_MINIMIZE | \
1217 WS_VISIBLE | \
1218 WS_DISABLED | \
1219 WS_CLIPSIBLINGS | \
1220 WS_CLIPCHILDREN | \
1221 WS_MAXIMIZE | \
1222 WS_BORDER | \
1223 WS_DLGFRAME | \
1224 WS_VSCROLL | \
1225 WS_HSCROLL | \
1226 WS_SYSMENU | \
1227 WS_THICKFRAME | \
1228 WS_GROUP | \
1229 WS_TABSTOP | \
1230 WS_MINIMIZEBOX | \
1231 WS_MAXIMIZEBOX))
1233 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1234 TRACE("\n");
1235 #undef DUMPED_STYLES
1237 TRACE( "exstyle:" );
1238 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1239 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1240 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1241 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1242 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1243 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1244 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1245 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1246 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1247 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1248 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1249 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1250 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1251 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1252 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1253 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1254 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1255 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1256 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1258 #define DUMPED_EX_STYLES \
1259 ((DWORD)(WS_EX_DLGMODALFRAME | \
1260 WS_EX_DRAGDETECT | \
1261 WS_EX_NOPARENTNOTIFY | \
1262 WS_EX_TOPMOST | \
1263 WS_EX_ACCEPTFILES | \
1264 WS_EX_TRANSPARENT | \
1265 WS_EX_MDICHILD | \
1266 WS_EX_TOOLWINDOW | \
1267 WS_EX_WINDOWEDGE | \
1268 WS_EX_CLIENTEDGE | \
1269 WS_EX_CONTEXTHELP | \
1270 WS_EX_RIGHT | \
1271 WS_EX_RTLREADING | \
1272 WS_EX_LEFTSCROLLBAR | \
1273 WS_EX_CONTROLPARENT | \
1274 WS_EX_STATICEDGE | \
1275 WS_EX_APPWINDOW | \
1276 WS_EX_LAYERED | \
1277 WS_EX_LAYOUTRTL))
1279 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1280 TRACE("\n");
1281 #undef DUMPED_EX_STYLES
1285 /***********************************************************************
1286 * WIN_CreateWindowEx
1288 * Implementation of CreateWindowEx().
1290 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1292 INT cx, cy, style, sw = SW_SHOW;
1293 LRESULT result;
1294 RECT rect;
1295 WND *wndPtr;
1296 HWND hwnd, parent, owner, top_child = 0;
1297 MDICREATESTRUCTW mdi_cs;
1298 CBT_CREATEWNDW cbtc;
1299 CREATESTRUCTW cbcs;
1301 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1302 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1303 debugstr_w(className),
1304 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1305 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1306 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1308 /* Fix the styles for MDI children */
1309 if (cs->dwExStyle & WS_EX_MDICHILD)
1311 UINT flags = 0;
1313 wndPtr = WIN_GetPtr(cs->hwndParent);
1314 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1316 flags = wndPtr->flags;
1317 WIN_ReleasePtr(wndPtr);
1320 if (!(flags & WIN_ISMDICLIENT))
1322 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1323 return 0;
1326 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1327 * MDICREATESTRUCT members have the originally passed values.
1329 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1330 * have the same layout.
1332 mdi_cs.szClass = cs->lpszClass;
1333 mdi_cs.szTitle = cs->lpszName;
1334 mdi_cs.hOwner = cs->hInstance;
1335 mdi_cs.x = cs->x;
1336 mdi_cs.y = cs->y;
1337 mdi_cs.cx = cs->cx;
1338 mdi_cs.cy = cs->cy;
1339 mdi_cs.style = cs->style;
1340 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1342 cs->lpCreateParams = &mdi_cs;
1344 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1346 if (cs->style & WS_POPUP)
1348 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1349 return 0;
1351 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1353 else
1355 cs->style &= ~WS_POPUP;
1356 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1357 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1360 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1362 if (top_child)
1364 /* Restore current maximized child */
1365 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1367 TRACE("Restoring current maximized child %p\n", top_child);
1368 if (cs->style & WS_MAXIMIZE)
1370 /* if the new window is maximized don't bother repainting */
1371 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1372 ShowWindow( top_child, SW_SHOWNORMAL );
1373 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1375 else ShowWindow( top_child, SW_SHOWNORMAL );
1380 /* Find the parent window */
1382 parent = cs->hwndParent;
1383 owner = 0;
1385 if (cs->hwndParent == HWND_MESSAGE)
1387 cs->hwndParent = parent = get_hwnd_message_parent();
1389 else if (cs->hwndParent)
1391 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1393 parent = GetDesktopWindow();
1394 owner = cs->hwndParent;
1396 else
1398 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1399 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1400 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1403 else
1405 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1407 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1409 WARN("No parent for child window\n" );
1410 SetLastError(ERROR_TLW_WITH_WSCHILD);
1411 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1413 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1414 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1415 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1417 DWORD layout;
1418 GetProcessDefaultLayout( &layout );
1419 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1420 parent = GetDesktopWindow();
1424 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1426 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1427 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1428 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1429 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1430 else
1431 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1433 /* Create the window structure */
1435 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1436 return 0;
1437 hwnd = wndPtr->obj.handle;
1439 /* Fill the window structure */
1441 wndPtr->tid = GetCurrentThreadId();
1442 wndPtr->hInstance = cs->hInstance;
1443 wndPtr->text = NULL;
1444 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1445 wndPtr->dwExStyle = cs->dwExStyle;
1446 wndPtr->wIDmenu = 0;
1447 wndPtr->helpContext = 0;
1448 wndPtr->pScroll = NULL;
1449 wndPtr->userdata = 0;
1450 wndPtr->hIcon = 0;
1451 wndPtr->hIconSmall = 0;
1452 wndPtr->hSysMenu = 0;
1454 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1455 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1457 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1460 * Correct the window styles.
1462 * It affects only the style loaded into the WIN structure.
1465 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1467 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1468 if (!(wndPtr->dwStyle & WS_POPUP))
1469 wndPtr->dwStyle |= WS_CAPTION;
1472 /* WS_EX_WINDOWEDGE depends on some other styles */
1473 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1474 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1475 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1477 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1478 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1479 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1481 else
1482 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1484 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1485 wndPtr->flags |= WIN_NEED_SIZE;
1487 SERVER_START_REQ( set_window_info )
1489 req->handle = wine_server_user_handle( hwnd );
1490 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1491 req->style = wndPtr->dwStyle;
1492 req->ex_style = wndPtr->dwExStyle;
1493 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1494 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1495 req->extra_offset = -1;
1496 wine_server_call( req );
1498 SERVER_END_REQ;
1500 /* Set the window menu */
1502 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1504 if (cs->hMenu)
1506 if (!MENU_SetMenu(hwnd, cs->hMenu))
1508 WIN_ReleasePtr( wndPtr );
1509 free_window_handle( hwnd );
1510 return 0;
1513 else
1515 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1516 if (menuName)
1518 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1519 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1523 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1525 /* call the WH_CBT hook */
1527 /* the window style passed to the hook must be the real window style,
1528 * rather than just the window style that the caller to CreateWindowEx
1529 * passed in, so we have to copy the original CREATESTRUCT and get the
1530 * the real style. */
1531 cbcs = *cs;
1532 cbcs.style = wndPtr->dwStyle;
1533 cbtc.lpcs = &cbcs;
1534 cbtc.hwndInsertAfter = HWND_TOP;
1535 WIN_ReleasePtr( wndPtr );
1536 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1538 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1540 cx = cs->cx;
1541 cy = cs->cy;
1542 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1544 POINT maxSize, maxPos, minTrack, maxTrack;
1545 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1546 if (maxTrack.x < cx) cx = maxTrack.x;
1547 if (maxTrack.y < cy) cy = maxTrack.y;
1548 if (minTrack.x > cx) cx = minTrack.x;
1549 if (minTrack.y > cy) cy = minTrack.y;
1552 if (cx < 0) cx = 0;
1553 if (cy < 0) cy = 0;
1554 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1555 /* check for wraparound */
1556 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1557 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1558 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1560 /* send WM_NCCREATE */
1562 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1563 if (unicode)
1564 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1565 else
1566 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1567 if (!result)
1569 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1570 goto failed;
1573 /* send WM_NCCALCSIZE */
1575 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1577 /* yes, even if the CBT hook was called with HWND_TOP */
1578 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1579 RECT client_rect = rect;
1581 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1582 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1583 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1584 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1585 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1587 else return 0;
1589 /* send WM_CREATE */
1591 if (unicode)
1592 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1593 else
1594 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1595 if (result == -1) goto failed;
1597 /* call the driver */
1599 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1601 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1603 /* send the size messages */
1605 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1606 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1607 if (!(wndPtr->flags & WIN_NEED_SIZE))
1609 WIN_ReleasePtr( wndPtr );
1610 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1611 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1612 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1613 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1615 else WIN_ReleasePtr( wndPtr );
1617 /* Show the window, maximizing or minimizing if needed */
1619 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1620 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1622 RECT newPos;
1623 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1625 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1626 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1627 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1628 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1629 newPos.bottom - newPos.top, swFlag );
1632 /* Notify the parent window only */
1634 send_parent_notify( hwnd, WM_CREATE );
1635 if (!IsWindow( hwnd )) return 0;
1637 if (cs->style & WS_VISIBLE)
1639 if (cs->style & WS_MAXIMIZE)
1640 sw = SW_SHOW;
1641 else if (cs->style & WS_MINIMIZE)
1642 sw = SW_SHOWMINIMIZED;
1644 ShowWindow( hwnd, sw );
1645 if (cs->dwExStyle & WS_EX_MDICHILD)
1647 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1648 /* ShowWindow won't activate child windows */
1649 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1653 /* Call WH_SHELL hook */
1655 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1656 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1658 TRACE("created window %p\n", hwnd);
1659 return hwnd;
1661 failed:
1662 WIN_DestroyWindow( hwnd );
1663 return 0;
1667 /***********************************************************************
1668 * CreateWindowExA (USER32.@)
1670 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1671 LPCSTR windowName, DWORD style, INT x,
1672 INT y, INT width, INT height,
1673 HWND parent, HMENU menu,
1674 HINSTANCE instance, LPVOID data )
1676 CREATESTRUCTA cs;
1678 cs.lpCreateParams = data;
1679 cs.hInstance = instance;
1680 cs.hMenu = menu;
1681 cs.hwndParent = parent;
1682 cs.x = x;
1683 cs.y = y;
1684 cs.cx = width;
1685 cs.cy = height;
1686 cs.style = style;
1687 cs.lpszName = windowName;
1688 cs.lpszClass = className;
1689 cs.dwExStyle = exStyle;
1691 if (!IS_INTRESOURCE(className))
1693 WCHAR bufferW[256];
1694 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1695 return 0;
1696 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1698 /* Note: we rely on the fact that CREATESTRUCTA and */
1699 /* CREATESTRUCTW have the same layout. */
1700 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1704 /***********************************************************************
1705 * CreateWindowExW (USER32.@)
1707 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1708 LPCWSTR windowName, DWORD style, INT x,
1709 INT y, INT width, INT height,
1710 HWND parent, HMENU menu,
1711 HINSTANCE instance, LPVOID data )
1713 CREATESTRUCTW cs;
1715 cs.lpCreateParams = data;
1716 cs.hInstance = instance;
1717 cs.hMenu = menu;
1718 cs.hwndParent = parent;
1719 cs.x = x;
1720 cs.y = y;
1721 cs.cx = width;
1722 cs.cy = height;
1723 cs.style = style;
1724 cs.lpszName = windowName;
1725 cs.lpszClass = className;
1726 cs.dwExStyle = exStyle;
1728 return wow_handlers.create_window( &cs, className, instance, TRUE );
1732 /***********************************************************************
1733 * WIN_SendDestroyMsg
1735 static void WIN_SendDestroyMsg( HWND hwnd )
1737 GUITHREADINFO info;
1739 info.cbSize = sizeof(info);
1740 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1742 if (hwnd == info.hwndCaret) DestroyCaret();
1743 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1747 * Send the WM_DESTROY to the window.
1749 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1752 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1753 * make sure that the window still exists when we come back.
1755 if (IsWindow(hwnd))
1757 HWND* pWndArray;
1758 int i;
1760 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1762 for (i = 0; pWndArray[i]; i++)
1764 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1766 HeapFree( GetProcessHeap(), 0, pWndArray );
1768 else
1769 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1773 /***********************************************************************
1774 * DestroyWindow (USER32.@)
1776 BOOL WINAPI DestroyWindow( HWND hwnd )
1778 BOOL is_child;
1780 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1782 SetLastError( ERROR_ACCESS_DENIED );
1783 return FALSE;
1786 TRACE("(%p)\n", hwnd);
1788 /* Call hooks */
1790 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1792 if (MENU_IsMenuActive() == hwnd)
1793 EndMenu();
1795 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1797 if (is_child)
1799 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1800 send_parent_notify( hwnd, WM_DESTROY );
1802 else if (!GetWindow( hwnd, GW_OWNER ))
1804 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1805 /* FIXME: clean up palette - see "Internals" p.352 */
1808 if (!IsWindow(hwnd)) return TRUE;
1810 /* Hide the window */
1811 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1813 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1814 if (is_child)
1815 ShowWindow( hwnd, SW_HIDE );
1816 else
1817 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1818 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1821 if (!IsWindow(hwnd)) return TRUE;
1823 /* Recursively destroy owned windows */
1825 if (!is_child)
1827 for (;;)
1829 int i, got_one = 0;
1830 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1831 if (list)
1833 for (i = 0; list[i]; i++)
1835 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1836 if (WIN_IsCurrentThread( list[i] ))
1838 DestroyWindow( list[i] );
1839 got_one = 1;
1840 continue;
1842 WIN_SetOwner( list[i], 0 );
1844 HeapFree( GetProcessHeap(), 0, list );
1846 if (!got_one) break;
1850 /* Send destroy messages */
1852 WIN_SendDestroyMsg( hwnd );
1853 if (!IsWindow( hwnd )) return TRUE;
1855 if (GetClipboardOwner() == hwnd)
1856 CLIPBOARD_ReleaseOwner();
1858 /* Destroy the window storage */
1860 WIN_DestroyWindow( hwnd );
1861 return TRUE;
1865 /***********************************************************************
1866 * CloseWindow (USER32.@)
1868 BOOL WINAPI CloseWindow( HWND hwnd )
1870 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1871 ShowWindow( hwnd, SW_MINIMIZE );
1872 return TRUE;
1876 /***********************************************************************
1877 * OpenIcon (USER32.@)
1879 BOOL WINAPI OpenIcon( HWND hwnd )
1881 if (!IsIconic( hwnd )) return FALSE;
1882 ShowWindow( hwnd, SW_SHOWNORMAL );
1883 return TRUE;
1887 /***********************************************************************
1888 * FindWindowExW (USER32.@)
1890 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1892 HWND *list = NULL;
1893 HWND retvalue = 0;
1894 int i = 0, len = 0;
1895 WCHAR *buffer = NULL;
1897 if (!parent && child) parent = GetDesktopWindow();
1898 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1900 if (title)
1902 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1903 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1906 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1908 if (child)
1910 child = WIN_GetFullHandle( child );
1911 while (list[i] && list[i] != child) i++;
1912 if (!list[i]) goto done;
1913 i++; /* start from next window */
1916 if (title)
1918 while (list[i])
1920 if (GetWindowTextW( list[i], buffer, len + 1 ))
1922 if (!strcmpiW( buffer, title )) break;
1924 else
1926 if (!title[0]) break;
1928 i++;
1931 retvalue = list[i];
1933 done:
1934 HeapFree( GetProcessHeap(), 0, list );
1935 HeapFree( GetProcessHeap(), 0, buffer );
1936 return retvalue;
1941 /***********************************************************************
1942 * FindWindowA (USER32.@)
1944 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1946 HWND ret = FindWindowExA( 0, 0, className, title );
1947 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1948 return ret;
1952 /***********************************************************************
1953 * FindWindowExA (USER32.@)
1955 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1957 LPWSTR titleW = NULL;
1958 HWND hwnd = 0;
1960 if (title)
1962 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1963 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1964 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1967 if (!IS_INTRESOURCE(className))
1969 WCHAR classW[256];
1970 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1971 hwnd = FindWindowExW( parent, child, classW, titleW );
1973 else
1975 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1978 HeapFree( GetProcessHeap(), 0, titleW );
1979 return hwnd;
1983 /***********************************************************************
1984 * FindWindowW (USER32.@)
1986 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1988 return FindWindowExW( 0, 0, className, title );
1992 /**********************************************************************
1993 * GetDesktopWindow (USER32.@)
1995 HWND WINAPI GetDesktopWindow(void)
1997 struct user_thread_info *thread_info = get_user_thread_info();
1999 if (thread_info->top_window) return thread_info->top_window;
2001 SERVER_START_REQ( get_desktop_window )
2003 req->force = 0;
2004 if (!wine_server_call( req ))
2006 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2007 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2010 SERVER_END_REQ;
2012 if (!thread_info->top_window)
2014 USEROBJECTFLAGS flags;
2015 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2016 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2018 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2019 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2020 STARTUPINFOW si;
2021 PROCESS_INFORMATION pi;
2022 WCHAR windir[MAX_PATH];
2023 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2024 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2025 void *redir;
2027 memset( &si, 0, sizeof(si) );
2028 si.cb = sizeof(si);
2029 si.dwFlags = STARTF_USESTDHANDLES;
2030 si.hStdInput = 0;
2031 si.hStdOutput = 0;
2032 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2034 GetSystemDirectoryW( windir, MAX_PATH );
2035 strcpyW( app, windir );
2036 strcatW( app, explorer );
2037 strcpyW( cmdline, app );
2038 strcatW( cmdline, args );
2040 Wow64DisableWow64FsRedirection( &redir );
2041 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2042 NULL, windir, &si, &pi ))
2044 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2045 WaitForInputIdle( pi.hProcess, 10000 );
2046 CloseHandle( pi.hThread );
2047 CloseHandle( pi.hProcess );
2049 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2050 Wow64RevertWow64FsRedirection( redir );
2052 else TRACE( "not starting explorer since winstation is not visible\n" );
2054 SERVER_START_REQ( get_desktop_window )
2056 req->force = 1;
2057 if (!wine_server_call( req ))
2059 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2060 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2063 SERVER_END_REQ;
2066 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2067 ERR( "failed to create desktop window\n" );
2069 return thread_info->top_window;
2073 /*******************************************************************
2074 * EnableWindow (USER32.@)
2076 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2078 BOOL retvalue;
2079 HWND full_handle;
2081 if (is_broadcast(hwnd))
2083 SetLastError( ERROR_INVALID_PARAMETER );
2084 return FALSE;
2087 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2088 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2090 hwnd = full_handle;
2092 TRACE("( %p, %d )\n", hwnd, enable);
2094 retvalue = !IsWindowEnabled( hwnd );
2096 if (enable && retvalue)
2098 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2099 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2101 else if (!enable && !retvalue)
2103 HWND capture_wnd;
2105 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2107 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2109 if (hwnd == GetFocus())
2110 SetFocus( 0 ); /* A disabled window can't have the focus */
2112 capture_wnd = GetCapture();
2113 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2114 ReleaseCapture(); /* A disabled window can't capture the mouse */
2116 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2118 return retvalue;
2122 /***********************************************************************
2123 * IsWindowEnabled (USER32.@)
2125 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2127 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2131 /***********************************************************************
2132 * IsWindowUnicode (USER32.@)
2134 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2136 WND * wndPtr;
2137 BOOL retvalue = FALSE;
2139 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2141 if (wndPtr == WND_DESKTOP) return TRUE;
2143 if (wndPtr != WND_OTHER_PROCESS)
2145 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2146 WIN_ReleasePtr( wndPtr );
2148 else
2150 SERVER_START_REQ( get_window_info )
2152 req->handle = wine_server_user_handle( hwnd );
2153 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2155 SERVER_END_REQ;
2157 return retvalue;
2161 /**********************************************************************
2162 * WIN_GetWindowLong
2164 * Helper function for GetWindowLong().
2166 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2168 LONG_PTR retvalue = 0;
2169 WND *wndPtr;
2171 if (offset == GWLP_HWNDPARENT)
2173 HWND parent = GetAncestor( hwnd, GA_PARENT );
2174 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2175 return (ULONG_PTR)parent;
2178 if (!(wndPtr = WIN_GetPtr( hwnd )))
2180 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2181 return 0;
2184 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2186 if (offset == GWLP_WNDPROC)
2188 SetLastError( ERROR_ACCESS_DENIED );
2189 return 0;
2191 SERVER_START_REQ( set_window_info )
2193 req->handle = wine_server_user_handle( hwnd );
2194 req->flags = 0; /* don't set anything, just retrieve */
2195 req->extra_offset = (offset >= 0) ? offset : -1;
2196 req->extra_size = (offset >= 0) ? size : 0;
2197 if (!wine_server_call_err( req ))
2199 switch(offset)
2201 case GWL_STYLE: retvalue = reply->old_style; break;
2202 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2203 case GWLP_ID: retvalue = reply->old_id; break;
2204 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2205 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2206 default:
2207 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2208 else SetLastError( ERROR_INVALID_INDEX );
2209 break;
2213 SERVER_END_REQ;
2214 return retvalue;
2217 /* now we have a valid wndPtr */
2219 if (offset >= 0)
2221 if (offset > (int)(wndPtr->cbWndExtra - size))
2223 WARN("Invalid offset %d\n", offset );
2224 WIN_ReleasePtr( wndPtr );
2225 SetLastError( ERROR_INVALID_INDEX );
2226 return 0;
2228 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2230 /* Special case for dialog window procedure */
2231 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2232 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2233 WIN_ReleasePtr( wndPtr );
2234 return retvalue;
2237 switch(offset)
2239 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2240 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2241 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2242 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2243 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2244 case GWLP_WNDPROC:
2245 /* This looks like a hack only for the edit control (see tests). This makes these controls
2246 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2247 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2249 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2250 retvalue = (ULONG_PTR)wndPtr->winproc;
2251 else
2252 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2253 break;
2254 default:
2255 WARN("Unknown offset %d\n", offset );
2256 SetLastError( ERROR_INVALID_INDEX );
2257 break;
2259 WIN_ReleasePtr(wndPtr);
2260 return retvalue;
2264 /**********************************************************************
2265 * WIN_SetWindowLong
2267 * Helper function for SetWindowLong().
2269 * 0 is the failure code. However, in the case of failure SetLastError
2270 * must be set to distinguish between a 0 return value and a failure.
2272 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2274 STYLESTRUCT style;
2275 BOOL ok, needs_show = FALSE;
2276 LONG_PTR retval = 0;
2277 WND *wndPtr;
2279 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2281 if (is_broadcast(hwnd))
2283 SetLastError( ERROR_INVALID_PARAMETER );
2284 return FALSE;
2287 if (!(wndPtr = WIN_GetPtr( hwnd )))
2289 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2290 return 0;
2292 if (wndPtr == WND_DESKTOP)
2294 /* can't change anything on the desktop window */
2295 SetLastError( ERROR_ACCESS_DENIED );
2296 return 0;
2298 if (wndPtr == WND_OTHER_PROCESS)
2300 if (offset == GWLP_WNDPROC)
2302 SetLastError( ERROR_ACCESS_DENIED );
2303 return 0;
2305 if (offset > 32767 || offset < -32767)
2307 SetLastError( ERROR_INVALID_INDEX );
2308 return 0;
2310 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2313 /* first some special cases */
2314 switch( offset )
2316 case GWL_STYLE:
2317 style.styleOld = wndPtr->dwStyle;
2318 style.styleNew = newval;
2319 WIN_ReleasePtr( wndPtr );
2320 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2321 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2322 newval = style.styleNew;
2323 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2324 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2325 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2326 WS_EX_WINDOWEDGE too */
2327 break;
2328 case GWL_EXSTYLE:
2329 style.styleOld = wndPtr->dwExStyle;
2330 style.styleNew = newval;
2331 WIN_ReleasePtr( wndPtr );
2332 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2333 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2334 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2335 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2336 /* WS_EX_WINDOWEDGE depends on some other styles */
2337 if (newval & WS_EX_DLGMODALFRAME)
2338 newval |= WS_EX_WINDOWEDGE;
2339 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2340 newval |= WS_EX_WINDOWEDGE;
2341 else
2342 newval &= ~WS_EX_WINDOWEDGE;
2343 break;
2344 case GWLP_HWNDPARENT:
2345 if (wndPtr->parent == GetDesktopWindow())
2347 WIN_ReleasePtr( wndPtr );
2348 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2350 else
2352 WIN_ReleasePtr( wndPtr );
2353 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2355 case GWLP_WNDPROC:
2357 WNDPROC proc;
2358 UINT old_flags = wndPtr->flags;
2359 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2360 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2361 if (proc) wndPtr->winproc = proc;
2362 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2363 else wndPtr->flags &= ~WIN_ISUNICODE;
2364 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2366 WIN_ReleasePtr( wndPtr );
2367 return retval;
2369 /* update is_unicode flag on the server side */
2370 break;
2372 case GWLP_ID:
2373 case GWLP_HINSTANCE:
2374 case GWLP_USERDATA:
2375 break;
2376 case DWLP_DLGPROC:
2377 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2378 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2380 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2381 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2382 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2383 WIN_ReleasePtr( wndPtr );
2384 return retval;
2386 /* fall through */
2387 default:
2388 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2390 WARN("Invalid offset %d\n", offset );
2391 WIN_ReleasePtr( wndPtr );
2392 SetLastError( ERROR_INVALID_INDEX );
2393 return 0;
2395 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2397 /* already set to the same value */
2398 WIN_ReleasePtr( wndPtr );
2399 return newval;
2401 break;
2404 SERVER_START_REQ( set_window_info )
2406 req->handle = wine_server_user_handle( hwnd );
2407 req->extra_offset = -1;
2408 switch(offset)
2410 case GWL_STYLE:
2411 req->flags = SET_WIN_STYLE;
2412 req->style = newval;
2413 break;
2414 case GWL_EXSTYLE:
2415 req->flags = SET_WIN_EXSTYLE;
2416 req->ex_style = newval;
2417 break;
2418 case GWLP_ID:
2419 req->flags = SET_WIN_ID;
2420 req->id = newval;
2421 break;
2422 case GWLP_HINSTANCE:
2423 req->flags = SET_WIN_INSTANCE;
2424 req->instance = wine_server_client_ptr( (void *)newval );
2425 break;
2426 case GWLP_WNDPROC:
2427 req->flags = SET_WIN_UNICODE;
2428 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2429 break;
2430 case GWLP_USERDATA:
2431 req->flags = SET_WIN_USERDATA;
2432 req->user_data = newval;
2433 break;
2434 default:
2435 req->flags = SET_WIN_EXTRA;
2436 req->extra_offset = offset;
2437 req->extra_size = size;
2438 set_win_data( &req->extra_value, newval, size );
2440 if ((ok = !wine_server_call_err( req )))
2442 switch(offset)
2444 case GWL_STYLE:
2445 wndPtr->dwStyle = newval;
2446 retval = reply->old_style;
2447 break;
2448 case GWL_EXSTYLE:
2449 wndPtr->dwExStyle = newval;
2450 retval = reply->old_ex_style;
2451 break;
2452 case GWLP_ID:
2453 wndPtr->wIDmenu = newval;
2454 retval = reply->old_id;
2455 break;
2456 case GWLP_HINSTANCE:
2457 wndPtr->hInstance = (HINSTANCE)newval;
2458 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2459 break;
2460 case GWLP_WNDPROC:
2461 break;
2462 case GWLP_USERDATA:
2463 wndPtr->userdata = newval;
2464 retval = reply->old_user_data;
2465 break;
2466 default:
2467 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2468 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2469 break;
2473 SERVER_END_REQ;
2475 if (offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
2477 needs_show = !(wndPtr->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
2478 invalidate_dce( wndPtr, NULL );
2480 WIN_ReleasePtr( wndPtr );
2482 if (!ok) return 0;
2484 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2486 style.styleOld = retval;
2487 style.styleNew = newval;
2488 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2489 if (needs_show)
2491 RECT window_rect, client_rect;
2492 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
2493 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
2494 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
2495 &window_rect, &client_rect, NULL );
2497 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2500 return retval;
2504 /**********************************************************************
2505 * GetWindowWord (USER32.@)
2507 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2509 switch(offset)
2511 case GWLP_ID:
2512 case GWLP_HINSTANCE:
2513 case GWLP_HWNDPARENT:
2514 break;
2515 default:
2516 if (offset < 0)
2518 WARN("Invalid offset %d\n", offset );
2519 SetLastError( ERROR_INVALID_INDEX );
2520 return 0;
2522 break;
2524 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2528 /**********************************************************************
2529 * GetWindowLongA (USER32.@)
2531 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2533 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2537 /**********************************************************************
2538 * GetWindowLongW (USER32.@)
2540 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2542 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2546 /**********************************************************************
2547 * SetWindowWord (USER32.@)
2549 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2551 switch(offset)
2553 case GWLP_ID:
2554 case GWLP_HINSTANCE:
2555 case GWLP_HWNDPARENT:
2556 break;
2557 default:
2558 if (offset < 0)
2560 WARN("Invalid offset %d\n", offset );
2561 SetLastError( ERROR_INVALID_INDEX );
2562 return 0;
2564 break;
2566 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2570 /**********************************************************************
2571 * SetWindowLongA (USER32.@)
2573 * See SetWindowLongW.
2575 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2577 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2581 /**********************************************************************
2582 * SetWindowLongW (USER32.@) Set window attribute
2584 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2585 * value in a window's extra memory.
2587 * The _hwnd_ parameter specifies the window. is the handle to a
2588 * window that has extra memory. The _newval_ parameter contains the
2589 * new attribute or extra memory value. If positive, the _offset_
2590 * parameter is the byte-addressed location in the window's extra
2591 * memory to set. If negative, _offset_ specifies the window
2592 * attribute to set, and should be one of the following values:
2594 * GWL_EXSTYLE The window's extended window style
2596 * GWL_STYLE The window's window style.
2598 * GWLP_WNDPROC Pointer to the window's window procedure.
2600 * GWLP_HINSTANCE The window's pplication instance handle.
2602 * GWLP_ID The window's identifier.
2604 * GWLP_USERDATA The window's user-specified data.
2606 * If the window is a dialog box, the _offset_ parameter can be one of
2607 * the following values:
2609 * DWLP_DLGPROC The address of the window's dialog box procedure.
2611 * DWLP_MSGRESULT The return value of a message
2612 * that the dialog box procedure processed.
2614 * DWLP_USER Application specific information.
2616 * RETURNS
2618 * If successful, returns the previous value located at _offset_. Otherwise,
2619 * returns 0.
2621 * NOTES
2623 * Extra memory for a window class is specified by a nonzero cbWndExtra
2624 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2625 * time of class creation.
2627 * Using GWL_WNDPROC to set a new window procedure effectively creates
2628 * a window subclass. Use CallWindowProc() in the new windows procedure
2629 * to pass messages to the superclass's window procedure.
2631 * The user data is reserved for use by the application which created
2632 * the window.
2634 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2635 * instead, call the EnableWindow() function to change the window's
2636 * disabled state.
2638 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2639 * SetParent() instead.
2641 * Win95:
2642 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2643 * it sends WM_STYLECHANGING before changing the settings
2644 * and WM_STYLECHANGED afterwards.
2645 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2647 LONG WINAPI SetWindowLongW(
2648 HWND hwnd, /* [in] window to alter */
2649 INT offset, /* [in] offset, in bytes, of location to alter */
2650 LONG newval /* [in] new value of location */
2652 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2656 /*******************************************************************
2657 * GetWindowTextA (USER32.@)
2659 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2661 WCHAR *buffer;
2663 if (!lpString) return 0;
2665 if (WIN_IsCurrentProcess( hwnd ))
2666 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2668 /* when window belongs to other process, don't send a message */
2669 if (nMaxCount <= 0) return 0;
2670 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2671 get_server_window_text( hwnd, buffer, nMaxCount );
2672 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2673 lpString[nMaxCount-1] = 0;
2674 HeapFree( GetProcessHeap(), 0, buffer );
2675 return strlen(lpString);
2679 /*******************************************************************
2680 * InternalGetWindowText (USER32.@)
2682 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2684 WND *win;
2686 if (nMaxCount <= 0) return 0;
2687 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2688 if (win == WND_DESKTOP) lpString[0] = 0;
2689 else if (win != WND_OTHER_PROCESS)
2691 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2692 else lpString[0] = 0;
2693 WIN_ReleasePtr( win );
2695 else
2697 get_server_window_text( hwnd, lpString, nMaxCount );
2699 return strlenW(lpString);
2703 /*******************************************************************
2704 * GetWindowTextW (USER32.@)
2706 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2708 if (!lpString) return 0;
2710 if (WIN_IsCurrentProcess( hwnd ))
2711 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2713 /* when window belongs to other process, don't send a message */
2714 if (nMaxCount <= 0) return 0;
2715 get_server_window_text( hwnd, lpString, nMaxCount );
2716 return strlenW(lpString);
2720 /*******************************************************************
2721 * SetWindowTextA (USER32.@)
2722 * SetWindowText (USER32.@)
2724 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2726 if (is_broadcast(hwnd))
2728 SetLastError( ERROR_INVALID_PARAMETER );
2729 return FALSE;
2731 if (!WIN_IsCurrentProcess( hwnd ))
2732 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2733 debugstr_a(lpString), hwnd );
2734 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2738 /*******************************************************************
2739 * SetWindowTextW (USER32.@)
2741 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2743 if (is_broadcast(hwnd))
2745 SetLastError( ERROR_INVALID_PARAMETER );
2746 return FALSE;
2748 if (!WIN_IsCurrentProcess( hwnd ))
2749 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2750 debugstr_w(lpString), hwnd );
2751 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2755 /*******************************************************************
2756 * GetWindowTextLengthA (USER32.@)
2758 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2760 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2763 /*******************************************************************
2764 * GetWindowTextLengthW (USER32.@)
2766 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2768 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2772 /*******************************************************************
2773 * IsWindow (USER32.@)
2775 BOOL WINAPI IsWindow( HWND hwnd )
2777 WND *ptr;
2778 BOOL ret;
2780 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2781 if (ptr == WND_DESKTOP) return TRUE;
2783 if (ptr != WND_OTHER_PROCESS)
2785 WIN_ReleasePtr( ptr );
2786 return TRUE;
2789 /* check other processes */
2790 SERVER_START_REQ( get_window_info )
2792 req->handle = wine_server_user_handle( hwnd );
2793 ret = !wine_server_call_err( req );
2795 SERVER_END_REQ;
2796 return ret;
2800 /***********************************************************************
2801 * GetWindowThreadProcessId (USER32.@)
2803 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2805 WND *ptr;
2806 DWORD tid = 0;
2808 if (!(ptr = WIN_GetPtr( hwnd )))
2810 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2811 return 0;
2814 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2816 /* got a valid window */
2817 tid = ptr->tid;
2818 if (process) *process = GetCurrentProcessId();
2819 WIN_ReleasePtr( ptr );
2820 return tid;
2823 /* check other processes */
2824 SERVER_START_REQ( get_window_info )
2826 req->handle = wine_server_user_handle( hwnd );
2827 if (!wine_server_call_err( req ))
2829 tid = (DWORD)reply->tid;
2830 if (process) *process = (DWORD)reply->pid;
2833 SERVER_END_REQ;
2834 return tid;
2838 /*****************************************************************
2839 * GetParent (USER32.@)
2841 HWND WINAPI GetParent( HWND hwnd )
2843 WND *wndPtr;
2844 HWND retvalue = 0;
2846 if (!(wndPtr = WIN_GetPtr( hwnd )))
2848 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2849 return 0;
2851 if (wndPtr == WND_DESKTOP) return 0;
2852 if (wndPtr == WND_OTHER_PROCESS)
2854 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2855 if (style & (WS_POPUP | WS_CHILD))
2857 SERVER_START_REQ( get_window_tree )
2859 req->handle = wine_server_user_handle( hwnd );
2860 if (!wine_server_call_err( req ))
2862 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2863 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2866 SERVER_END_REQ;
2869 else
2871 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2872 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2873 WIN_ReleasePtr( wndPtr );
2875 return retvalue;
2879 /*****************************************************************
2880 * GetAncestor (USER32.@)
2882 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2884 WND *win;
2885 HWND *list, ret = 0;
2887 switch(type)
2889 case GA_PARENT:
2890 if (!(win = WIN_GetPtr( hwnd )))
2892 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2893 return 0;
2895 if (win == WND_DESKTOP) return 0;
2896 if (win != WND_OTHER_PROCESS)
2898 ret = win->parent;
2899 WIN_ReleasePtr( win );
2901 else /* need to query the server */
2903 SERVER_START_REQ( get_window_tree )
2905 req->handle = wine_server_user_handle( hwnd );
2906 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2908 SERVER_END_REQ;
2910 break;
2912 case GA_ROOT:
2913 if (!(list = list_window_parents( hwnd ))) return 0;
2915 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2916 else
2918 int count = 2;
2919 while (list[count]) count++;
2920 ret = list[count - 2]; /* get the one before the desktop */
2922 HeapFree( GetProcessHeap(), 0, list );
2923 break;
2925 case GA_ROOTOWNER:
2926 if (is_desktop_window( hwnd )) return 0;
2927 ret = WIN_GetFullHandle( hwnd );
2928 for (;;)
2930 HWND parent = GetParent( ret );
2931 if (!parent) break;
2932 ret = parent;
2934 break;
2936 return ret;
2940 /*****************************************************************
2941 * SetParent (USER32.@)
2943 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2945 HWND full_handle;
2946 HWND old_parent = 0;
2947 BOOL was_visible;
2948 WND *wndPtr;
2949 POINT pt;
2950 BOOL ret;
2952 if (is_broadcast(hwnd) || is_broadcast(parent))
2954 SetLastError(ERROR_INVALID_PARAMETER);
2955 return 0;
2958 if (!parent) parent = GetDesktopWindow();
2959 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2960 else parent = WIN_GetFullHandle( parent );
2962 if (!IsWindow( parent ))
2964 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2965 return 0;
2968 /* Some applications try to set a child as a parent */
2969 if (IsChild(hwnd, parent))
2971 SetLastError( ERROR_INVALID_PARAMETER );
2972 return 0;
2975 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2976 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2978 if (full_handle == parent)
2980 SetLastError( ERROR_INVALID_PARAMETER );
2981 return 0;
2984 /* Windows hides the window first, then shows it again
2985 * including the WM_SHOWWINDOW messages and all */
2986 was_visible = ShowWindow( hwnd, SW_HIDE );
2988 wndPtr = WIN_GetPtr( hwnd );
2989 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2991 pt.x = wndPtr->rectWindow.left;
2992 pt.y = wndPtr->rectWindow.top;
2994 SERVER_START_REQ( set_parent )
2996 req->handle = wine_server_user_handle( hwnd );
2997 req->parent = wine_server_user_handle( parent );
2998 if ((ret = !wine_server_call( req )))
3000 old_parent = wine_server_ptr_handle( reply->old_parent );
3001 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3005 SERVER_END_REQ;
3006 WIN_ReleasePtr( wndPtr );
3007 if (!ret) return 0;
3009 USER_Driver->pSetParent( full_handle, parent, old_parent );
3011 /* SetParent additionally needs to make hwnd the topmost window
3012 in the x-order and send the expected WM_WINDOWPOSCHANGING and
3013 WM_WINDOWPOSCHANGED notification messages.
3015 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3017 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3019 return old_parent;
3023 /*******************************************************************
3024 * IsChild (USER32.@)
3026 BOOL WINAPI IsChild( HWND parent, HWND child )
3028 HWND *list = list_window_parents( child );
3029 int i;
3030 BOOL ret;
3032 if (!list) return FALSE;
3033 parent = WIN_GetFullHandle( parent );
3034 for (i = 0; list[i]; i++) if (list[i] == parent) break;
3035 ret = list[i] && list[i+1];
3036 HeapFree( GetProcessHeap(), 0, list );
3037 return ret;
3041 /***********************************************************************
3042 * IsWindowVisible (USER32.@)
3044 BOOL WINAPI IsWindowVisible( HWND hwnd )
3046 HWND *list;
3047 BOOL retval = TRUE;
3048 int i;
3050 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3051 if (!(list = list_window_parents( hwnd ))) return TRUE;
3052 if (list[0])
3054 for (i = 0; list[i+1]; i++)
3055 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3056 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3058 HeapFree( GetProcessHeap(), 0, list );
3059 return retval;
3063 /***********************************************************************
3064 * WIN_IsWindowDrawable
3066 * hwnd is drawable when it is visible, all parents are not
3067 * minimized, and it is itself not minimized unless we are
3068 * trying to draw its default class icon.
3070 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3072 HWND *list;
3073 BOOL retval = TRUE;
3074 int i;
3075 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3077 if (!(style & WS_VISIBLE)) return FALSE;
3078 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3080 if (!(list = list_window_parents( hwnd ))) return TRUE;
3081 if (list[0])
3083 for (i = 0; list[i+1]; i++)
3084 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3085 break;
3086 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3088 HeapFree( GetProcessHeap(), 0, list );
3089 return retval;
3093 /*******************************************************************
3094 * GetTopWindow (USER32.@)
3096 HWND WINAPI GetTopWindow( HWND hwnd )
3098 if (!hwnd) hwnd = GetDesktopWindow();
3099 return GetWindow( hwnd, GW_CHILD );
3103 /*******************************************************************
3104 * GetWindow (USER32.@)
3106 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3108 HWND retval = 0;
3110 if (rel == GW_OWNER) /* this one may be available locally */
3112 WND *wndPtr = WIN_GetPtr( hwnd );
3113 if (!wndPtr)
3115 SetLastError( ERROR_INVALID_HANDLE );
3116 return 0;
3118 if (wndPtr == WND_DESKTOP) return 0;
3119 if (wndPtr != WND_OTHER_PROCESS)
3121 retval = wndPtr->owner;
3122 WIN_ReleasePtr( wndPtr );
3123 return retval;
3125 /* else fall through to server call */
3128 SERVER_START_REQ( get_window_tree )
3130 req->handle = wine_server_user_handle( hwnd );
3131 if (!wine_server_call_err( req ))
3133 switch(rel)
3135 case GW_HWNDFIRST:
3136 retval = wine_server_ptr_handle( reply->first_sibling );
3137 break;
3138 case GW_HWNDLAST:
3139 retval = wine_server_ptr_handle( reply->last_sibling );
3140 break;
3141 case GW_HWNDNEXT:
3142 retval = wine_server_ptr_handle( reply->next_sibling );
3143 break;
3144 case GW_HWNDPREV:
3145 retval = wine_server_ptr_handle( reply->prev_sibling );
3146 break;
3147 case GW_OWNER:
3148 retval = wine_server_ptr_handle( reply->owner );
3149 break;
3150 case GW_CHILD:
3151 retval = wine_server_ptr_handle( reply->first_child );
3152 break;
3156 SERVER_END_REQ;
3157 return retval;
3161 /*******************************************************************
3162 * ShowOwnedPopups (USER32.@)
3164 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3166 int count = 0;
3167 WND *pWnd;
3168 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3170 if (!win_array) return TRUE;
3172 while (win_array[count]) count++;
3173 while (--count >= 0)
3175 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3176 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3177 if (pWnd == WND_OTHER_PROCESS) continue;
3178 if (fShow)
3180 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3182 WIN_ReleasePtr( pWnd );
3183 /* In Windows, ShowOwnedPopups(TRUE) generates
3184 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3185 * regardless of the state of the owner
3187 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3188 continue;
3191 else
3193 if (pWnd->dwStyle & WS_VISIBLE)
3195 WIN_ReleasePtr( pWnd );
3196 /* In Windows, ShowOwnedPopups(FALSE) generates
3197 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3198 * regardless of the state of the owner
3200 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3201 continue;
3204 WIN_ReleasePtr( pWnd );
3206 HeapFree( GetProcessHeap(), 0, win_array );
3207 return TRUE;
3211 /*******************************************************************
3212 * GetLastActivePopup (USER32.@)
3214 HWND WINAPI GetLastActivePopup( HWND hwnd )
3216 HWND retval = hwnd;
3218 SERVER_START_REQ( get_window_info )
3220 req->handle = wine_server_user_handle( hwnd );
3221 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3223 SERVER_END_REQ;
3224 return retval;
3228 /*******************************************************************
3229 * WIN_ListChildren
3231 * Build an array of the children of a given window. The array must be
3232 * freed with HeapFree. Returns NULL when no windows are found.
3234 HWND *WIN_ListChildren( HWND hwnd )
3236 if (!hwnd)
3238 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3239 return NULL;
3241 return list_window_children( 0, hwnd, NULL, 0 );
3245 /*******************************************************************
3246 * EnumWindows (USER32.@)
3248 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3250 HWND *list;
3251 BOOL ret = TRUE;
3252 int i;
3254 USER_CheckNotLock();
3256 /* We have to build a list of all windows first, to avoid */
3257 /* unpleasant side-effects, for instance if the callback */
3258 /* function changes the Z-order of the windows. */
3260 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3262 /* Now call the callback function for every window */
3264 for (i = 0; list[i]; i++)
3266 /* Make sure that the window still exists */
3267 if (!IsWindow( list[i] )) continue;
3268 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3270 HeapFree( GetProcessHeap(), 0, list );
3271 return ret;
3275 /**********************************************************************
3276 * EnumThreadWindows (USER32.@)
3278 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3280 HWND *list;
3281 int i;
3282 BOOL ret = TRUE;
3284 USER_CheckNotLock();
3286 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3288 /* Now call the callback function for every window */
3290 for (i = 0; list[i]; i++)
3291 if (!(ret = func( list[i], lParam ))) break;
3292 HeapFree( GetProcessHeap(), 0, list );
3293 return ret;
3297 /***********************************************************************
3298 * EnumDesktopWindows (USER32.@)
3300 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3302 HWND *list;
3303 int i;
3305 USER_CheckNotLock();
3307 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3309 for (i = 0; list[i]; i++)
3310 if (!func( list[i], lparam )) break;
3311 HeapFree( GetProcessHeap(), 0, list );
3312 return TRUE;
3316 /**********************************************************************
3317 * WIN_EnumChildWindows
3319 * Helper function for EnumChildWindows().
3321 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3323 HWND *childList;
3324 BOOL ret = FALSE;
3326 for ( ; *list; list++)
3328 /* Make sure that the window still exists */
3329 if (!IsWindow( *list )) continue;
3330 /* Build children list first */
3331 childList = WIN_ListChildren( *list );
3333 ret = func( *list, lParam );
3335 if (childList)
3337 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3338 HeapFree( GetProcessHeap(), 0, childList );
3340 if (!ret) return FALSE;
3342 return TRUE;
3346 /**********************************************************************
3347 * EnumChildWindows (USER32.@)
3349 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3351 HWND *list;
3352 BOOL ret;
3354 USER_CheckNotLock();
3356 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3357 ret = WIN_EnumChildWindows( list, func, lParam );
3358 HeapFree( GetProcessHeap(), 0, list );
3359 return ret;
3363 /*******************************************************************
3364 * AnyPopup (USER32.@)
3366 BOOL WINAPI AnyPopup(void)
3368 int i;
3369 BOOL retvalue;
3370 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3372 if (!list) return FALSE;
3373 for (i = 0; list[i]; i++)
3375 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3377 retvalue = (list[i] != 0);
3378 HeapFree( GetProcessHeap(), 0, list );
3379 return retvalue;
3383 /*******************************************************************
3384 * FlashWindow (USER32.@)
3386 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3388 WND *wndPtr;
3390 TRACE("%p\n", hWnd);
3392 if (IsIconic( hWnd ))
3394 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3396 wndPtr = WIN_GetPtr(hWnd);
3397 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3398 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3400 wndPtr->flags |= WIN_NCACTIVATED;
3402 else
3404 wndPtr->flags &= ~WIN_NCACTIVATED;
3406 WIN_ReleasePtr( wndPtr );
3407 return TRUE;
3409 else
3411 WPARAM wparam;
3413 wndPtr = WIN_GetPtr(hWnd);
3414 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3415 hWnd = wndPtr->obj.handle; /* make it a full handle */
3417 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3418 else wparam = (hWnd == GetForegroundWindow());
3420 WIN_ReleasePtr( wndPtr );
3421 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3422 return wparam;
3426 /*******************************************************************
3427 * FlashWindowEx (USER32.@)
3429 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3431 FIXME("%p\n", pfwi);
3432 return TRUE;
3435 /*******************************************************************
3436 * GetWindowContextHelpId (USER32.@)
3438 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3440 DWORD retval;
3441 WND *wnd = WIN_GetPtr( hwnd );
3442 if (!wnd || wnd == WND_DESKTOP) return 0;
3443 if (wnd == WND_OTHER_PROCESS)
3445 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3446 return 0;
3448 retval = wnd->helpContext;
3449 WIN_ReleasePtr( wnd );
3450 return retval;
3454 /*******************************************************************
3455 * SetWindowContextHelpId (USER32.@)
3457 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3459 WND *wnd = WIN_GetPtr( hwnd );
3460 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3461 if (wnd == WND_OTHER_PROCESS)
3463 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3464 return 0;
3466 wnd->helpContext = id;
3467 WIN_ReleasePtr( wnd );
3468 return TRUE;
3472 /*******************************************************************
3473 * DragDetect (USER32.@)
3475 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3477 MSG msg;
3478 RECT rect;
3479 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3480 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3482 rect.left = pt.x - wDragWidth;
3483 rect.right = pt.x + wDragWidth;
3485 rect.top = pt.y - wDragHeight;
3486 rect.bottom = pt.y + wDragHeight;
3488 SetCapture(hWnd);
3490 while(1)
3492 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3494 if( msg.message == WM_LBUTTONUP )
3496 ReleaseCapture();
3497 return 0;
3499 if( msg.message == WM_MOUSEMOVE )
3501 POINT tmp;
3502 tmp.x = (short)LOWORD(msg.lParam);
3503 tmp.y = (short)HIWORD(msg.lParam);
3504 if( !PtInRect( &rect, tmp ))
3506 ReleaseCapture();
3507 return 1;
3511 WaitMessage();
3513 return 0;
3516 /******************************************************************************
3517 * GetWindowModuleFileNameA (USER32.@)
3519 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3521 WND *win;
3522 HINSTANCE hinst;
3524 TRACE( "%p, %p, %u\n", hwnd, module, size );
3526 win = WIN_GetPtr( hwnd );
3527 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3529 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3530 return 0;
3532 hinst = win->hInstance;
3533 WIN_ReleasePtr( win );
3535 return GetModuleFileNameA( hinst, module, size );
3538 /******************************************************************************
3539 * GetWindowModuleFileNameW (USER32.@)
3541 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3543 WND *win;
3544 HINSTANCE hinst;
3546 TRACE( "%p, %p, %u\n", hwnd, module, size );
3548 win = WIN_GetPtr( hwnd );
3549 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3551 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3552 return 0;
3554 hinst = win->hInstance;
3555 WIN_ReleasePtr( win );
3557 return GetModuleFileNameW( hinst, module, size );
3560 /******************************************************************************
3561 * GetWindowInfo (USER32.@)
3563 * Note: tests show that Windows doesn't check cbSize of the structure.
3565 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3567 if (!pwi) return FALSE;
3568 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3570 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3571 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3572 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3574 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3575 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3577 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3578 pwi->wCreatorVersion = 0x0400;
3580 return TRUE;
3583 /******************************************************************************
3584 * SwitchDesktop (USER32.@)
3586 * NOTES: Sets the current input or interactive desktop.
3588 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3590 FIXME("(hwnd %p) stub!\n", hDesktop);
3591 return TRUE;
3594 /*****************************************************************************
3595 * SetLayeredWindowAttributes (USER32.@)
3597 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3599 BOOL ret;
3601 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3603 SERVER_START_REQ( set_window_layered_info )
3605 req->handle = wine_server_user_handle( hwnd );
3606 req->color_key = key;
3607 req->alpha = alpha;
3608 req->flags = flags;
3609 ret = !wine_server_call_err( req );
3611 SERVER_END_REQ;
3613 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3615 return ret;
3619 /*****************************************************************************
3620 * GetLayeredWindowAttributes (USER32.@)
3622 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3624 BOOL ret;
3626 SERVER_START_REQ( get_window_layered_info )
3628 req->handle = wine_server_user_handle( hwnd );
3629 if ((ret = !wine_server_call_err( req )))
3631 if (key) *key = reply->color_key;
3632 if (alpha) *alpha = reply->alpha;
3633 if (flags) *flags = reply->flags;
3636 SERVER_END_REQ;
3638 return ret;
3642 /*****************************************************************************
3643 * UpdateLayeredWindowIndirect (USER32.@)
3645 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3647 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3648 RECT window_rect, client_rect;
3649 SIZE offset;
3650 BYTE alpha = 0xff;
3652 if (!info ||
3653 info->cbSize != sizeof(*info) ||
3654 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3655 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3656 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3658 SetLastError( ERROR_INVALID_PARAMETER );
3659 return FALSE;
3662 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3664 if (info->pptDst)
3666 offset.cx = info->pptDst->x - window_rect.left;
3667 offset.cy = info->pptDst->y - window_rect.top;
3668 OffsetRect( &client_rect, offset.cx, offset.cy );
3669 OffsetRect( &window_rect, offset.cx, offset.cy );
3670 flags &= ~SWP_NOMOVE;
3672 if (info->psize)
3674 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3675 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3676 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3678 SetLastError( ERROR_INVALID_PARAMETER );
3679 return FALSE;
3681 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3683 SetLastError( ERROR_INCORRECT_SIZE );
3684 return FALSE;
3686 client_rect.right += offset.cx;
3687 client_rect.bottom += offset.cy;
3688 window_rect.right += offset.cx;
3689 window_rect.bottom += offset.cy;
3690 flags &= ~SWP_NOSIZE;
3693 TRACE( "window %p win %s client %s\n", hwnd,
3694 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3695 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3697 if (info->hdcSrc)
3699 HDC hdc = GetWindowDC( hwnd );
3701 if (hdc)
3703 int x = 0, y = 0;
3704 RECT rect;
3706 GetWindowRect( hwnd, &rect );
3707 OffsetRect( &rect, -rect.left, -rect.top);
3708 if (info->pptSrc)
3710 x = info->pptSrc->x;
3711 y = info->pptSrc->y;
3714 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3716 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3717 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3718 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3720 ReleaseDC( hwnd, hdc );
3724 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3725 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3726 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3727 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3728 return TRUE;
3732 /*****************************************************************************
3733 * UpdateLayeredWindow (USER32.@)
3735 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3736 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3737 DWORD flags)
3739 UPDATELAYEREDWINDOWINFO info;
3741 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3743 SetLastError( ERROR_INVALID_PARAMETER );
3744 return FALSE;
3746 info.cbSize = sizeof(info);
3747 info.hdcDst = hdcDst;
3748 info.pptDst = pptDst;
3749 info.psize = psize;
3750 info.hdcSrc = hdcSrc;
3751 info.pptSrc = pptSrc;
3752 info.crKey = crKey;
3753 info.pblend = pblend;
3754 info.dwFlags = flags;
3755 info.prcDirty = NULL;
3756 return UpdateLayeredWindowIndirect( hwnd, &info );
3760 /******************************************************************************
3761 * GetProcessDefaultLayout [USER32.@]
3763 * Gets the default layout for parentless windows.
3765 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3767 if (!layout)
3769 SetLastError( ERROR_NOACCESS );
3770 return FALSE;
3772 if (process_layout == ~0u)
3774 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3775 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3776 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3777 '\\','%','0','4','x','%','0','4','x',
3778 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3779 WCHAR *str, buffer[MAX_PATH];
3780 DWORD i, len, version_layout = 0;
3781 DWORD user_lang = GetUserDefaultLangID();
3782 DWORD *languages;
3783 void *data = NULL;
3785 GetModuleFileNameW( 0, buffer, MAX_PATH );
3786 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3787 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3788 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3789 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3791 len /= sizeof(DWORD);
3792 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3793 if (i == len) /* try neutral language */
3794 for (i = 0; i < len; i++)
3795 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3796 if (i == len) i = 0; /* default to the first one */
3798 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3799 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3800 TRACE( "found description %s\n", debugstr_w( str ));
3801 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3803 done:
3804 HeapFree( GetProcessHeap(), 0, data );
3805 process_layout = version_layout;
3807 *layout = process_layout;
3808 return TRUE;
3812 /******************************************************************************
3813 * SetProcessDefaultLayout [USER32.@]
3815 * Sets the default layout for parentless windows.
3817 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3819 process_layout = layout;
3820 return TRUE;
3824 /* 64bit versions */
3826 #ifdef GetWindowLongPtrW
3827 #undef GetWindowLongPtrW
3828 #endif
3830 #ifdef GetWindowLongPtrA
3831 #undef GetWindowLongPtrA
3832 #endif
3834 #ifdef SetWindowLongPtrW
3835 #undef SetWindowLongPtrW
3836 #endif
3838 #ifdef SetWindowLongPtrA
3839 #undef SetWindowLongPtrA
3840 #endif
3842 /*****************************************************************************
3843 * GetWindowLongPtrW (USER32.@)
3845 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3847 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3850 /*****************************************************************************
3851 * GetWindowLongPtrA (USER32.@)
3853 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3855 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3858 /*****************************************************************************
3859 * SetWindowLongPtrW (USER32.@)
3861 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3863 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3866 /*****************************************************************************
3867 * SetWindowLongPtrA (USER32.@)
3869 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3871 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );