user32: Don't redraw anything when WS_VISIBLE is toggled manually.
[wine.git] / dlls / user32 / win.c
blob0f487f7c34a4ce68567eec70a300c79009511bc6
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_NOREDRAW | 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)) ||
2476 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2478 needs_show = !(wndPtr->flags & WIN_HIDDEN) && (wndPtr->dwStyle & WS_VISIBLE);
2479 invalidate_dce( wndPtr, NULL );
2481 WIN_ReleasePtr( wndPtr );
2483 if (!ok) return 0;
2485 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2487 style.styleOld = retval;
2488 style.styleNew = newval;
2489 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2490 if (needs_show)
2492 RECT window_rect, client_rect;
2493 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
2494 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
2495 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_SHOWWINDOW,
2496 &window_rect, &client_rect, NULL );
2498 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2501 return retval;
2505 /**********************************************************************
2506 * GetWindowWord (USER32.@)
2508 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2510 switch(offset)
2512 case GWLP_ID:
2513 case GWLP_HINSTANCE:
2514 case GWLP_HWNDPARENT:
2515 break;
2516 default:
2517 if (offset < 0)
2519 WARN("Invalid offset %d\n", offset );
2520 SetLastError( ERROR_INVALID_INDEX );
2521 return 0;
2523 break;
2525 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2529 /**********************************************************************
2530 * GetWindowLongA (USER32.@)
2532 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2534 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2538 /**********************************************************************
2539 * GetWindowLongW (USER32.@)
2541 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2543 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2547 /**********************************************************************
2548 * SetWindowWord (USER32.@)
2550 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2552 switch(offset)
2554 case GWLP_ID:
2555 case GWLP_HINSTANCE:
2556 case GWLP_HWNDPARENT:
2557 break;
2558 default:
2559 if (offset < 0)
2561 WARN("Invalid offset %d\n", offset );
2562 SetLastError( ERROR_INVALID_INDEX );
2563 return 0;
2565 break;
2567 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2571 /**********************************************************************
2572 * SetWindowLongA (USER32.@)
2574 * See SetWindowLongW.
2576 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2578 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2582 /**********************************************************************
2583 * SetWindowLongW (USER32.@) Set window attribute
2585 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2586 * value in a window's extra memory.
2588 * The _hwnd_ parameter specifies the window. is the handle to a
2589 * window that has extra memory. The _newval_ parameter contains the
2590 * new attribute or extra memory value. If positive, the _offset_
2591 * parameter is the byte-addressed location in the window's extra
2592 * memory to set. If negative, _offset_ specifies the window
2593 * attribute to set, and should be one of the following values:
2595 * GWL_EXSTYLE The window's extended window style
2597 * GWL_STYLE The window's window style.
2599 * GWLP_WNDPROC Pointer to the window's window procedure.
2601 * GWLP_HINSTANCE The window's pplication instance handle.
2603 * GWLP_ID The window's identifier.
2605 * GWLP_USERDATA The window's user-specified data.
2607 * If the window is a dialog box, the _offset_ parameter can be one of
2608 * the following values:
2610 * DWLP_DLGPROC The address of the window's dialog box procedure.
2612 * DWLP_MSGRESULT The return value of a message
2613 * that the dialog box procedure processed.
2615 * DWLP_USER Application specific information.
2617 * RETURNS
2619 * If successful, returns the previous value located at _offset_. Otherwise,
2620 * returns 0.
2622 * NOTES
2624 * Extra memory for a window class is specified by a nonzero cbWndExtra
2625 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2626 * time of class creation.
2628 * Using GWL_WNDPROC to set a new window procedure effectively creates
2629 * a window subclass. Use CallWindowProc() in the new windows procedure
2630 * to pass messages to the superclass's window procedure.
2632 * The user data is reserved for use by the application which created
2633 * the window.
2635 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2636 * instead, call the EnableWindow() function to change the window's
2637 * disabled state.
2639 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2640 * SetParent() instead.
2642 * Win95:
2643 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2644 * it sends WM_STYLECHANGING before changing the settings
2645 * and WM_STYLECHANGED afterwards.
2646 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2648 LONG WINAPI SetWindowLongW(
2649 HWND hwnd, /* [in] window to alter */
2650 INT offset, /* [in] offset, in bytes, of location to alter */
2651 LONG newval /* [in] new value of location */
2653 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2657 /*******************************************************************
2658 * GetWindowTextA (USER32.@)
2660 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2662 WCHAR *buffer;
2664 if (!lpString) return 0;
2666 if (WIN_IsCurrentProcess( hwnd ))
2667 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2669 /* when window belongs to other process, don't send a message */
2670 if (nMaxCount <= 0) return 0;
2671 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2672 get_server_window_text( hwnd, buffer, nMaxCount );
2673 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2674 lpString[nMaxCount-1] = 0;
2675 HeapFree( GetProcessHeap(), 0, buffer );
2676 return strlen(lpString);
2680 /*******************************************************************
2681 * InternalGetWindowText (USER32.@)
2683 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2685 WND *win;
2687 if (nMaxCount <= 0) return 0;
2688 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2689 if (win == WND_DESKTOP) lpString[0] = 0;
2690 else if (win != WND_OTHER_PROCESS)
2692 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2693 else lpString[0] = 0;
2694 WIN_ReleasePtr( win );
2696 else
2698 get_server_window_text( hwnd, lpString, nMaxCount );
2700 return strlenW(lpString);
2704 /*******************************************************************
2705 * GetWindowTextW (USER32.@)
2707 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2709 if (!lpString) return 0;
2711 if (WIN_IsCurrentProcess( hwnd ))
2712 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2714 /* when window belongs to other process, don't send a message */
2715 if (nMaxCount <= 0) return 0;
2716 get_server_window_text( hwnd, lpString, nMaxCount );
2717 return strlenW(lpString);
2721 /*******************************************************************
2722 * SetWindowTextA (USER32.@)
2723 * SetWindowText (USER32.@)
2725 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2727 if (is_broadcast(hwnd))
2729 SetLastError( ERROR_INVALID_PARAMETER );
2730 return FALSE;
2732 if (!WIN_IsCurrentProcess( hwnd ))
2733 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2734 debugstr_a(lpString), hwnd );
2735 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2739 /*******************************************************************
2740 * SetWindowTextW (USER32.@)
2742 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2744 if (is_broadcast(hwnd))
2746 SetLastError( ERROR_INVALID_PARAMETER );
2747 return FALSE;
2749 if (!WIN_IsCurrentProcess( hwnd ))
2750 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2751 debugstr_w(lpString), hwnd );
2752 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2756 /*******************************************************************
2757 * GetWindowTextLengthA (USER32.@)
2759 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2761 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2764 /*******************************************************************
2765 * GetWindowTextLengthW (USER32.@)
2767 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2769 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2773 /*******************************************************************
2774 * IsWindow (USER32.@)
2776 BOOL WINAPI IsWindow( HWND hwnd )
2778 WND *ptr;
2779 BOOL ret;
2781 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2782 if (ptr == WND_DESKTOP) return TRUE;
2784 if (ptr != WND_OTHER_PROCESS)
2786 WIN_ReleasePtr( ptr );
2787 return TRUE;
2790 /* check other processes */
2791 SERVER_START_REQ( get_window_info )
2793 req->handle = wine_server_user_handle( hwnd );
2794 ret = !wine_server_call_err( req );
2796 SERVER_END_REQ;
2797 return ret;
2801 /***********************************************************************
2802 * GetWindowThreadProcessId (USER32.@)
2804 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2806 WND *ptr;
2807 DWORD tid = 0;
2809 if (!(ptr = WIN_GetPtr( hwnd )))
2811 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2812 return 0;
2815 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2817 /* got a valid window */
2818 tid = ptr->tid;
2819 if (process) *process = GetCurrentProcessId();
2820 WIN_ReleasePtr( ptr );
2821 return tid;
2824 /* check other processes */
2825 SERVER_START_REQ( get_window_info )
2827 req->handle = wine_server_user_handle( hwnd );
2828 if (!wine_server_call_err( req ))
2830 tid = (DWORD)reply->tid;
2831 if (process) *process = (DWORD)reply->pid;
2834 SERVER_END_REQ;
2835 return tid;
2839 /*****************************************************************
2840 * GetParent (USER32.@)
2842 HWND WINAPI GetParent( HWND hwnd )
2844 WND *wndPtr;
2845 HWND retvalue = 0;
2847 if (!(wndPtr = WIN_GetPtr( hwnd )))
2849 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2850 return 0;
2852 if (wndPtr == WND_DESKTOP) return 0;
2853 if (wndPtr == WND_OTHER_PROCESS)
2855 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2856 if (style & (WS_POPUP | WS_CHILD))
2858 SERVER_START_REQ( get_window_tree )
2860 req->handle = wine_server_user_handle( hwnd );
2861 if (!wine_server_call_err( req ))
2863 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2864 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2867 SERVER_END_REQ;
2870 else
2872 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2873 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2874 WIN_ReleasePtr( wndPtr );
2876 return retvalue;
2880 /*****************************************************************
2881 * GetAncestor (USER32.@)
2883 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2885 WND *win;
2886 HWND *list, ret = 0;
2888 switch(type)
2890 case GA_PARENT:
2891 if (!(win = WIN_GetPtr( hwnd )))
2893 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2894 return 0;
2896 if (win == WND_DESKTOP) return 0;
2897 if (win != WND_OTHER_PROCESS)
2899 ret = win->parent;
2900 WIN_ReleasePtr( win );
2902 else /* need to query the server */
2904 SERVER_START_REQ( get_window_tree )
2906 req->handle = wine_server_user_handle( hwnd );
2907 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2909 SERVER_END_REQ;
2911 break;
2913 case GA_ROOT:
2914 if (!(list = list_window_parents( hwnd ))) return 0;
2916 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2917 else
2919 int count = 2;
2920 while (list[count]) count++;
2921 ret = list[count - 2]; /* get the one before the desktop */
2923 HeapFree( GetProcessHeap(), 0, list );
2924 break;
2926 case GA_ROOTOWNER:
2927 if (is_desktop_window( hwnd )) return 0;
2928 ret = WIN_GetFullHandle( hwnd );
2929 for (;;)
2931 HWND parent = GetParent( ret );
2932 if (!parent) break;
2933 ret = parent;
2935 break;
2937 return ret;
2941 /*****************************************************************
2942 * SetParent (USER32.@)
2944 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2946 HWND full_handle;
2947 HWND old_parent = 0;
2948 BOOL was_visible;
2949 WND *wndPtr;
2950 POINT pt;
2951 BOOL ret;
2953 if (is_broadcast(hwnd) || is_broadcast(parent))
2955 SetLastError(ERROR_INVALID_PARAMETER);
2956 return 0;
2959 if (!parent) parent = GetDesktopWindow();
2960 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2961 else parent = WIN_GetFullHandle( parent );
2963 if (!IsWindow( parent ))
2965 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2966 return 0;
2969 /* Some applications try to set a child as a parent */
2970 if (IsChild(hwnd, parent))
2972 SetLastError( ERROR_INVALID_PARAMETER );
2973 return 0;
2976 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2977 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2979 if (full_handle == parent)
2981 SetLastError( ERROR_INVALID_PARAMETER );
2982 return 0;
2985 /* Windows hides the window first, then shows it again
2986 * including the WM_SHOWWINDOW messages and all */
2987 was_visible = ShowWindow( hwnd, SW_HIDE );
2989 wndPtr = WIN_GetPtr( hwnd );
2990 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2992 pt.x = wndPtr->rectWindow.left;
2993 pt.y = wndPtr->rectWindow.top;
2995 SERVER_START_REQ( set_parent )
2997 req->handle = wine_server_user_handle( hwnd );
2998 req->parent = wine_server_user_handle( parent );
2999 if ((ret = !wine_server_call( req )))
3001 old_parent = wine_server_ptr_handle( reply->old_parent );
3002 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3006 SERVER_END_REQ;
3007 WIN_ReleasePtr( wndPtr );
3008 if (!ret) return 0;
3010 USER_Driver->pSetParent( full_handle, parent, old_parent );
3012 /* SetParent additionally needs to make hwnd the topmost window
3013 in the x-order and send the expected WM_WINDOWPOSCHANGING and
3014 WM_WINDOWPOSCHANGED notification messages.
3016 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3018 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3020 return old_parent;
3024 /*******************************************************************
3025 * IsChild (USER32.@)
3027 BOOL WINAPI IsChild( HWND parent, HWND child )
3029 HWND *list = list_window_parents( child );
3030 int i;
3031 BOOL ret;
3033 if (!list) return FALSE;
3034 parent = WIN_GetFullHandle( parent );
3035 for (i = 0; list[i]; i++) if (list[i] == parent) break;
3036 ret = list[i] && list[i+1];
3037 HeapFree( GetProcessHeap(), 0, list );
3038 return ret;
3042 /***********************************************************************
3043 * IsWindowVisible (USER32.@)
3045 BOOL WINAPI IsWindowVisible( HWND hwnd )
3047 HWND *list;
3048 BOOL retval = TRUE;
3049 int i;
3051 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3052 if (!(list = list_window_parents( hwnd ))) return TRUE;
3053 if (list[0])
3055 for (i = 0; list[i+1]; i++)
3056 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3057 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3059 HeapFree( GetProcessHeap(), 0, list );
3060 return retval;
3064 /***********************************************************************
3065 * WIN_IsWindowDrawable
3067 * hwnd is drawable when it is visible, all parents are not
3068 * minimized, and it is itself not minimized unless we are
3069 * trying to draw its default class icon.
3071 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3073 HWND *list;
3074 BOOL retval = TRUE;
3075 int i;
3076 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3078 if (!(style & WS_VISIBLE)) return FALSE;
3079 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3081 if (!(list = list_window_parents( hwnd ))) return TRUE;
3082 if (list[0])
3084 for (i = 0; list[i+1]; i++)
3085 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3086 break;
3087 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3089 HeapFree( GetProcessHeap(), 0, list );
3090 return retval;
3094 /*******************************************************************
3095 * GetTopWindow (USER32.@)
3097 HWND WINAPI GetTopWindow( HWND hwnd )
3099 if (!hwnd) hwnd = GetDesktopWindow();
3100 return GetWindow( hwnd, GW_CHILD );
3104 /*******************************************************************
3105 * GetWindow (USER32.@)
3107 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3109 HWND retval = 0;
3111 if (rel == GW_OWNER) /* this one may be available locally */
3113 WND *wndPtr = WIN_GetPtr( hwnd );
3114 if (!wndPtr)
3116 SetLastError( ERROR_INVALID_HANDLE );
3117 return 0;
3119 if (wndPtr == WND_DESKTOP) return 0;
3120 if (wndPtr != WND_OTHER_PROCESS)
3122 retval = wndPtr->owner;
3123 WIN_ReleasePtr( wndPtr );
3124 return retval;
3126 /* else fall through to server call */
3129 SERVER_START_REQ( get_window_tree )
3131 req->handle = wine_server_user_handle( hwnd );
3132 if (!wine_server_call_err( req ))
3134 switch(rel)
3136 case GW_HWNDFIRST:
3137 retval = wine_server_ptr_handle( reply->first_sibling );
3138 break;
3139 case GW_HWNDLAST:
3140 retval = wine_server_ptr_handle( reply->last_sibling );
3141 break;
3142 case GW_HWNDNEXT:
3143 retval = wine_server_ptr_handle( reply->next_sibling );
3144 break;
3145 case GW_HWNDPREV:
3146 retval = wine_server_ptr_handle( reply->prev_sibling );
3147 break;
3148 case GW_OWNER:
3149 retval = wine_server_ptr_handle( reply->owner );
3150 break;
3151 case GW_CHILD:
3152 retval = wine_server_ptr_handle( reply->first_child );
3153 break;
3157 SERVER_END_REQ;
3158 return retval;
3162 /*******************************************************************
3163 * ShowOwnedPopups (USER32.@)
3165 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3167 int count = 0;
3168 WND *pWnd;
3169 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3171 if (!win_array) return TRUE;
3173 while (win_array[count]) count++;
3174 while (--count >= 0)
3176 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3177 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3178 if (pWnd == WND_OTHER_PROCESS) continue;
3179 if (fShow)
3181 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3183 WIN_ReleasePtr( pWnd );
3184 /* In Windows, ShowOwnedPopups(TRUE) generates
3185 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3186 * regardless of the state of the owner
3188 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3189 continue;
3192 else
3194 if (pWnd->dwStyle & WS_VISIBLE)
3196 WIN_ReleasePtr( pWnd );
3197 /* In Windows, ShowOwnedPopups(FALSE) generates
3198 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3199 * regardless of the state of the owner
3201 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3202 continue;
3205 WIN_ReleasePtr( pWnd );
3207 HeapFree( GetProcessHeap(), 0, win_array );
3208 return TRUE;
3212 /*******************************************************************
3213 * GetLastActivePopup (USER32.@)
3215 HWND WINAPI GetLastActivePopup( HWND hwnd )
3217 HWND retval = hwnd;
3219 SERVER_START_REQ( get_window_info )
3221 req->handle = wine_server_user_handle( hwnd );
3222 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3224 SERVER_END_REQ;
3225 return retval;
3229 /*******************************************************************
3230 * WIN_ListChildren
3232 * Build an array of the children of a given window. The array must be
3233 * freed with HeapFree. Returns NULL when no windows are found.
3235 HWND *WIN_ListChildren( HWND hwnd )
3237 if (!hwnd)
3239 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3240 return NULL;
3242 return list_window_children( 0, hwnd, NULL, 0 );
3246 /*******************************************************************
3247 * EnumWindows (USER32.@)
3249 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3251 HWND *list;
3252 BOOL ret = TRUE;
3253 int i;
3255 USER_CheckNotLock();
3257 /* We have to build a list of all windows first, to avoid */
3258 /* unpleasant side-effects, for instance if the callback */
3259 /* function changes the Z-order of the windows. */
3261 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3263 /* Now call the callback function for every window */
3265 for (i = 0; list[i]; i++)
3267 /* Make sure that the window still exists */
3268 if (!IsWindow( list[i] )) continue;
3269 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3271 HeapFree( GetProcessHeap(), 0, list );
3272 return ret;
3276 /**********************************************************************
3277 * EnumThreadWindows (USER32.@)
3279 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3281 HWND *list;
3282 int i;
3283 BOOL ret = TRUE;
3285 USER_CheckNotLock();
3287 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3289 /* Now call the callback function for every window */
3291 for (i = 0; list[i]; i++)
3292 if (!(ret = func( list[i], lParam ))) break;
3293 HeapFree( GetProcessHeap(), 0, list );
3294 return ret;
3298 /***********************************************************************
3299 * EnumDesktopWindows (USER32.@)
3301 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3303 HWND *list;
3304 int i;
3306 USER_CheckNotLock();
3308 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3310 for (i = 0; list[i]; i++)
3311 if (!func( list[i], lparam )) break;
3312 HeapFree( GetProcessHeap(), 0, list );
3313 return TRUE;
3317 /**********************************************************************
3318 * WIN_EnumChildWindows
3320 * Helper function for EnumChildWindows().
3322 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3324 HWND *childList;
3325 BOOL ret = FALSE;
3327 for ( ; *list; list++)
3329 /* Make sure that the window still exists */
3330 if (!IsWindow( *list )) continue;
3331 /* Build children list first */
3332 childList = WIN_ListChildren( *list );
3334 ret = func( *list, lParam );
3336 if (childList)
3338 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3339 HeapFree( GetProcessHeap(), 0, childList );
3341 if (!ret) return FALSE;
3343 return TRUE;
3347 /**********************************************************************
3348 * EnumChildWindows (USER32.@)
3350 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3352 HWND *list;
3353 BOOL ret;
3355 USER_CheckNotLock();
3357 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3358 ret = WIN_EnumChildWindows( list, func, lParam );
3359 HeapFree( GetProcessHeap(), 0, list );
3360 return ret;
3364 /*******************************************************************
3365 * AnyPopup (USER32.@)
3367 BOOL WINAPI AnyPopup(void)
3369 int i;
3370 BOOL retvalue;
3371 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3373 if (!list) return FALSE;
3374 for (i = 0; list[i]; i++)
3376 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3378 retvalue = (list[i] != 0);
3379 HeapFree( GetProcessHeap(), 0, list );
3380 return retvalue;
3384 /*******************************************************************
3385 * FlashWindow (USER32.@)
3387 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3389 WND *wndPtr;
3391 TRACE("%p\n", hWnd);
3393 if (IsIconic( hWnd ))
3395 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3397 wndPtr = WIN_GetPtr(hWnd);
3398 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3399 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3401 wndPtr->flags |= WIN_NCACTIVATED;
3403 else
3405 wndPtr->flags &= ~WIN_NCACTIVATED;
3407 WIN_ReleasePtr( wndPtr );
3408 return TRUE;
3410 else
3412 WPARAM wparam;
3414 wndPtr = WIN_GetPtr(hWnd);
3415 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3416 hWnd = wndPtr->obj.handle; /* make it a full handle */
3418 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3419 else wparam = (hWnd == GetForegroundWindow());
3421 WIN_ReleasePtr( wndPtr );
3422 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3423 return wparam;
3427 /*******************************************************************
3428 * FlashWindowEx (USER32.@)
3430 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3432 FIXME("%p\n", pfwi);
3433 return TRUE;
3436 /*******************************************************************
3437 * GetWindowContextHelpId (USER32.@)
3439 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3441 DWORD retval;
3442 WND *wnd = WIN_GetPtr( hwnd );
3443 if (!wnd || wnd == WND_DESKTOP) return 0;
3444 if (wnd == WND_OTHER_PROCESS)
3446 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3447 return 0;
3449 retval = wnd->helpContext;
3450 WIN_ReleasePtr( wnd );
3451 return retval;
3455 /*******************************************************************
3456 * SetWindowContextHelpId (USER32.@)
3458 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3460 WND *wnd = WIN_GetPtr( hwnd );
3461 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3462 if (wnd == WND_OTHER_PROCESS)
3464 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3465 return 0;
3467 wnd->helpContext = id;
3468 WIN_ReleasePtr( wnd );
3469 return TRUE;
3473 /*******************************************************************
3474 * DragDetect (USER32.@)
3476 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3478 MSG msg;
3479 RECT rect;
3480 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3481 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3483 rect.left = pt.x - wDragWidth;
3484 rect.right = pt.x + wDragWidth;
3486 rect.top = pt.y - wDragHeight;
3487 rect.bottom = pt.y + wDragHeight;
3489 SetCapture(hWnd);
3491 while(1)
3493 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3495 if( msg.message == WM_LBUTTONUP )
3497 ReleaseCapture();
3498 return 0;
3500 if( msg.message == WM_MOUSEMOVE )
3502 POINT tmp;
3503 tmp.x = (short)LOWORD(msg.lParam);
3504 tmp.y = (short)HIWORD(msg.lParam);
3505 if( !PtInRect( &rect, tmp ))
3507 ReleaseCapture();
3508 return 1;
3512 WaitMessage();
3514 return 0;
3517 /******************************************************************************
3518 * GetWindowModuleFileNameA (USER32.@)
3520 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3522 WND *win;
3523 HINSTANCE hinst;
3525 TRACE( "%p, %p, %u\n", hwnd, module, size );
3527 win = WIN_GetPtr( hwnd );
3528 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3530 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3531 return 0;
3533 hinst = win->hInstance;
3534 WIN_ReleasePtr( win );
3536 return GetModuleFileNameA( hinst, module, size );
3539 /******************************************************************************
3540 * GetWindowModuleFileNameW (USER32.@)
3542 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3544 WND *win;
3545 HINSTANCE hinst;
3547 TRACE( "%p, %p, %u\n", hwnd, module, size );
3549 win = WIN_GetPtr( hwnd );
3550 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3552 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3553 return 0;
3555 hinst = win->hInstance;
3556 WIN_ReleasePtr( win );
3558 return GetModuleFileNameW( hinst, module, size );
3561 /******************************************************************************
3562 * GetWindowInfo (USER32.@)
3564 * Note: tests show that Windows doesn't check cbSize of the structure.
3566 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3568 if (!pwi) return FALSE;
3569 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3571 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3572 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3573 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3575 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3576 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3578 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3579 pwi->wCreatorVersion = 0x0400;
3581 return TRUE;
3584 /******************************************************************************
3585 * SwitchDesktop (USER32.@)
3587 * NOTES: Sets the current input or interactive desktop.
3589 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3591 FIXME("(hwnd %p) stub!\n", hDesktop);
3592 return TRUE;
3595 /*****************************************************************************
3596 * SetLayeredWindowAttributes (USER32.@)
3598 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3600 BOOL ret;
3602 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3604 SERVER_START_REQ( set_window_layered_info )
3606 req->handle = wine_server_user_handle( hwnd );
3607 req->color_key = key;
3608 req->alpha = alpha;
3609 req->flags = flags;
3610 ret = !wine_server_call_err( req );
3612 SERVER_END_REQ;
3614 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3616 return ret;
3620 /*****************************************************************************
3621 * GetLayeredWindowAttributes (USER32.@)
3623 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3625 BOOL ret;
3627 SERVER_START_REQ( get_window_layered_info )
3629 req->handle = wine_server_user_handle( hwnd );
3630 if ((ret = !wine_server_call_err( req )))
3632 if (key) *key = reply->color_key;
3633 if (alpha) *alpha = reply->alpha;
3634 if (flags) *flags = reply->flags;
3637 SERVER_END_REQ;
3639 return ret;
3643 /*****************************************************************************
3644 * UpdateLayeredWindowIndirect (USER32.@)
3646 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3648 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3649 RECT window_rect, client_rect;
3650 SIZE offset;
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) );
3696 if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3698 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3699 return TRUE;
3703 /*****************************************************************************
3704 * UpdateLayeredWindow (USER32.@)
3706 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3707 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3708 DWORD flags)
3710 UPDATELAYEREDWINDOWINFO info;
3712 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3714 SetLastError( ERROR_INVALID_PARAMETER );
3715 return FALSE;
3717 info.cbSize = sizeof(info);
3718 info.hdcDst = hdcDst;
3719 info.pptDst = pptDst;
3720 info.psize = psize;
3721 info.hdcSrc = hdcSrc;
3722 info.pptSrc = pptSrc;
3723 info.crKey = crKey;
3724 info.pblend = pblend;
3725 info.dwFlags = flags;
3726 info.prcDirty = NULL;
3727 return UpdateLayeredWindowIndirect( hwnd, &info );
3731 /******************************************************************************
3732 * GetProcessDefaultLayout [USER32.@]
3734 * Gets the default layout for parentless windows.
3736 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3738 if (!layout)
3740 SetLastError( ERROR_NOACCESS );
3741 return FALSE;
3743 if (process_layout == ~0u)
3745 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3746 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3747 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3748 '\\','%','0','4','x','%','0','4','x',
3749 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3750 WCHAR *str, buffer[MAX_PATH];
3751 DWORD i, len, version_layout = 0;
3752 DWORD user_lang = GetUserDefaultLangID();
3753 DWORD *languages;
3754 void *data = NULL;
3756 GetModuleFileNameW( 0, buffer, MAX_PATH );
3757 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3758 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3759 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3760 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3762 len /= sizeof(DWORD);
3763 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3764 if (i == len) /* try neutral language */
3765 for (i = 0; i < len; i++)
3766 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3767 if (i == len) i = 0; /* default to the first one */
3769 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3770 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3771 TRACE( "found description %s\n", debugstr_w( str ));
3772 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3774 done:
3775 HeapFree( GetProcessHeap(), 0, data );
3776 process_layout = version_layout;
3778 *layout = process_layout;
3779 return TRUE;
3783 /******************************************************************************
3784 * SetProcessDefaultLayout [USER32.@]
3786 * Sets the default layout for parentless windows.
3788 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3790 process_layout = layout;
3791 return TRUE;
3795 /* 64bit versions */
3797 #ifdef GetWindowLongPtrW
3798 #undef GetWindowLongPtrW
3799 #endif
3801 #ifdef GetWindowLongPtrA
3802 #undef GetWindowLongPtrA
3803 #endif
3805 #ifdef SetWindowLongPtrW
3806 #undef SetWindowLongPtrW
3807 #endif
3809 #ifdef SetWindowLongPtrA
3810 #undef SetWindowLongPtrA
3811 #endif
3813 /*****************************************************************************
3814 * GetWindowLongPtrW (USER32.@)
3816 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3818 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3821 /*****************************************************************************
3822 * GetWindowLongPtrA (USER32.@)
3824 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3826 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3829 /*****************************************************************************
3830 * SetWindowLongPtrW (USER32.@)
3832 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3834 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3837 /*****************************************************************************
3838 * SetWindowLongPtrA (USER32.@)
3840 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3842 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );