user32: Add support for setting the window surface visible region.
[wine.git] / dlls / user32 / win.c
blob66eaf099d1874da30f8d983d16878430488a9967
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 * update_window_state
436 * Trigger an update of the window's driver state and surface.
438 static void update_window_state( HWND hwnd )
440 RECT window_rect, client_rect;
442 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
443 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
444 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW, &window_rect, &client_rect, NULL );
448 /*******************************************************************
449 * get_server_window_text
451 * Retrieve the window text from the server.
453 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
455 size_t len = 0;
457 SERVER_START_REQ( get_window_text )
459 req->handle = wine_server_user_handle( hwnd );
460 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
461 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
463 SERVER_END_REQ;
464 text[len / sizeof(WCHAR)] = 0;
468 /*******************************************************************
469 * get_hwnd_message_parent
471 * Return the parent for HWND_MESSAGE windows.
473 HWND get_hwnd_message_parent(void)
475 struct user_thread_info *thread_info = get_user_thread_info();
477 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
478 return thread_info->msg_window;
482 /*******************************************************************
483 * is_desktop_window
485 * Check if window is the desktop or the HWND_MESSAGE top parent.
487 BOOL is_desktop_window( HWND hwnd )
489 struct user_thread_info *thread_info = get_user_thread_info();
491 if (!hwnd) return FALSE;
492 if (hwnd == thread_info->top_window) return TRUE;
493 if (hwnd == thread_info->msg_window) return TRUE;
495 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
497 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
498 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
500 return FALSE;
504 /*******************************************************************
505 * Dummy window surface for windows that shouldn't get painted.
508 static void dummy_surface_lock( struct window_surface *window_surface )
510 /* nothing to do */
513 static void dummy_surface_unlock( struct window_surface *window_surface )
515 /* nothing to do */
518 static void *dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
520 static DWORD dummy_data;
522 info->bmiHeader.biSize = sizeof( info->bmiHeader );
523 info->bmiHeader.biWidth = dummy_surface.rect.right;
524 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
525 info->bmiHeader.biPlanes = 1;
526 info->bmiHeader.biBitCount = 32;
527 info->bmiHeader.biCompression = BI_RGB;
528 info->bmiHeader.biSizeImage = 0;
529 info->bmiHeader.biXPelsPerMeter = 0;
530 info->bmiHeader.biYPelsPerMeter = 0;
531 info->bmiHeader.biClrUsed = 0;
532 info->bmiHeader.biClrImportant = 0;
533 return &dummy_data;
536 static RECT *dummy_surface_get_bounds( struct window_surface *window_surface )
538 static RECT dummy_bounds;
539 return &dummy_bounds;
542 static void dummy_surface_set_region( struct window_surface *window_surface, HRGN region )
544 /* nothing to do */
547 static void dummy_surface_flush( struct window_surface *window_surface )
549 /* nothing to do */
552 static void dummy_surface_destroy( struct window_surface *window_surface )
554 /* nothing to do */
557 static const struct window_surface_funcs dummy_surface_funcs =
559 dummy_surface_lock,
560 dummy_surface_unlock,
561 dummy_surface_get_bitmap_info,
562 dummy_surface_get_bounds,
563 dummy_surface_set_region,
564 dummy_surface_flush,
565 dummy_surface_destroy
568 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
571 /*******************************************************************
572 * register_window_surface
574 * Register a window surface in the global list, possibly replacing another one.
576 void register_window_surface( struct window_surface *old, struct window_surface *new )
578 if (old == new) return;
579 EnterCriticalSection( &surfaces_section );
580 if (old && old != &dummy_surface) list_remove( &old->entry );
581 if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
582 LeaveCriticalSection( &surfaces_section );
586 /*******************************************************************
587 * flush_window_surfaces
589 * Flush pending output from all window surfaces.
591 void flush_window_surfaces( BOOL idle )
593 static DWORD last_idle;
594 DWORD now;
595 struct window_surface *surface;
597 EnterCriticalSection( &surfaces_section );
598 now = GetTickCount();
599 if (idle) last_idle = now;
600 /* if not idle, we only flush if there's evidence that the app never goes idle */
601 else if ((int)(now - last_idle) < 1000) goto done;
603 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
604 surface->funcs->flush( surface );
605 done:
606 LeaveCriticalSection( &surfaces_section );
610 /***********************************************************************
611 * WIN_GetPtr
613 * Return a pointer to the WND structure if local to the process,
614 * or WND_OTHER_PROCESS if handle may be valid in other process.
615 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
617 WND *WIN_GetPtr( HWND hwnd )
619 WND *ptr;
621 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
623 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
625 return ptr;
629 /***********************************************************************
630 * WIN_IsCurrentProcess
632 * Check whether a given window belongs to the current process (and return the full handle).
634 HWND WIN_IsCurrentProcess( HWND hwnd )
636 WND *ptr;
637 HWND ret;
639 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
640 ret = ptr->obj.handle;
641 WIN_ReleasePtr( ptr );
642 return ret;
646 /***********************************************************************
647 * WIN_IsCurrentThread
649 * Check whether a given window belongs to the current thread (and return the full handle).
651 HWND WIN_IsCurrentThread( HWND hwnd )
653 WND *ptr;
654 HWND ret = 0;
656 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
657 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
658 WIN_ReleasePtr( ptr );
659 return ret;
663 /***********************************************************************
664 * WIN_GetFullHandle
666 * Convert a possibly truncated window handle to a full 32-bit handle.
668 HWND WIN_GetFullHandle( HWND hwnd )
670 WND *ptr;
672 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
673 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
674 /* do sign extension for -2 and -3 */
675 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
677 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
679 if (ptr == WND_DESKTOP)
681 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
682 else return get_hwnd_message_parent();
685 if (ptr != WND_OTHER_PROCESS)
687 hwnd = ptr->obj.handle;
688 WIN_ReleasePtr( ptr );
690 else /* may belong to another process */
692 SERVER_START_REQ( get_window_info )
694 req->handle = wine_server_user_handle( hwnd );
695 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
697 SERVER_END_REQ;
699 return hwnd;
703 /***********************************************************************
704 * WIN_SetOwner
706 * Change the owner of a window.
708 HWND WIN_SetOwner( HWND hwnd, HWND owner )
710 WND *win = WIN_GetPtr( hwnd );
711 HWND ret = 0;
713 if (!win || win == WND_DESKTOP) return 0;
714 if (win == WND_OTHER_PROCESS)
716 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
717 return 0;
719 SERVER_START_REQ( set_window_owner )
721 req->handle = wine_server_user_handle( hwnd );
722 req->owner = wine_server_user_handle( owner );
723 if (!wine_server_call( req ))
725 win->owner = wine_server_ptr_handle( reply->full_owner );
726 ret = wine_server_ptr_handle( reply->prev_owner );
729 SERVER_END_REQ;
730 WIN_ReleasePtr( win );
731 return ret;
735 /***********************************************************************
736 * WIN_SetStyle
738 * Change the style of a window.
740 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
742 BOOL ok, made_visible = FALSE;
743 STYLESTRUCT style;
744 WND *win = WIN_GetPtr( hwnd );
746 if (!win || win == WND_DESKTOP) return 0;
747 if (win == WND_OTHER_PROCESS)
749 if (IsWindow(hwnd))
750 ERR( "cannot set style %x/%x on other process window %p\n",
751 set_bits, clear_bits, hwnd );
752 return 0;
754 style.styleOld = win->dwStyle;
755 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
756 if (style.styleNew == style.styleOld)
758 WIN_ReleasePtr( win );
759 return style.styleNew;
761 SERVER_START_REQ( set_window_info )
763 req->handle = wine_server_user_handle( hwnd );
764 req->flags = SET_WIN_STYLE;
765 req->style = style.styleNew;
766 req->extra_offset = -1;
767 if ((ok = !wine_server_call( req )))
769 style.styleOld = reply->old_style;
770 win->dwStyle = style.styleNew;
773 SERVER_END_REQ;
775 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
777 /* Some apps try to make their window visible through WM_SETREDRAW.
778 * Only do that if the window was never explicitly hidden,
779 * because Steam messes with WM_SETREDRAW after hiding its windows. */
780 made_visible = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
781 invalidate_dce( win, NULL );
783 WIN_ReleasePtr( win );
785 if (!ok) return 0;
787 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
788 if (made_visible) update_window_state( hwnd );
790 return style.styleOld;
794 /***********************************************************************
795 * WIN_GetRectangles
797 * Get the window and client rectangles.
799 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
801 WND *win = WIN_GetPtr( hwnd );
802 BOOL ret = TRUE;
804 if (!win)
806 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
807 return FALSE;
809 if (win == WND_DESKTOP)
811 RECT rect;
812 rect.left = rect.top = 0;
813 if (hwnd == get_hwnd_message_parent())
815 rect.right = 100;
816 rect.bottom = 100;
818 else
820 rect.right = GetSystemMetrics(SM_CXSCREEN);
821 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
823 if (rectWindow) *rectWindow = rect;
824 if (rectClient) *rectClient = rect;
825 return TRUE;
827 if (win != WND_OTHER_PROCESS)
829 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
831 switch (relative)
833 case COORDS_CLIENT:
834 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
835 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
836 if (win->dwExStyle & WS_EX_LAYOUTRTL)
837 mirror_rect( &win->rectClient, &window_rect );
838 break;
839 case COORDS_WINDOW:
840 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
841 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
842 if (win->dwExStyle & WS_EX_LAYOUTRTL)
843 mirror_rect( &win->rectWindow, &client_rect );
844 break;
845 case COORDS_PARENT:
846 if (win->parent)
848 WND *parent = WIN_GetPtr( win->parent );
849 if (parent == WND_DESKTOP) break;
850 if (!parent || parent == WND_OTHER_PROCESS)
852 WIN_ReleasePtr( win );
853 goto other_process;
855 if (parent->flags & WIN_CHILDREN_MOVED)
857 WIN_ReleasePtr( parent );
858 WIN_ReleasePtr( win );
859 goto other_process;
861 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
863 mirror_rect( &parent->rectClient, &window_rect );
864 mirror_rect( &parent->rectClient, &client_rect );
866 WIN_ReleasePtr( parent );
868 break;
869 case COORDS_SCREEN:
870 while (win->parent)
872 WND *parent = WIN_GetPtr( win->parent );
873 if (parent == WND_DESKTOP) break;
874 if (!parent || parent == WND_OTHER_PROCESS)
876 WIN_ReleasePtr( win );
877 goto other_process;
879 WIN_ReleasePtr( win );
880 if (parent->flags & WIN_CHILDREN_MOVED)
882 WIN_ReleasePtr( parent );
883 goto other_process;
885 win = parent;
886 if (win->parent)
888 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
889 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
892 break;
894 if (rectWindow) *rectWindow = window_rect;
895 if (rectClient) *rectClient = client_rect;
896 WIN_ReleasePtr( win );
897 return TRUE;
900 other_process:
901 SERVER_START_REQ( get_window_rectangles )
903 req->handle = wine_server_user_handle( hwnd );
904 req->relative = relative;
905 if ((ret = !wine_server_call_err( req )))
907 if (rectWindow)
909 rectWindow->left = reply->window.left;
910 rectWindow->top = reply->window.top;
911 rectWindow->right = reply->window.right;
912 rectWindow->bottom = reply->window.bottom;
914 if (rectClient)
916 rectClient->left = reply->client.left;
917 rectClient->top = reply->client.top;
918 rectClient->right = reply->client.right;
919 rectClient->bottom = reply->client.bottom;
923 SERVER_END_REQ;
924 return ret;
928 /***********************************************************************
929 * WIN_DestroyWindow
931 * Destroy storage associated to a window. "Internals" p.358
933 LRESULT WIN_DestroyWindow( HWND hwnd )
935 WND *wndPtr;
936 HWND *list;
937 HMENU menu = 0, sys_menu;
938 HWND icon_title;
939 struct window_surface *surface;
941 TRACE("%p\n", hwnd );
943 /* free child windows */
944 if ((list = WIN_ListChildren( hwnd )))
946 int i;
947 for (i = 0; list[i]; i++)
949 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
950 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
952 HeapFree( GetProcessHeap(), 0, list );
955 /* Unlink now so we won't bother with the children later on */
956 SERVER_START_REQ( set_parent )
958 req->handle = wine_server_user_handle( hwnd );
959 req->parent = 0;
960 wine_server_call( req );
962 SERVER_END_REQ;
965 * Send the WM_NCDESTROY to the window being destroyed.
967 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
969 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
971 /* free resources associated with the window */
973 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
974 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
975 menu = (HMENU)wndPtr->wIDmenu;
976 sys_menu = wndPtr->hSysMenu;
977 free_dce( wndPtr->dce, hwnd );
978 wndPtr->dce = NULL;
979 icon_title = wndPtr->icon_title;
980 HeapFree( GetProcessHeap(), 0, wndPtr->text );
981 wndPtr->text = NULL;
982 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
983 wndPtr->pScroll = NULL;
984 surface = wndPtr->surface;
985 wndPtr->surface = NULL;
986 WIN_ReleasePtr( wndPtr );
988 if (icon_title) DestroyWindow( icon_title );
989 if (menu) DestroyMenu( menu );
990 if (sys_menu) DestroyMenu( sys_menu );
991 if (surface)
993 register_window_surface( surface, NULL );
994 window_surface_release( surface );
997 USER_Driver->pDestroyWindow( hwnd );
999 free_window_handle( hwnd );
1000 return 0;
1004 /***********************************************************************
1005 * destroy_thread_window
1007 * Destroy a window upon exit of its thread.
1009 static void destroy_thread_window( HWND hwnd )
1011 WND *wndPtr;
1012 HWND *list;
1013 HMENU menu = 0, sys_menu = 0;
1014 struct window_surface *surface = NULL;
1015 WORD index;
1017 /* free child windows */
1019 if ((list = WIN_ListChildren( hwnd )))
1021 int i;
1022 for (i = 0; list[i]; i++)
1024 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
1025 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1027 HeapFree( GetProcessHeap(), 0, list );
1030 /* destroy the client-side storage */
1032 index = USER_HANDLE_TO_INDEX(hwnd);
1033 if (index >= NB_USER_HANDLES) return;
1034 USER_Lock();
1035 if ((wndPtr = user_handles[index]))
1037 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
1038 sys_menu = wndPtr->hSysMenu;
1039 free_dce( wndPtr->dce, hwnd );
1040 surface = wndPtr->surface;
1041 wndPtr->surface = NULL;
1042 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
1044 USER_Unlock();
1046 HeapFree( GetProcessHeap(), 0, wndPtr );
1047 if (menu) DestroyMenu( menu );
1048 if (sys_menu) DestroyMenu( sys_menu );
1049 if (surface)
1051 register_window_surface( surface, NULL );
1052 window_surface_release( surface );
1057 /***********************************************************************
1058 * destroy_thread_child_windows
1060 * Destroy child windows upon exit of its thread.
1062 static void destroy_thread_child_windows( HWND hwnd )
1064 HWND *list;
1065 int i;
1067 if (WIN_IsCurrentThread( hwnd ))
1069 destroy_thread_window( hwnd );
1071 else if ((list = WIN_ListChildren( hwnd )))
1073 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1074 HeapFree( GetProcessHeap(), 0, list );
1079 /***********************************************************************
1080 * WIN_DestroyThreadWindows
1082 * Destroy all children of 'wnd' owned by the current thread.
1084 void WIN_DestroyThreadWindows( HWND hwnd )
1086 HWND *list;
1087 int i;
1089 if (!(list = WIN_ListChildren( hwnd ))) return;
1091 /* reset owners of top-level windows */
1092 for (i = 0; list[i]; i++)
1094 if (!WIN_IsCurrentThread( list[i] ))
1096 HWND owner = GetWindow( list[i], GW_OWNER );
1097 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1101 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1102 HeapFree( GetProcessHeap(), 0, list );
1106 /***********************************************************************
1107 * WIN_FixCoordinates
1109 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1110 * returns default show mode in sw.
1112 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1114 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1115 POINT pos[2];
1117 if (cs->dwExStyle & WS_EX_MDICHILD)
1119 UINT id = 0;
1121 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1122 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1124 TRACE("MDI child id %04x\n", id);
1127 if (cs->style & (WS_CHILD | WS_POPUP))
1129 if (cs->dwExStyle & WS_EX_MDICHILD)
1131 if (IS_DEFAULT(cs->x))
1133 cs->x = pos[0].x;
1134 cs->y = pos[0].y;
1136 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1137 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1139 else
1141 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1142 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1145 else /* overlapped window */
1147 HMONITOR monitor;
1148 MONITORINFO mon_info;
1149 STARTUPINFOW info;
1151 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1153 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1154 mon_info.cbSize = sizeof(mon_info);
1155 GetMonitorInfoW( monitor, &mon_info );
1156 GetStartupInfoW( &info );
1158 if (IS_DEFAULT(cs->x))
1160 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1161 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1162 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1165 if (IS_DEFAULT(cs->cx))
1167 if (info.dwFlags & STARTF_USESIZE)
1169 cs->cx = info.dwXSize;
1170 cs->cy = info.dwYSize;
1172 else
1174 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1175 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1178 /* neither x nor cx are default. Check the y values .
1179 * In the trace we see Outlook and Outlook Express using
1180 * cy set to CW_USEDEFAULT when opening the address book.
1182 else if (IS_DEFAULT(cs->cy))
1184 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1185 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1188 #undef IS_DEFAULT
1191 /***********************************************************************
1192 * dump_window_styles
1194 static void dump_window_styles( DWORD style, DWORD exstyle )
1196 TRACE( "style:" );
1197 if(style & WS_POPUP) TRACE(" WS_POPUP");
1198 if(style & WS_CHILD) TRACE(" WS_CHILD");
1199 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1200 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1201 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1202 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1203 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1204 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1205 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1206 else
1208 if(style & WS_BORDER) TRACE(" WS_BORDER");
1209 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1211 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1212 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1213 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1214 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1215 if (style & WS_CHILD)
1217 if(style & WS_GROUP) TRACE(" WS_GROUP");
1218 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1220 else
1222 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1223 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1226 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1227 #define DUMPED_STYLES \
1228 ((DWORD)(WS_POPUP | \
1229 WS_CHILD | \
1230 WS_MINIMIZE | \
1231 WS_VISIBLE | \
1232 WS_DISABLED | \
1233 WS_CLIPSIBLINGS | \
1234 WS_CLIPCHILDREN | \
1235 WS_MAXIMIZE | \
1236 WS_BORDER | \
1237 WS_DLGFRAME | \
1238 WS_VSCROLL | \
1239 WS_HSCROLL | \
1240 WS_SYSMENU | \
1241 WS_THICKFRAME | \
1242 WS_GROUP | \
1243 WS_TABSTOP | \
1244 WS_MINIMIZEBOX | \
1245 WS_MAXIMIZEBOX))
1247 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1248 TRACE("\n");
1249 #undef DUMPED_STYLES
1251 TRACE( "exstyle:" );
1252 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1253 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1254 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1255 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1256 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1257 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1258 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1259 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1260 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1261 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1262 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1263 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1264 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1265 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1266 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1267 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1268 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1269 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1270 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1272 #define DUMPED_EX_STYLES \
1273 ((DWORD)(WS_EX_DLGMODALFRAME | \
1274 WS_EX_DRAGDETECT | \
1275 WS_EX_NOPARENTNOTIFY | \
1276 WS_EX_TOPMOST | \
1277 WS_EX_ACCEPTFILES | \
1278 WS_EX_TRANSPARENT | \
1279 WS_EX_MDICHILD | \
1280 WS_EX_TOOLWINDOW | \
1281 WS_EX_WINDOWEDGE | \
1282 WS_EX_CLIENTEDGE | \
1283 WS_EX_CONTEXTHELP | \
1284 WS_EX_RIGHT | \
1285 WS_EX_RTLREADING | \
1286 WS_EX_LEFTSCROLLBAR | \
1287 WS_EX_CONTROLPARENT | \
1288 WS_EX_STATICEDGE | \
1289 WS_EX_APPWINDOW | \
1290 WS_EX_LAYERED | \
1291 WS_EX_LAYOUTRTL))
1293 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1294 TRACE("\n");
1295 #undef DUMPED_EX_STYLES
1299 /***********************************************************************
1300 * WIN_CreateWindowEx
1302 * Implementation of CreateWindowEx().
1304 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1306 INT cx, cy, style, sw = SW_SHOW;
1307 LRESULT result;
1308 RECT rect;
1309 WND *wndPtr;
1310 HWND hwnd, parent, owner, top_child = 0;
1311 MDICREATESTRUCTW mdi_cs;
1312 CBT_CREATEWNDW cbtc;
1313 CREATESTRUCTW cbcs;
1315 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1316 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1317 debugstr_w(className),
1318 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1319 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1320 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1322 /* Fix the styles for MDI children */
1323 if (cs->dwExStyle & WS_EX_MDICHILD)
1325 UINT flags = 0;
1327 wndPtr = WIN_GetPtr(cs->hwndParent);
1328 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1330 flags = wndPtr->flags;
1331 WIN_ReleasePtr(wndPtr);
1334 if (!(flags & WIN_ISMDICLIENT))
1336 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1337 return 0;
1340 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1341 * MDICREATESTRUCT members have the originally passed values.
1343 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1344 * have the same layout.
1346 mdi_cs.szClass = cs->lpszClass;
1347 mdi_cs.szTitle = cs->lpszName;
1348 mdi_cs.hOwner = cs->hInstance;
1349 mdi_cs.x = cs->x;
1350 mdi_cs.y = cs->y;
1351 mdi_cs.cx = cs->cx;
1352 mdi_cs.cy = cs->cy;
1353 mdi_cs.style = cs->style;
1354 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1356 cs->lpCreateParams = &mdi_cs;
1358 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1360 if (cs->style & WS_POPUP)
1362 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1363 return 0;
1365 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1367 else
1369 cs->style &= ~WS_POPUP;
1370 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1371 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1374 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1376 if (top_child)
1378 /* Restore current maximized child */
1379 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1381 TRACE("Restoring current maximized child %p\n", top_child);
1382 if (cs->style & WS_MAXIMIZE)
1384 /* if the new window is maximized don't bother repainting */
1385 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1386 ShowWindow( top_child, SW_SHOWNORMAL );
1387 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1389 else ShowWindow( top_child, SW_SHOWNORMAL );
1394 /* Find the parent window */
1396 parent = cs->hwndParent;
1397 owner = 0;
1399 if (cs->hwndParent == HWND_MESSAGE)
1401 cs->hwndParent = parent = get_hwnd_message_parent();
1403 else if (cs->hwndParent)
1405 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1407 parent = GetDesktopWindow();
1408 owner = cs->hwndParent;
1410 else
1412 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1413 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1414 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1417 else
1419 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1421 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1423 WARN("No parent for child window\n" );
1424 SetLastError(ERROR_TLW_WITH_WSCHILD);
1425 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1427 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1428 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1429 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1431 DWORD layout;
1432 GetProcessDefaultLayout( &layout );
1433 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1434 parent = GetDesktopWindow();
1438 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1440 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1441 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1442 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1443 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1444 else
1445 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1447 /* Create the window structure */
1449 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1450 return 0;
1451 hwnd = wndPtr->obj.handle;
1453 /* Fill the window structure */
1455 wndPtr->tid = GetCurrentThreadId();
1456 wndPtr->hInstance = cs->hInstance;
1457 wndPtr->text = NULL;
1458 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1459 wndPtr->dwExStyle = cs->dwExStyle;
1460 wndPtr->wIDmenu = 0;
1461 wndPtr->helpContext = 0;
1462 wndPtr->pScroll = NULL;
1463 wndPtr->userdata = 0;
1464 wndPtr->hIcon = 0;
1465 wndPtr->hIconSmall = 0;
1466 wndPtr->hSysMenu = 0;
1468 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1469 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1471 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1474 * Correct the window styles.
1476 * It affects only the style loaded into the WIN structure.
1479 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1481 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1482 if (!(wndPtr->dwStyle & WS_POPUP))
1483 wndPtr->dwStyle |= WS_CAPTION;
1486 /* WS_EX_WINDOWEDGE depends on some other styles */
1487 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1488 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1489 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1491 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1492 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1493 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1495 else
1496 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1498 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1499 wndPtr->flags |= WIN_NEED_SIZE;
1501 SERVER_START_REQ( set_window_info )
1503 req->handle = wine_server_user_handle( hwnd );
1504 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1505 req->style = wndPtr->dwStyle;
1506 req->ex_style = wndPtr->dwExStyle;
1507 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1508 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1509 req->extra_offset = -1;
1510 wine_server_call( req );
1512 SERVER_END_REQ;
1514 /* Set the window menu */
1516 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1518 if (cs->hMenu)
1520 if (!MENU_SetMenu(hwnd, cs->hMenu))
1522 WIN_ReleasePtr( wndPtr );
1523 free_window_handle( hwnd );
1524 return 0;
1527 else
1529 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1530 if (menuName)
1532 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1533 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1537 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1539 /* call the WH_CBT hook */
1541 /* the window style passed to the hook must be the real window style,
1542 * rather than just the window style that the caller to CreateWindowEx
1543 * passed in, so we have to copy the original CREATESTRUCT and get the
1544 * the real style. */
1545 cbcs = *cs;
1546 cbcs.style = wndPtr->dwStyle;
1547 cbtc.lpcs = &cbcs;
1548 cbtc.hwndInsertAfter = HWND_TOP;
1549 WIN_ReleasePtr( wndPtr );
1550 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1552 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1554 cx = cs->cx;
1555 cy = cs->cy;
1556 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1558 POINT maxSize, maxPos, minTrack, maxTrack;
1559 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1560 if (maxTrack.x < cx) cx = maxTrack.x;
1561 if (maxTrack.y < cy) cy = maxTrack.y;
1562 if (minTrack.x > cx) cx = minTrack.x;
1563 if (minTrack.y > cy) cy = minTrack.y;
1566 if (cx < 0) cx = 0;
1567 if (cy < 0) cy = 0;
1568 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1569 /* check for wraparound */
1570 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1571 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1572 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1574 /* send WM_NCCREATE */
1576 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1577 if (unicode)
1578 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1579 else
1580 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1581 if (!result)
1583 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1584 goto failed;
1587 /* send WM_NCCALCSIZE */
1589 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1591 /* yes, even if the CBT hook was called with HWND_TOP */
1592 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1593 RECT client_rect = rect;
1595 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1596 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1597 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1598 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1599 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1601 else return 0;
1603 /* send WM_CREATE */
1605 if (unicode)
1606 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1607 else
1608 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1609 if (result == -1) goto failed;
1611 /* call the driver */
1613 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1615 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1617 /* send the size messages */
1619 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1620 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1621 if (!(wndPtr->flags & WIN_NEED_SIZE))
1623 WIN_ReleasePtr( wndPtr );
1624 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1625 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1626 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1627 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1629 else WIN_ReleasePtr( wndPtr );
1631 /* Show the window, maximizing or minimizing if needed */
1633 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1634 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1636 RECT newPos;
1637 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1639 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1640 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1641 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1642 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1643 newPos.bottom - newPos.top, swFlag );
1646 /* Notify the parent window only */
1648 send_parent_notify( hwnd, WM_CREATE );
1649 if (!IsWindow( hwnd )) return 0;
1651 if (cs->style & WS_VISIBLE)
1653 if (cs->style & WS_MAXIMIZE)
1654 sw = SW_SHOW;
1655 else if (cs->style & WS_MINIMIZE)
1656 sw = SW_SHOWMINIMIZED;
1658 ShowWindow( hwnd, sw );
1659 if (cs->dwExStyle & WS_EX_MDICHILD)
1661 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1662 /* ShowWindow won't activate child windows */
1663 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1667 /* Call WH_SHELL hook */
1669 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1670 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1672 TRACE("created window %p\n", hwnd);
1673 return hwnd;
1675 failed:
1676 WIN_DestroyWindow( hwnd );
1677 return 0;
1681 /***********************************************************************
1682 * CreateWindowExA (USER32.@)
1684 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1685 LPCSTR windowName, DWORD style, INT x,
1686 INT y, INT width, INT height,
1687 HWND parent, HMENU menu,
1688 HINSTANCE instance, LPVOID data )
1690 CREATESTRUCTA cs;
1692 cs.lpCreateParams = data;
1693 cs.hInstance = instance;
1694 cs.hMenu = menu;
1695 cs.hwndParent = parent;
1696 cs.x = x;
1697 cs.y = y;
1698 cs.cx = width;
1699 cs.cy = height;
1700 cs.style = style;
1701 cs.lpszName = windowName;
1702 cs.lpszClass = className;
1703 cs.dwExStyle = exStyle;
1705 if (!IS_INTRESOURCE(className))
1707 WCHAR bufferW[256];
1708 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1709 return 0;
1710 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1712 /* Note: we rely on the fact that CREATESTRUCTA and */
1713 /* CREATESTRUCTW have the same layout. */
1714 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1718 /***********************************************************************
1719 * CreateWindowExW (USER32.@)
1721 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1722 LPCWSTR windowName, DWORD style, INT x,
1723 INT y, INT width, INT height,
1724 HWND parent, HMENU menu,
1725 HINSTANCE instance, LPVOID data )
1727 CREATESTRUCTW cs;
1729 cs.lpCreateParams = data;
1730 cs.hInstance = instance;
1731 cs.hMenu = menu;
1732 cs.hwndParent = parent;
1733 cs.x = x;
1734 cs.y = y;
1735 cs.cx = width;
1736 cs.cy = height;
1737 cs.style = style;
1738 cs.lpszName = windowName;
1739 cs.lpszClass = className;
1740 cs.dwExStyle = exStyle;
1742 return wow_handlers.create_window( &cs, className, instance, TRUE );
1746 /***********************************************************************
1747 * WIN_SendDestroyMsg
1749 static void WIN_SendDestroyMsg( HWND hwnd )
1751 GUITHREADINFO info;
1753 info.cbSize = sizeof(info);
1754 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1756 if (hwnd == info.hwndCaret) DestroyCaret();
1757 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1761 * Send the WM_DESTROY to the window.
1763 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1766 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1767 * make sure that the window still exists when we come back.
1769 if (IsWindow(hwnd))
1771 HWND* pWndArray;
1772 int i;
1774 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1776 for (i = 0; pWndArray[i]; i++)
1778 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1780 HeapFree( GetProcessHeap(), 0, pWndArray );
1782 else
1783 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1787 /***********************************************************************
1788 * DestroyWindow (USER32.@)
1790 BOOL WINAPI DestroyWindow( HWND hwnd )
1792 BOOL is_child;
1794 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1796 SetLastError( ERROR_ACCESS_DENIED );
1797 return FALSE;
1800 TRACE("(%p)\n", hwnd);
1802 /* Call hooks */
1804 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1806 if (MENU_IsMenuActive() == hwnd)
1807 EndMenu();
1809 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1811 if (is_child)
1813 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1814 send_parent_notify( hwnd, WM_DESTROY );
1816 else if (!GetWindow( hwnd, GW_OWNER ))
1818 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1819 /* FIXME: clean up palette - see "Internals" p.352 */
1822 if (!IsWindow(hwnd)) return TRUE;
1824 /* Hide the window */
1825 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1827 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1828 if (is_child)
1829 ShowWindow( hwnd, SW_HIDE );
1830 else
1831 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1832 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1835 if (!IsWindow(hwnd)) return TRUE;
1837 /* Recursively destroy owned windows */
1839 if (!is_child)
1841 for (;;)
1843 int i, got_one = 0;
1844 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1845 if (list)
1847 for (i = 0; list[i]; i++)
1849 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1850 if (WIN_IsCurrentThread( list[i] ))
1852 DestroyWindow( list[i] );
1853 got_one = 1;
1854 continue;
1856 WIN_SetOwner( list[i], 0 );
1858 HeapFree( GetProcessHeap(), 0, list );
1860 if (!got_one) break;
1864 /* Send destroy messages */
1866 WIN_SendDestroyMsg( hwnd );
1867 if (!IsWindow( hwnd )) return TRUE;
1869 if (GetClipboardOwner() == hwnd)
1870 CLIPBOARD_ReleaseOwner();
1872 /* Destroy the window storage */
1874 WIN_DestroyWindow( hwnd );
1875 return TRUE;
1879 /***********************************************************************
1880 * CloseWindow (USER32.@)
1882 BOOL WINAPI CloseWindow( HWND hwnd )
1884 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1885 ShowWindow( hwnd, SW_MINIMIZE );
1886 return TRUE;
1890 /***********************************************************************
1891 * OpenIcon (USER32.@)
1893 BOOL WINAPI OpenIcon( HWND hwnd )
1895 if (!IsIconic( hwnd )) return FALSE;
1896 ShowWindow( hwnd, SW_SHOWNORMAL );
1897 return TRUE;
1901 /***********************************************************************
1902 * FindWindowExW (USER32.@)
1904 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1906 HWND *list = NULL;
1907 HWND retvalue = 0;
1908 int i = 0, len = 0;
1909 WCHAR *buffer = NULL;
1911 if (!parent && child) parent = GetDesktopWindow();
1912 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1914 if (title)
1916 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1917 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1920 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1922 if (child)
1924 child = WIN_GetFullHandle( child );
1925 while (list[i] && list[i] != child) i++;
1926 if (!list[i]) goto done;
1927 i++; /* start from next window */
1930 if (title)
1932 while (list[i])
1934 if (GetWindowTextW( list[i], buffer, len + 1 ))
1936 if (!strcmpiW( buffer, title )) break;
1938 else
1940 if (!title[0]) break;
1942 i++;
1945 retvalue = list[i];
1947 done:
1948 HeapFree( GetProcessHeap(), 0, list );
1949 HeapFree( GetProcessHeap(), 0, buffer );
1950 return retvalue;
1955 /***********************************************************************
1956 * FindWindowA (USER32.@)
1958 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1960 HWND ret = FindWindowExA( 0, 0, className, title );
1961 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1962 return ret;
1966 /***********************************************************************
1967 * FindWindowExA (USER32.@)
1969 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1971 LPWSTR titleW = NULL;
1972 HWND hwnd = 0;
1974 if (title)
1976 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1977 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1978 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1981 if (!IS_INTRESOURCE(className))
1983 WCHAR classW[256];
1984 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1985 hwnd = FindWindowExW( parent, child, classW, titleW );
1987 else
1989 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1992 HeapFree( GetProcessHeap(), 0, titleW );
1993 return hwnd;
1997 /***********************************************************************
1998 * FindWindowW (USER32.@)
2000 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2002 return FindWindowExW( 0, 0, className, title );
2006 /**********************************************************************
2007 * GetDesktopWindow (USER32.@)
2009 HWND WINAPI GetDesktopWindow(void)
2011 struct user_thread_info *thread_info = get_user_thread_info();
2013 if (thread_info->top_window) return thread_info->top_window;
2015 SERVER_START_REQ( get_desktop_window )
2017 req->force = 0;
2018 if (!wine_server_call( req ))
2020 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2021 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2024 SERVER_END_REQ;
2026 if (!thread_info->top_window)
2028 USEROBJECTFLAGS flags;
2029 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2030 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2032 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2033 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2034 STARTUPINFOW si;
2035 PROCESS_INFORMATION pi;
2036 WCHAR windir[MAX_PATH];
2037 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2038 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2039 void *redir;
2041 memset( &si, 0, sizeof(si) );
2042 si.cb = sizeof(si);
2043 si.dwFlags = STARTF_USESTDHANDLES;
2044 si.hStdInput = 0;
2045 si.hStdOutput = 0;
2046 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2048 GetSystemDirectoryW( windir, MAX_PATH );
2049 strcpyW( app, windir );
2050 strcatW( app, explorer );
2051 strcpyW( cmdline, app );
2052 strcatW( cmdline, args );
2054 Wow64DisableWow64FsRedirection( &redir );
2055 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2056 NULL, windir, &si, &pi ))
2058 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2059 WaitForInputIdle( pi.hProcess, 10000 );
2060 CloseHandle( pi.hThread );
2061 CloseHandle( pi.hProcess );
2063 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2064 Wow64RevertWow64FsRedirection( redir );
2066 else TRACE( "not starting explorer since winstation is not visible\n" );
2068 SERVER_START_REQ( get_desktop_window )
2070 req->force = 1;
2071 if (!wine_server_call( req ))
2073 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2074 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2077 SERVER_END_REQ;
2080 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2081 ERR( "failed to create desktop window\n" );
2083 return thread_info->top_window;
2087 /*******************************************************************
2088 * EnableWindow (USER32.@)
2090 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2092 BOOL retvalue;
2093 HWND full_handle;
2095 if (is_broadcast(hwnd))
2097 SetLastError( ERROR_INVALID_PARAMETER );
2098 return FALSE;
2101 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2102 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2104 hwnd = full_handle;
2106 TRACE("( %p, %d )\n", hwnd, enable);
2108 retvalue = !IsWindowEnabled( hwnd );
2110 if (enable && retvalue)
2112 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2113 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2115 else if (!enable && !retvalue)
2117 HWND capture_wnd;
2119 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2121 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2123 if (hwnd == GetFocus())
2124 SetFocus( 0 ); /* A disabled window can't have the focus */
2126 capture_wnd = GetCapture();
2127 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2128 ReleaseCapture(); /* A disabled window can't capture the mouse */
2130 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2132 return retvalue;
2136 /***********************************************************************
2137 * IsWindowEnabled (USER32.@)
2139 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2141 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2145 /***********************************************************************
2146 * IsWindowUnicode (USER32.@)
2148 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2150 WND * wndPtr;
2151 BOOL retvalue = FALSE;
2153 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2155 if (wndPtr == WND_DESKTOP) return TRUE;
2157 if (wndPtr != WND_OTHER_PROCESS)
2159 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2160 WIN_ReleasePtr( wndPtr );
2162 else
2164 SERVER_START_REQ( get_window_info )
2166 req->handle = wine_server_user_handle( hwnd );
2167 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2169 SERVER_END_REQ;
2171 return retvalue;
2175 /**********************************************************************
2176 * WIN_GetWindowLong
2178 * Helper function for GetWindowLong().
2180 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2182 LONG_PTR retvalue = 0;
2183 WND *wndPtr;
2185 if (offset == GWLP_HWNDPARENT)
2187 HWND parent = GetAncestor( hwnd, GA_PARENT );
2188 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2189 return (ULONG_PTR)parent;
2192 if (!(wndPtr = WIN_GetPtr( hwnd )))
2194 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2195 return 0;
2198 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2200 if (offset == GWLP_WNDPROC)
2202 SetLastError( ERROR_ACCESS_DENIED );
2203 return 0;
2205 SERVER_START_REQ( set_window_info )
2207 req->handle = wine_server_user_handle( hwnd );
2208 req->flags = 0; /* don't set anything, just retrieve */
2209 req->extra_offset = (offset >= 0) ? offset : -1;
2210 req->extra_size = (offset >= 0) ? size : 0;
2211 if (!wine_server_call_err( req ))
2213 switch(offset)
2215 case GWL_STYLE: retvalue = reply->old_style; break;
2216 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2217 case GWLP_ID: retvalue = reply->old_id; break;
2218 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2219 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2220 default:
2221 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2222 else SetLastError( ERROR_INVALID_INDEX );
2223 break;
2227 SERVER_END_REQ;
2228 return retvalue;
2231 /* now we have a valid wndPtr */
2233 if (offset >= 0)
2235 if (offset > (int)(wndPtr->cbWndExtra - size))
2237 WARN("Invalid offset %d\n", offset );
2238 WIN_ReleasePtr( wndPtr );
2239 SetLastError( ERROR_INVALID_INDEX );
2240 return 0;
2242 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2244 /* Special case for dialog window procedure */
2245 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2246 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2247 WIN_ReleasePtr( wndPtr );
2248 return retvalue;
2251 switch(offset)
2253 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2254 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2255 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2256 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2257 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2258 case GWLP_WNDPROC:
2259 /* This looks like a hack only for the edit control (see tests). This makes these controls
2260 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2261 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2263 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2264 retvalue = (ULONG_PTR)wndPtr->winproc;
2265 else
2266 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2267 break;
2268 default:
2269 WARN("Unknown offset %d\n", offset );
2270 SetLastError( ERROR_INVALID_INDEX );
2271 break;
2273 WIN_ReleasePtr(wndPtr);
2274 return retvalue;
2278 /**********************************************************************
2279 * WIN_SetWindowLong
2281 * Helper function for SetWindowLong().
2283 * 0 is the failure code. However, in the case of failure SetLastError
2284 * must be set to distinguish between a 0 return value and a failure.
2286 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2288 STYLESTRUCT style;
2289 BOOL ok, made_visible = FALSE;
2290 LONG_PTR retval = 0;
2291 WND *wndPtr;
2293 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2295 if (is_broadcast(hwnd))
2297 SetLastError( ERROR_INVALID_PARAMETER );
2298 return FALSE;
2301 if (!(wndPtr = WIN_GetPtr( hwnd )))
2303 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2304 return 0;
2306 if (wndPtr == WND_DESKTOP)
2308 /* can't change anything on the desktop window */
2309 SetLastError( ERROR_ACCESS_DENIED );
2310 return 0;
2312 if (wndPtr == WND_OTHER_PROCESS)
2314 if (offset == GWLP_WNDPROC)
2316 SetLastError( ERROR_ACCESS_DENIED );
2317 return 0;
2319 if (offset > 32767 || offset < -32767)
2321 SetLastError( ERROR_INVALID_INDEX );
2322 return 0;
2324 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2327 /* first some special cases */
2328 switch( offset )
2330 case GWL_STYLE:
2331 style.styleOld = wndPtr->dwStyle;
2332 style.styleNew = newval;
2333 WIN_ReleasePtr( wndPtr );
2334 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2335 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2336 newval = style.styleNew;
2337 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2338 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2339 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2340 WS_EX_WINDOWEDGE too */
2341 break;
2342 case GWL_EXSTYLE:
2343 style.styleOld = wndPtr->dwExStyle;
2344 style.styleNew = newval;
2345 WIN_ReleasePtr( wndPtr );
2346 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2347 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2348 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2349 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2350 /* WS_EX_WINDOWEDGE depends on some other styles */
2351 if (newval & WS_EX_DLGMODALFRAME)
2352 newval |= WS_EX_WINDOWEDGE;
2353 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2354 newval |= WS_EX_WINDOWEDGE;
2355 else
2356 newval &= ~WS_EX_WINDOWEDGE;
2357 break;
2358 case GWLP_HWNDPARENT:
2359 if (wndPtr->parent == GetDesktopWindow())
2361 WIN_ReleasePtr( wndPtr );
2362 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2364 else
2366 WIN_ReleasePtr( wndPtr );
2367 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2369 case GWLP_WNDPROC:
2371 WNDPROC proc;
2372 UINT old_flags = wndPtr->flags;
2373 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2374 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2375 if (proc) wndPtr->winproc = proc;
2376 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2377 else wndPtr->flags &= ~WIN_ISUNICODE;
2378 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2380 WIN_ReleasePtr( wndPtr );
2381 return retval;
2383 /* update is_unicode flag on the server side */
2384 break;
2386 case GWLP_ID:
2387 case GWLP_HINSTANCE:
2388 case GWLP_USERDATA:
2389 break;
2390 case DWLP_DLGPROC:
2391 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2392 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2394 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2395 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2396 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2397 WIN_ReleasePtr( wndPtr );
2398 return retval;
2400 /* fall through */
2401 default:
2402 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2404 WARN("Invalid offset %d\n", offset );
2405 WIN_ReleasePtr( wndPtr );
2406 SetLastError( ERROR_INVALID_INDEX );
2407 return 0;
2409 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2411 /* already set to the same value */
2412 WIN_ReleasePtr( wndPtr );
2413 return newval;
2415 break;
2418 SERVER_START_REQ( set_window_info )
2420 req->handle = wine_server_user_handle( hwnd );
2421 req->extra_offset = -1;
2422 switch(offset)
2424 case GWL_STYLE:
2425 req->flags = SET_WIN_STYLE;
2426 req->style = newval;
2427 break;
2428 case GWL_EXSTYLE:
2429 req->flags = SET_WIN_EXSTYLE;
2430 req->ex_style = newval;
2431 break;
2432 case GWLP_ID:
2433 req->flags = SET_WIN_ID;
2434 req->id = newval;
2435 break;
2436 case GWLP_HINSTANCE:
2437 req->flags = SET_WIN_INSTANCE;
2438 req->instance = wine_server_client_ptr( (void *)newval );
2439 break;
2440 case GWLP_WNDPROC:
2441 req->flags = SET_WIN_UNICODE;
2442 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2443 break;
2444 case GWLP_USERDATA:
2445 req->flags = SET_WIN_USERDATA;
2446 req->user_data = newval;
2447 break;
2448 default:
2449 req->flags = SET_WIN_EXTRA;
2450 req->extra_offset = offset;
2451 req->extra_size = size;
2452 set_win_data( &req->extra_value, newval, size );
2454 if ((ok = !wine_server_call_err( req )))
2456 switch(offset)
2458 case GWL_STYLE:
2459 wndPtr->dwStyle = newval;
2460 retval = reply->old_style;
2461 break;
2462 case GWL_EXSTYLE:
2463 wndPtr->dwExStyle = newval;
2464 retval = reply->old_ex_style;
2465 break;
2466 case GWLP_ID:
2467 wndPtr->wIDmenu = newval;
2468 retval = reply->old_id;
2469 break;
2470 case GWLP_HINSTANCE:
2471 wndPtr->hInstance = (HINSTANCE)newval;
2472 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2473 break;
2474 case GWLP_WNDPROC:
2475 break;
2476 case GWLP_USERDATA:
2477 wndPtr->userdata = newval;
2478 retval = reply->old_user_data;
2479 break;
2480 default:
2481 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2482 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2483 break;
2487 SERVER_END_REQ;
2489 if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2490 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2492 made_visible = !(wndPtr->flags & WIN_HIDDEN) && (wndPtr->dwStyle & WS_VISIBLE);
2493 invalidate_dce( wndPtr, NULL );
2495 WIN_ReleasePtr( wndPtr );
2497 if (!ok) return 0;
2499 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2501 style.styleOld = retval;
2502 style.styleNew = newval;
2503 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2504 if (made_visible) update_window_state( hwnd );
2505 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2508 return retval;
2512 /**********************************************************************
2513 * GetWindowWord (USER32.@)
2515 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2517 switch(offset)
2519 case GWLP_ID:
2520 case GWLP_HINSTANCE:
2521 case GWLP_HWNDPARENT:
2522 break;
2523 default:
2524 if (offset < 0)
2526 WARN("Invalid offset %d\n", offset );
2527 SetLastError( ERROR_INVALID_INDEX );
2528 return 0;
2530 break;
2532 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2536 /**********************************************************************
2537 * GetWindowLongA (USER32.@)
2539 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2541 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2545 /**********************************************************************
2546 * GetWindowLongW (USER32.@)
2548 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2550 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2554 /**********************************************************************
2555 * SetWindowWord (USER32.@)
2557 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2559 switch(offset)
2561 case GWLP_ID:
2562 case GWLP_HINSTANCE:
2563 case GWLP_HWNDPARENT:
2564 break;
2565 default:
2566 if (offset < 0)
2568 WARN("Invalid offset %d\n", offset );
2569 SetLastError( ERROR_INVALID_INDEX );
2570 return 0;
2572 break;
2574 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2578 /**********************************************************************
2579 * SetWindowLongA (USER32.@)
2581 * See SetWindowLongW.
2583 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2585 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2589 /**********************************************************************
2590 * SetWindowLongW (USER32.@) Set window attribute
2592 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2593 * value in a window's extra memory.
2595 * The _hwnd_ parameter specifies the window. is the handle to a
2596 * window that has extra memory. The _newval_ parameter contains the
2597 * new attribute or extra memory value. If positive, the _offset_
2598 * parameter is the byte-addressed location in the window's extra
2599 * memory to set. If negative, _offset_ specifies the window
2600 * attribute to set, and should be one of the following values:
2602 * GWL_EXSTYLE The window's extended window style
2604 * GWL_STYLE The window's window style.
2606 * GWLP_WNDPROC Pointer to the window's window procedure.
2608 * GWLP_HINSTANCE The window's pplication instance handle.
2610 * GWLP_ID The window's identifier.
2612 * GWLP_USERDATA The window's user-specified data.
2614 * If the window is a dialog box, the _offset_ parameter can be one of
2615 * the following values:
2617 * DWLP_DLGPROC The address of the window's dialog box procedure.
2619 * DWLP_MSGRESULT The return value of a message
2620 * that the dialog box procedure processed.
2622 * DWLP_USER Application specific information.
2624 * RETURNS
2626 * If successful, returns the previous value located at _offset_. Otherwise,
2627 * returns 0.
2629 * NOTES
2631 * Extra memory for a window class is specified by a nonzero cbWndExtra
2632 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2633 * time of class creation.
2635 * Using GWL_WNDPROC to set a new window procedure effectively creates
2636 * a window subclass. Use CallWindowProc() in the new windows procedure
2637 * to pass messages to the superclass's window procedure.
2639 * The user data is reserved for use by the application which created
2640 * the window.
2642 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2643 * instead, call the EnableWindow() function to change the window's
2644 * disabled state.
2646 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2647 * SetParent() instead.
2649 * Win95:
2650 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2651 * it sends WM_STYLECHANGING before changing the settings
2652 * and WM_STYLECHANGED afterwards.
2653 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2655 LONG WINAPI SetWindowLongW(
2656 HWND hwnd, /* [in] window to alter */
2657 INT offset, /* [in] offset, in bytes, of location to alter */
2658 LONG newval /* [in] new value of location */
2660 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2664 /*******************************************************************
2665 * GetWindowTextA (USER32.@)
2667 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2669 WCHAR *buffer;
2671 if (!lpString) return 0;
2673 if (WIN_IsCurrentProcess( hwnd ))
2674 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2676 /* when window belongs to other process, don't send a message */
2677 if (nMaxCount <= 0) return 0;
2678 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2679 get_server_window_text( hwnd, buffer, nMaxCount );
2680 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2681 lpString[nMaxCount-1] = 0;
2682 HeapFree( GetProcessHeap(), 0, buffer );
2683 return strlen(lpString);
2687 /*******************************************************************
2688 * InternalGetWindowText (USER32.@)
2690 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2692 WND *win;
2694 if (nMaxCount <= 0) return 0;
2695 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2696 if (win == WND_DESKTOP) lpString[0] = 0;
2697 else if (win != WND_OTHER_PROCESS)
2699 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2700 else lpString[0] = 0;
2701 WIN_ReleasePtr( win );
2703 else
2705 get_server_window_text( hwnd, lpString, nMaxCount );
2707 return strlenW(lpString);
2711 /*******************************************************************
2712 * GetWindowTextW (USER32.@)
2714 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2716 if (!lpString) return 0;
2718 if (WIN_IsCurrentProcess( hwnd ))
2719 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2721 /* when window belongs to other process, don't send a message */
2722 if (nMaxCount <= 0) return 0;
2723 get_server_window_text( hwnd, lpString, nMaxCount );
2724 return strlenW(lpString);
2728 /*******************************************************************
2729 * SetWindowTextA (USER32.@)
2730 * SetWindowText (USER32.@)
2732 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2734 if (is_broadcast(hwnd))
2736 SetLastError( ERROR_INVALID_PARAMETER );
2737 return FALSE;
2739 if (!WIN_IsCurrentProcess( hwnd ))
2740 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2741 debugstr_a(lpString), hwnd );
2742 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2746 /*******************************************************************
2747 * SetWindowTextW (USER32.@)
2749 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2751 if (is_broadcast(hwnd))
2753 SetLastError( ERROR_INVALID_PARAMETER );
2754 return FALSE;
2756 if (!WIN_IsCurrentProcess( hwnd ))
2757 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2758 debugstr_w(lpString), hwnd );
2759 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2763 /*******************************************************************
2764 * GetWindowTextLengthA (USER32.@)
2766 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2768 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2771 /*******************************************************************
2772 * GetWindowTextLengthW (USER32.@)
2774 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2776 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2780 /*******************************************************************
2781 * IsWindow (USER32.@)
2783 BOOL WINAPI IsWindow( HWND hwnd )
2785 WND *ptr;
2786 BOOL ret;
2788 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2789 if (ptr == WND_DESKTOP) return TRUE;
2791 if (ptr != WND_OTHER_PROCESS)
2793 WIN_ReleasePtr( ptr );
2794 return TRUE;
2797 /* check other processes */
2798 SERVER_START_REQ( get_window_info )
2800 req->handle = wine_server_user_handle( hwnd );
2801 ret = !wine_server_call_err( req );
2803 SERVER_END_REQ;
2804 return ret;
2808 /***********************************************************************
2809 * GetWindowThreadProcessId (USER32.@)
2811 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2813 WND *ptr;
2814 DWORD tid = 0;
2816 if (!(ptr = WIN_GetPtr( hwnd )))
2818 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2819 return 0;
2822 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2824 /* got a valid window */
2825 tid = ptr->tid;
2826 if (process) *process = GetCurrentProcessId();
2827 WIN_ReleasePtr( ptr );
2828 return tid;
2831 /* check other processes */
2832 SERVER_START_REQ( get_window_info )
2834 req->handle = wine_server_user_handle( hwnd );
2835 if (!wine_server_call_err( req ))
2837 tid = (DWORD)reply->tid;
2838 if (process) *process = (DWORD)reply->pid;
2841 SERVER_END_REQ;
2842 return tid;
2846 /*****************************************************************
2847 * GetParent (USER32.@)
2849 HWND WINAPI GetParent( HWND hwnd )
2851 WND *wndPtr;
2852 HWND retvalue = 0;
2854 if (!(wndPtr = WIN_GetPtr( hwnd )))
2856 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2857 return 0;
2859 if (wndPtr == WND_DESKTOP) return 0;
2860 if (wndPtr == WND_OTHER_PROCESS)
2862 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2863 if (style & (WS_POPUP | WS_CHILD))
2865 SERVER_START_REQ( get_window_tree )
2867 req->handle = wine_server_user_handle( hwnd );
2868 if (!wine_server_call_err( req ))
2870 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2871 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2874 SERVER_END_REQ;
2877 else
2879 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2880 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2881 WIN_ReleasePtr( wndPtr );
2883 return retvalue;
2887 /*****************************************************************
2888 * GetAncestor (USER32.@)
2890 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2892 WND *win;
2893 HWND *list, ret = 0;
2895 switch(type)
2897 case GA_PARENT:
2898 if (!(win = WIN_GetPtr( hwnd )))
2900 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2901 return 0;
2903 if (win == WND_DESKTOP) return 0;
2904 if (win != WND_OTHER_PROCESS)
2906 ret = win->parent;
2907 WIN_ReleasePtr( win );
2909 else /* need to query the server */
2911 SERVER_START_REQ( get_window_tree )
2913 req->handle = wine_server_user_handle( hwnd );
2914 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2916 SERVER_END_REQ;
2918 break;
2920 case GA_ROOT:
2921 if (!(list = list_window_parents( hwnd ))) return 0;
2923 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2924 else
2926 int count = 2;
2927 while (list[count]) count++;
2928 ret = list[count - 2]; /* get the one before the desktop */
2930 HeapFree( GetProcessHeap(), 0, list );
2931 break;
2933 case GA_ROOTOWNER:
2934 if (is_desktop_window( hwnd )) return 0;
2935 ret = WIN_GetFullHandle( hwnd );
2936 for (;;)
2938 HWND parent = GetParent( ret );
2939 if (!parent) break;
2940 ret = parent;
2942 break;
2944 return ret;
2948 /*****************************************************************
2949 * SetParent (USER32.@)
2951 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2953 HWND full_handle;
2954 HWND old_parent = 0;
2955 BOOL was_visible;
2956 WND *wndPtr;
2957 POINT pt;
2958 BOOL ret;
2960 if (is_broadcast(hwnd) || is_broadcast(parent))
2962 SetLastError(ERROR_INVALID_PARAMETER);
2963 return 0;
2966 if (!parent) parent = GetDesktopWindow();
2967 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2968 else parent = WIN_GetFullHandle( parent );
2970 if (!IsWindow( parent ))
2972 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2973 return 0;
2976 /* Some applications try to set a child as a parent */
2977 if (IsChild(hwnd, parent))
2979 SetLastError( ERROR_INVALID_PARAMETER );
2980 return 0;
2983 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2984 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2986 if (full_handle == parent)
2988 SetLastError( ERROR_INVALID_PARAMETER );
2989 return 0;
2992 /* Windows hides the window first, then shows it again
2993 * including the WM_SHOWWINDOW messages and all */
2994 was_visible = ShowWindow( hwnd, SW_HIDE );
2996 wndPtr = WIN_GetPtr( hwnd );
2997 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2999 pt.x = wndPtr->rectWindow.left;
3000 pt.y = wndPtr->rectWindow.top;
3002 SERVER_START_REQ( set_parent )
3004 req->handle = wine_server_user_handle( hwnd );
3005 req->parent = wine_server_user_handle( parent );
3006 if ((ret = !wine_server_call( req )))
3008 old_parent = wine_server_ptr_handle( reply->old_parent );
3009 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3013 SERVER_END_REQ;
3014 WIN_ReleasePtr( wndPtr );
3015 if (!ret) return 0;
3017 USER_Driver->pSetParent( full_handle, parent, old_parent );
3019 /* SetParent additionally needs to make hwnd the topmost window
3020 in the x-order and send the expected WM_WINDOWPOSCHANGING and
3021 WM_WINDOWPOSCHANGED notification messages.
3023 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3025 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3027 return old_parent;
3031 /*******************************************************************
3032 * IsChild (USER32.@)
3034 BOOL WINAPI IsChild( HWND parent, HWND child )
3036 HWND *list = list_window_parents( child );
3037 int i;
3038 BOOL ret;
3040 if (!list) return FALSE;
3041 parent = WIN_GetFullHandle( parent );
3042 for (i = 0; list[i]; i++) if (list[i] == parent) break;
3043 ret = list[i] && list[i+1];
3044 HeapFree( GetProcessHeap(), 0, list );
3045 return ret;
3049 /***********************************************************************
3050 * IsWindowVisible (USER32.@)
3052 BOOL WINAPI IsWindowVisible( HWND hwnd )
3054 HWND *list;
3055 BOOL retval = TRUE;
3056 int i;
3058 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3059 if (!(list = list_window_parents( hwnd ))) return TRUE;
3060 if (list[0])
3062 for (i = 0; list[i+1]; i++)
3063 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3064 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3066 HeapFree( GetProcessHeap(), 0, list );
3067 return retval;
3071 /***********************************************************************
3072 * WIN_IsWindowDrawable
3074 * hwnd is drawable when it is visible, all parents are not
3075 * minimized, and it is itself not minimized unless we are
3076 * trying to draw its default class icon.
3078 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3080 HWND *list;
3081 BOOL retval = TRUE;
3082 int i;
3083 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3085 if (!(style & WS_VISIBLE)) return FALSE;
3086 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3088 if (!(list = list_window_parents( hwnd ))) return TRUE;
3089 if (list[0])
3091 for (i = 0; list[i+1]; i++)
3092 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3093 break;
3094 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3096 HeapFree( GetProcessHeap(), 0, list );
3097 return retval;
3101 /*******************************************************************
3102 * GetTopWindow (USER32.@)
3104 HWND WINAPI GetTopWindow( HWND hwnd )
3106 if (!hwnd) hwnd = GetDesktopWindow();
3107 return GetWindow( hwnd, GW_CHILD );
3111 /*******************************************************************
3112 * GetWindow (USER32.@)
3114 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3116 HWND retval = 0;
3118 if (rel == GW_OWNER) /* this one may be available locally */
3120 WND *wndPtr = WIN_GetPtr( hwnd );
3121 if (!wndPtr)
3123 SetLastError( ERROR_INVALID_HANDLE );
3124 return 0;
3126 if (wndPtr == WND_DESKTOP) return 0;
3127 if (wndPtr != WND_OTHER_PROCESS)
3129 retval = wndPtr->owner;
3130 WIN_ReleasePtr( wndPtr );
3131 return retval;
3133 /* else fall through to server call */
3136 SERVER_START_REQ( get_window_tree )
3138 req->handle = wine_server_user_handle( hwnd );
3139 if (!wine_server_call_err( req ))
3141 switch(rel)
3143 case GW_HWNDFIRST:
3144 retval = wine_server_ptr_handle( reply->first_sibling );
3145 break;
3146 case GW_HWNDLAST:
3147 retval = wine_server_ptr_handle( reply->last_sibling );
3148 break;
3149 case GW_HWNDNEXT:
3150 retval = wine_server_ptr_handle( reply->next_sibling );
3151 break;
3152 case GW_HWNDPREV:
3153 retval = wine_server_ptr_handle( reply->prev_sibling );
3154 break;
3155 case GW_OWNER:
3156 retval = wine_server_ptr_handle( reply->owner );
3157 break;
3158 case GW_CHILD:
3159 retval = wine_server_ptr_handle( reply->first_child );
3160 break;
3164 SERVER_END_REQ;
3165 return retval;
3169 /*******************************************************************
3170 * ShowOwnedPopups (USER32.@)
3172 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3174 int count = 0;
3175 WND *pWnd;
3176 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3178 if (!win_array) return TRUE;
3180 while (win_array[count]) count++;
3181 while (--count >= 0)
3183 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3184 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3185 if (pWnd == WND_OTHER_PROCESS) continue;
3186 if (fShow)
3188 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3190 WIN_ReleasePtr( pWnd );
3191 /* In Windows, ShowOwnedPopups(TRUE) generates
3192 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3193 * regardless of the state of the owner
3195 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3196 continue;
3199 else
3201 if (pWnd->dwStyle & WS_VISIBLE)
3203 WIN_ReleasePtr( pWnd );
3204 /* In Windows, ShowOwnedPopups(FALSE) generates
3205 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3206 * regardless of the state of the owner
3208 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3209 continue;
3212 WIN_ReleasePtr( pWnd );
3214 HeapFree( GetProcessHeap(), 0, win_array );
3215 return TRUE;
3219 /*******************************************************************
3220 * GetLastActivePopup (USER32.@)
3222 HWND WINAPI GetLastActivePopup( HWND hwnd )
3224 HWND retval = hwnd;
3226 SERVER_START_REQ( get_window_info )
3228 req->handle = wine_server_user_handle( hwnd );
3229 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3231 SERVER_END_REQ;
3232 return retval;
3236 /*******************************************************************
3237 * WIN_ListChildren
3239 * Build an array of the children of a given window. The array must be
3240 * freed with HeapFree. Returns NULL when no windows are found.
3242 HWND *WIN_ListChildren( HWND hwnd )
3244 if (!hwnd)
3246 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3247 return NULL;
3249 return list_window_children( 0, hwnd, NULL, 0 );
3253 /*******************************************************************
3254 * EnumWindows (USER32.@)
3256 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3258 HWND *list;
3259 BOOL ret = TRUE;
3260 int i;
3262 USER_CheckNotLock();
3264 /* We have to build a list of all windows first, to avoid */
3265 /* unpleasant side-effects, for instance if the callback */
3266 /* function changes the Z-order of the windows. */
3268 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3270 /* Now call the callback function for every window */
3272 for (i = 0; list[i]; i++)
3274 /* Make sure that the window still exists */
3275 if (!IsWindow( list[i] )) continue;
3276 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3278 HeapFree( GetProcessHeap(), 0, list );
3279 return ret;
3283 /**********************************************************************
3284 * EnumThreadWindows (USER32.@)
3286 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3288 HWND *list;
3289 int i;
3290 BOOL ret = TRUE;
3292 USER_CheckNotLock();
3294 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3296 /* Now call the callback function for every window */
3298 for (i = 0; list[i]; i++)
3299 if (!(ret = func( list[i], lParam ))) break;
3300 HeapFree( GetProcessHeap(), 0, list );
3301 return ret;
3305 /***********************************************************************
3306 * EnumDesktopWindows (USER32.@)
3308 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3310 HWND *list;
3311 int i;
3313 USER_CheckNotLock();
3315 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3317 for (i = 0; list[i]; i++)
3318 if (!func( list[i], lparam )) break;
3319 HeapFree( GetProcessHeap(), 0, list );
3320 return TRUE;
3324 /**********************************************************************
3325 * WIN_EnumChildWindows
3327 * Helper function for EnumChildWindows().
3329 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3331 HWND *childList;
3332 BOOL ret = FALSE;
3334 for ( ; *list; list++)
3336 /* Make sure that the window still exists */
3337 if (!IsWindow( *list )) continue;
3338 /* Build children list first */
3339 childList = WIN_ListChildren( *list );
3341 ret = func( *list, lParam );
3343 if (childList)
3345 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3346 HeapFree( GetProcessHeap(), 0, childList );
3348 if (!ret) return FALSE;
3350 return TRUE;
3354 /**********************************************************************
3355 * EnumChildWindows (USER32.@)
3357 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3359 HWND *list;
3360 BOOL ret;
3362 USER_CheckNotLock();
3364 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3365 ret = WIN_EnumChildWindows( list, func, lParam );
3366 HeapFree( GetProcessHeap(), 0, list );
3367 return ret;
3371 /*******************************************************************
3372 * AnyPopup (USER32.@)
3374 BOOL WINAPI AnyPopup(void)
3376 int i;
3377 BOOL retvalue;
3378 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3380 if (!list) return FALSE;
3381 for (i = 0; list[i]; i++)
3383 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3385 retvalue = (list[i] != 0);
3386 HeapFree( GetProcessHeap(), 0, list );
3387 return retvalue;
3391 /*******************************************************************
3392 * FlashWindow (USER32.@)
3394 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3396 WND *wndPtr;
3398 TRACE("%p\n", hWnd);
3400 if (IsIconic( hWnd ))
3402 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3404 wndPtr = WIN_GetPtr(hWnd);
3405 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3406 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3408 wndPtr->flags |= WIN_NCACTIVATED;
3410 else
3412 wndPtr->flags &= ~WIN_NCACTIVATED;
3414 WIN_ReleasePtr( wndPtr );
3415 return TRUE;
3417 else
3419 WPARAM wparam;
3421 wndPtr = WIN_GetPtr(hWnd);
3422 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3423 hWnd = wndPtr->obj.handle; /* make it a full handle */
3425 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3426 else wparam = (hWnd == GetForegroundWindow());
3428 WIN_ReleasePtr( wndPtr );
3429 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3430 return wparam;
3434 /*******************************************************************
3435 * FlashWindowEx (USER32.@)
3437 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3439 FIXME("%p\n", pfwi);
3440 return TRUE;
3443 /*******************************************************************
3444 * GetWindowContextHelpId (USER32.@)
3446 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3448 DWORD retval;
3449 WND *wnd = WIN_GetPtr( hwnd );
3450 if (!wnd || wnd == WND_DESKTOP) return 0;
3451 if (wnd == WND_OTHER_PROCESS)
3453 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3454 return 0;
3456 retval = wnd->helpContext;
3457 WIN_ReleasePtr( wnd );
3458 return retval;
3462 /*******************************************************************
3463 * SetWindowContextHelpId (USER32.@)
3465 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3467 WND *wnd = WIN_GetPtr( hwnd );
3468 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3469 if (wnd == WND_OTHER_PROCESS)
3471 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3472 return 0;
3474 wnd->helpContext = id;
3475 WIN_ReleasePtr( wnd );
3476 return TRUE;
3480 /*******************************************************************
3481 * DragDetect (USER32.@)
3483 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3485 MSG msg;
3486 RECT rect;
3487 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3488 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3490 rect.left = pt.x - wDragWidth;
3491 rect.right = pt.x + wDragWidth;
3493 rect.top = pt.y - wDragHeight;
3494 rect.bottom = pt.y + wDragHeight;
3496 SetCapture(hWnd);
3498 while(1)
3500 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3502 if( msg.message == WM_LBUTTONUP )
3504 ReleaseCapture();
3505 return 0;
3507 if( msg.message == WM_MOUSEMOVE )
3509 POINT tmp;
3510 tmp.x = (short)LOWORD(msg.lParam);
3511 tmp.y = (short)HIWORD(msg.lParam);
3512 if( !PtInRect( &rect, tmp ))
3514 ReleaseCapture();
3515 return 1;
3519 WaitMessage();
3521 return 0;
3524 /******************************************************************************
3525 * GetWindowModuleFileNameA (USER32.@)
3527 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3529 WND *win;
3530 HINSTANCE hinst;
3532 TRACE( "%p, %p, %u\n", hwnd, module, size );
3534 win = WIN_GetPtr( hwnd );
3535 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3537 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3538 return 0;
3540 hinst = win->hInstance;
3541 WIN_ReleasePtr( win );
3543 return GetModuleFileNameA( hinst, module, size );
3546 /******************************************************************************
3547 * GetWindowModuleFileNameW (USER32.@)
3549 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3551 WND *win;
3552 HINSTANCE hinst;
3554 TRACE( "%p, %p, %u\n", hwnd, module, size );
3556 win = WIN_GetPtr( hwnd );
3557 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3559 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3560 return 0;
3562 hinst = win->hInstance;
3563 WIN_ReleasePtr( win );
3565 return GetModuleFileNameW( hinst, module, size );
3568 /******************************************************************************
3569 * GetWindowInfo (USER32.@)
3571 * Note: tests show that Windows doesn't check cbSize of the structure.
3573 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3575 if (!pwi) return FALSE;
3576 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3578 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3579 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3580 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3582 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3583 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3585 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3586 pwi->wCreatorVersion = 0x0400;
3588 return TRUE;
3591 /******************************************************************************
3592 * SwitchDesktop (USER32.@)
3594 * NOTES: Sets the current input or interactive desktop.
3596 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3598 FIXME("(hwnd %p) stub!\n", hDesktop);
3599 return TRUE;
3603 /***********************************************************************
3604 * __wine_set_pixel_format
3606 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3608 WND *win = WIN_GetPtr( hwnd );
3610 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3612 WARN( "setting format %d on win %p not supported\n", format, hwnd );
3613 return FALSE;
3615 win->pixel_format = format;
3616 WIN_ReleasePtr( win );
3618 update_window_state( hwnd );
3619 return TRUE;
3623 /*****************************************************************************
3624 * SetLayeredWindowAttributes (USER32.@)
3626 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3628 BOOL ret;
3630 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3632 SERVER_START_REQ( set_window_layered_info )
3634 req->handle = wine_server_user_handle( hwnd );
3635 req->color_key = key;
3636 req->alpha = alpha;
3637 req->flags = flags;
3638 ret = !wine_server_call_err( req );
3640 SERVER_END_REQ;
3642 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3644 return ret;
3648 /*****************************************************************************
3649 * GetLayeredWindowAttributes (USER32.@)
3651 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3653 BOOL ret;
3655 SERVER_START_REQ( get_window_layered_info )
3657 req->handle = wine_server_user_handle( hwnd );
3658 if ((ret = !wine_server_call_err( req )))
3660 if (key) *key = reply->color_key;
3661 if (alpha) *alpha = reply->alpha;
3662 if (flags) *flags = reply->flags;
3665 SERVER_END_REQ;
3667 return ret;
3671 /*****************************************************************************
3672 * UpdateLayeredWindowIndirect (USER32.@)
3674 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3676 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3677 RECT window_rect, client_rect;
3678 SIZE offset;
3680 if (!info ||
3681 info->cbSize != sizeof(*info) ||
3682 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3683 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3684 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3686 SetLastError( ERROR_INVALID_PARAMETER );
3687 return FALSE;
3690 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3692 if (info->pptDst)
3694 offset.cx = info->pptDst->x - window_rect.left;
3695 offset.cy = info->pptDst->y - window_rect.top;
3696 OffsetRect( &client_rect, offset.cx, offset.cy );
3697 OffsetRect( &window_rect, offset.cx, offset.cy );
3698 flags &= ~SWP_NOMOVE;
3700 if (info->psize)
3702 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3703 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3704 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3706 SetLastError( ERROR_INVALID_PARAMETER );
3707 return FALSE;
3709 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3711 SetLastError( ERROR_INCORRECT_SIZE );
3712 return FALSE;
3714 client_rect.right += offset.cx;
3715 client_rect.bottom += offset.cy;
3716 window_rect.right += offset.cx;
3717 window_rect.bottom += offset.cy;
3718 flags &= ~SWP_NOSIZE;
3721 TRACE( "window %p win %s client %s\n", hwnd,
3722 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3724 if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3726 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3727 return TRUE;
3731 /*****************************************************************************
3732 * UpdateLayeredWindow (USER32.@)
3734 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3735 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3736 DWORD flags)
3738 UPDATELAYEREDWINDOWINFO info;
3740 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3742 SetLastError( ERROR_INVALID_PARAMETER );
3743 return FALSE;
3745 info.cbSize = sizeof(info);
3746 info.hdcDst = hdcDst;
3747 info.pptDst = pptDst;
3748 info.psize = psize;
3749 info.hdcSrc = hdcSrc;
3750 info.pptSrc = pptSrc;
3751 info.crKey = crKey;
3752 info.pblend = pblend;
3753 info.dwFlags = flags;
3754 info.prcDirty = NULL;
3755 return UpdateLayeredWindowIndirect( hwnd, &info );
3759 /******************************************************************************
3760 * GetProcessDefaultLayout [USER32.@]
3762 * Gets the default layout for parentless windows.
3764 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3766 if (!layout)
3768 SetLastError( ERROR_NOACCESS );
3769 return FALSE;
3771 if (process_layout == ~0u)
3773 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3774 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3775 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3776 '\\','%','0','4','x','%','0','4','x',
3777 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3778 WCHAR *str, buffer[MAX_PATH];
3779 DWORD i, len, version_layout = 0;
3780 DWORD user_lang = GetUserDefaultLangID();
3781 DWORD *languages;
3782 void *data = NULL;
3784 GetModuleFileNameW( 0, buffer, MAX_PATH );
3785 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3786 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3787 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3788 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3790 len /= sizeof(DWORD);
3791 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3792 if (i == len) /* try neutral language */
3793 for (i = 0; i < len; i++)
3794 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3795 if (i == len) i = 0; /* default to the first one */
3797 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3798 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3799 TRACE( "found description %s\n", debugstr_w( str ));
3800 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3802 done:
3803 HeapFree( GetProcessHeap(), 0, data );
3804 process_layout = version_layout;
3806 *layout = process_layout;
3807 return TRUE;
3811 /******************************************************************************
3812 * SetProcessDefaultLayout [USER32.@]
3814 * Sets the default layout for parentless windows.
3816 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3818 process_layout = layout;
3819 return TRUE;
3823 /* 64bit versions */
3825 #ifdef GetWindowLongPtrW
3826 #undef GetWindowLongPtrW
3827 #endif
3829 #ifdef GetWindowLongPtrA
3830 #undef GetWindowLongPtrA
3831 #endif
3833 #ifdef SetWindowLongPtrW
3834 #undef SetWindowLongPtrW
3835 #endif
3837 #ifdef SetWindowLongPtrA
3838 #undef SetWindowLongPtrA
3839 #endif
3841 /*****************************************************************************
3842 * GetWindowLongPtrW (USER32.@)
3844 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3846 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3849 /*****************************************************************************
3850 * GetWindowLongPtrA (USER32.@)
3852 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3854 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3857 /*****************************************************************************
3858 * SetWindowLongPtrW (USER32.@)
3860 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3862 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3865 /*****************************************************************************
3866 * SetWindowLongPtrA (USER32.@)
3868 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3870 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );