wined3d: Move max_ffp_textures to wined3d_d3d_info.
[wine.git] / dlls / user32 / win.c
blobdb4881a3ad944ea18b64a7c38c8df4b319633a64
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 USER_Unlock();
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 USER_Unlock();
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;
1470 SetRect( &wndPtr->normal_rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1472 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1475 * Correct the window styles.
1477 * It affects only the style loaded into the WIN structure.
1480 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1482 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1483 if (!(wndPtr->dwStyle & WS_POPUP))
1484 wndPtr->dwStyle |= WS_CAPTION;
1487 /* WS_EX_WINDOWEDGE depends on some other styles */
1488 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1489 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1490 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1492 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1493 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1494 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1496 else
1497 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1499 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1500 wndPtr->flags |= WIN_NEED_SIZE;
1502 SERVER_START_REQ( set_window_info )
1504 req->handle = wine_server_user_handle( hwnd );
1505 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1506 req->style = wndPtr->dwStyle;
1507 req->ex_style = wndPtr->dwExStyle;
1508 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1509 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1510 req->extra_offset = -1;
1511 wine_server_call( req );
1513 SERVER_END_REQ;
1515 /* Set the window menu */
1517 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1519 if (cs->hMenu)
1521 if (!MENU_SetMenu(hwnd, cs->hMenu))
1523 WIN_ReleasePtr( wndPtr );
1524 free_window_handle( hwnd );
1525 return 0;
1528 else
1530 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1531 if (menuName)
1533 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1534 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1538 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1540 /* call the WH_CBT hook */
1542 /* the window style passed to the hook must be the real window style,
1543 * rather than just the window style that the caller to CreateWindowEx
1544 * passed in, so we have to copy the original CREATESTRUCT and get the
1545 * the real style. */
1546 cbcs = *cs;
1547 cbcs.style = wndPtr->dwStyle;
1548 cbtc.lpcs = &cbcs;
1549 cbtc.hwndInsertAfter = HWND_TOP;
1550 WIN_ReleasePtr( wndPtr );
1551 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1553 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1555 cx = cs->cx;
1556 cy = cs->cy;
1557 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1559 POINT maxSize, maxPos, minTrack, maxTrack;
1560 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1561 if (maxTrack.x < cx) cx = maxTrack.x;
1562 if (maxTrack.y < cy) cy = maxTrack.y;
1563 if (minTrack.x > cx) cx = minTrack.x;
1564 if (minTrack.y > cy) cy = minTrack.y;
1567 if (cx < 0) cx = 0;
1568 if (cy < 0) cy = 0;
1569 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1570 /* check for wraparound */
1571 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1572 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1573 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1575 /* send WM_NCCREATE */
1577 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1578 if (unicode)
1579 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1580 else
1581 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1582 if (!result)
1584 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1585 goto failed;
1588 /* send WM_NCCALCSIZE */
1590 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1592 /* yes, even if the CBT hook was called with HWND_TOP */
1593 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1594 RECT client_rect = rect;
1596 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1597 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1598 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1599 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1600 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1602 else return 0;
1604 /* send WM_CREATE */
1606 if (unicode)
1607 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1608 else
1609 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1610 if (result == -1) goto failed;
1612 /* call the driver */
1614 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1616 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1618 /* send the size messages */
1620 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1621 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1622 if (!(wndPtr->flags & WIN_NEED_SIZE))
1624 WIN_ReleasePtr( wndPtr );
1625 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1626 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1627 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1628 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1630 else WIN_ReleasePtr( wndPtr );
1632 /* Show the window, maximizing or minimizing if needed */
1634 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1635 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1637 RECT newPos;
1638 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1640 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1641 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1642 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1643 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1644 newPos.bottom - newPos.top, swFlag );
1647 /* Notify the parent window only */
1649 send_parent_notify( hwnd, WM_CREATE );
1650 if (!IsWindow( hwnd )) return 0;
1652 if (cs->style & WS_VISIBLE)
1654 if (cs->style & WS_MAXIMIZE)
1655 sw = SW_SHOW;
1656 else if (cs->style & WS_MINIMIZE)
1657 sw = SW_SHOWMINIMIZED;
1659 ShowWindow( hwnd, sw );
1660 if (cs->dwExStyle & WS_EX_MDICHILD)
1662 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1663 /* ShowWindow won't activate child windows */
1664 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1668 /* Call WH_SHELL hook */
1670 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1671 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1673 TRACE("created window %p\n", hwnd);
1674 return hwnd;
1676 failed:
1677 WIN_DestroyWindow( hwnd );
1678 return 0;
1682 /***********************************************************************
1683 * CreateWindowExA (USER32.@)
1685 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1686 LPCSTR windowName, DWORD style, INT x,
1687 INT y, INT width, INT height,
1688 HWND parent, HMENU menu,
1689 HINSTANCE instance, LPVOID data )
1691 CREATESTRUCTA cs;
1693 cs.lpCreateParams = data;
1694 cs.hInstance = instance;
1695 cs.hMenu = menu;
1696 cs.hwndParent = parent;
1697 cs.x = x;
1698 cs.y = y;
1699 cs.cx = width;
1700 cs.cy = height;
1701 cs.style = style;
1702 cs.lpszName = windowName;
1703 cs.lpszClass = className;
1704 cs.dwExStyle = exStyle;
1706 if (!IS_INTRESOURCE(className))
1708 WCHAR bufferW[256];
1709 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1710 return 0;
1711 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1713 /* Note: we rely on the fact that CREATESTRUCTA and */
1714 /* CREATESTRUCTW have the same layout. */
1715 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1719 /***********************************************************************
1720 * CreateWindowExW (USER32.@)
1722 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1723 LPCWSTR windowName, DWORD style, INT x,
1724 INT y, INT width, INT height,
1725 HWND parent, HMENU menu,
1726 HINSTANCE instance, LPVOID data )
1728 CREATESTRUCTW cs;
1730 cs.lpCreateParams = data;
1731 cs.hInstance = instance;
1732 cs.hMenu = menu;
1733 cs.hwndParent = parent;
1734 cs.x = x;
1735 cs.y = y;
1736 cs.cx = width;
1737 cs.cy = height;
1738 cs.style = style;
1739 cs.lpszName = windowName;
1740 cs.lpszClass = className;
1741 cs.dwExStyle = exStyle;
1743 return wow_handlers.create_window( &cs, className, instance, TRUE );
1747 /***********************************************************************
1748 * WIN_SendDestroyMsg
1750 static void WIN_SendDestroyMsg( HWND hwnd )
1752 GUITHREADINFO info;
1754 info.cbSize = sizeof(info);
1755 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1757 if (hwnd == info.hwndCaret) DestroyCaret();
1758 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1762 * Send the WM_DESTROY to the window.
1764 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1767 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1768 * make sure that the window still exists when we come back.
1770 if (IsWindow(hwnd))
1772 HWND* pWndArray;
1773 int i;
1775 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1777 for (i = 0; pWndArray[i]; i++)
1779 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1781 HeapFree( GetProcessHeap(), 0, pWndArray );
1783 else
1784 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1788 /***********************************************************************
1789 * DestroyWindow (USER32.@)
1791 BOOL WINAPI DestroyWindow( HWND hwnd )
1793 BOOL is_child;
1795 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1797 SetLastError( ERROR_ACCESS_DENIED );
1798 return FALSE;
1801 TRACE("(%p)\n", hwnd);
1803 /* Call hooks */
1805 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1807 if (MENU_IsMenuActive() == hwnd)
1808 EndMenu();
1810 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1812 if (is_child)
1814 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1815 send_parent_notify( hwnd, WM_DESTROY );
1817 else if (!GetWindow( hwnd, GW_OWNER ))
1819 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1820 /* FIXME: clean up palette - see "Internals" p.352 */
1823 if (!IsWindow(hwnd)) return TRUE;
1825 /* Hide the window */
1826 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1828 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1829 if (is_child)
1830 ShowWindow( hwnd, SW_HIDE );
1831 else
1832 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1833 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1836 if (!IsWindow(hwnd)) return TRUE;
1838 /* Recursively destroy owned windows */
1840 if (!is_child)
1842 for (;;)
1844 int i, got_one = 0;
1845 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1846 if (list)
1848 for (i = 0; list[i]; i++)
1850 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1851 if (WIN_IsCurrentThread( list[i] ))
1853 DestroyWindow( list[i] );
1854 got_one = 1;
1855 continue;
1857 WIN_SetOwner( list[i], 0 );
1859 HeapFree( GetProcessHeap(), 0, list );
1861 if (!got_one) break;
1865 /* Send destroy messages */
1867 WIN_SendDestroyMsg( hwnd );
1868 if (!IsWindow( hwnd )) return TRUE;
1870 if (GetClipboardOwner() == hwnd)
1871 CLIPBOARD_ReleaseOwner();
1873 /* Destroy the window storage */
1875 WIN_DestroyWindow( hwnd );
1876 return TRUE;
1880 /***********************************************************************
1881 * CloseWindow (USER32.@)
1883 BOOL WINAPI CloseWindow( HWND hwnd )
1885 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1886 ShowWindow( hwnd, SW_MINIMIZE );
1887 return TRUE;
1891 /***********************************************************************
1892 * OpenIcon (USER32.@)
1894 BOOL WINAPI OpenIcon( HWND hwnd )
1896 if (!IsIconic( hwnd )) return FALSE;
1897 ShowWindow( hwnd, SW_SHOWNORMAL );
1898 return TRUE;
1902 /***********************************************************************
1903 * FindWindowExW (USER32.@)
1905 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1907 HWND *list = NULL;
1908 HWND retvalue = 0;
1909 int i = 0, len = 0;
1910 WCHAR *buffer = NULL;
1912 if (!parent && child) parent = GetDesktopWindow();
1913 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1915 if (title)
1917 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1918 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1921 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1923 if (child)
1925 child = WIN_GetFullHandle( child );
1926 while (list[i] && list[i] != child) i++;
1927 if (!list[i]) goto done;
1928 i++; /* start from next window */
1931 if (title)
1933 while (list[i])
1935 if (GetWindowTextW( list[i], buffer, len + 1 ))
1937 if (!strcmpiW( buffer, title )) break;
1939 else
1941 if (!title[0]) break;
1943 i++;
1946 retvalue = list[i];
1948 done:
1949 HeapFree( GetProcessHeap(), 0, list );
1950 HeapFree( GetProcessHeap(), 0, buffer );
1951 return retvalue;
1956 /***********************************************************************
1957 * FindWindowA (USER32.@)
1959 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1961 HWND ret = FindWindowExA( 0, 0, className, title );
1962 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1963 return ret;
1967 /***********************************************************************
1968 * FindWindowExA (USER32.@)
1970 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1972 LPWSTR titleW = NULL;
1973 HWND hwnd = 0;
1975 if (title)
1977 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1978 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1979 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1982 if (!IS_INTRESOURCE(className))
1984 WCHAR classW[256];
1985 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1986 hwnd = FindWindowExW( parent, child, classW, titleW );
1988 else
1990 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1993 HeapFree( GetProcessHeap(), 0, titleW );
1994 return hwnd;
1998 /***********************************************************************
1999 * FindWindowW (USER32.@)
2001 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2003 return FindWindowExW( 0, 0, className, title );
2007 /**********************************************************************
2008 * GetDesktopWindow (USER32.@)
2010 HWND WINAPI GetDesktopWindow(void)
2012 struct user_thread_info *thread_info = get_user_thread_info();
2014 if (thread_info->top_window) return thread_info->top_window;
2016 SERVER_START_REQ( get_desktop_window )
2018 req->force = 0;
2019 if (!wine_server_call( req ))
2021 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2022 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2025 SERVER_END_REQ;
2027 if (!thread_info->top_window)
2029 USEROBJECTFLAGS flags;
2030 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2031 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2033 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2034 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2035 STARTUPINFOW si;
2036 PROCESS_INFORMATION pi;
2037 WCHAR windir[MAX_PATH];
2038 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2039 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2040 void *redir;
2042 memset( &si, 0, sizeof(si) );
2043 si.cb = sizeof(si);
2044 si.dwFlags = STARTF_USESTDHANDLES;
2045 si.hStdInput = 0;
2046 si.hStdOutput = 0;
2047 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2049 GetSystemDirectoryW( windir, MAX_PATH );
2050 strcpyW( app, windir );
2051 strcatW( app, explorer );
2052 strcpyW( cmdline, app );
2053 strcatW( cmdline, args );
2055 Wow64DisableWow64FsRedirection( &redir );
2056 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2057 NULL, windir, &si, &pi ))
2059 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2060 WaitForInputIdle( pi.hProcess, 10000 );
2061 CloseHandle( pi.hThread );
2062 CloseHandle( pi.hProcess );
2064 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2065 Wow64RevertWow64FsRedirection( redir );
2067 else TRACE( "not starting explorer since winstation is not visible\n" );
2069 SERVER_START_REQ( get_desktop_window )
2071 req->force = 1;
2072 if (!wine_server_call( req ))
2074 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2075 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2078 SERVER_END_REQ;
2081 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2082 ERR( "failed to create desktop window\n" );
2084 return thread_info->top_window;
2088 /*******************************************************************
2089 * EnableWindow (USER32.@)
2091 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2093 BOOL retvalue;
2094 HWND full_handle;
2096 if (is_broadcast(hwnd))
2098 SetLastError( ERROR_INVALID_PARAMETER );
2099 return FALSE;
2102 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2103 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2105 hwnd = full_handle;
2107 TRACE("( %p, %d )\n", hwnd, enable);
2109 retvalue = !IsWindowEnabled( hwnd );
2111 if (enable && retvalue)
2113 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2114 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2116 else if (!enable && !retvalue)
2118 HWND capture_wnd;
2120 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2122 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2124 if (hwnd == GetFocus())
2125 SetFocus( 0 ); /* A disabled window can't have the focus */
2127 capture_wnd = GetCapture();
2128 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2129 ReleaseCapture(); /* A disabled window can't capture the mouse */
2131 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2133 return retvalue;
2137 /***********************************************************************
2138 * IsWindowEnabled (USER32.@)
2140 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2142 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2146 /***********************************************************************
2147 * IsWindowUnicode (USER32.@)
2149 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2151 WND * wndPtr;
2152 BOOL retvalue = FALSE;
2154 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2156 if (wndPtr == WND_DESKTOP) return TRUE;
2158 if (wndPtr != WND_OTHER_PROCESS)
2160 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2161 WIN_ReleasePtr( wndPtr );
2163 else
2165 SERVER_START_REQ( get_window_info )
2167 req->handle = wine_server_user_handle( hwnd );
2168 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2170 SERVER_END_REQ;
2172 return retvalue;
2176 /**********************************************************************
2177 * WIN_GetWindowLong
2179 * Helper function for GetWindowLong().
2181 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2183 LONG_PTR retvalue = 0;
2184 WND *wndPtr;
2186 if (offset == GWLP_HWNDPARENT)
2188 HWND parent = GetAncestor( hwnd, GA_PARENT );
2189 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2190 return (ULONG_PTR)parent;
2193 if (!(wndPtr = WIN_GetPtr( hwnd )))
2195 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2196 return 0;
2199 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2201 if (offset == GWLP_WNDPROC)
2203 SetLastError( ERROR_ACCESS_DENIED );
2204 return 0;
2206 SERVER_START_REQ( set_window_info )
2208 req->handle = wine_server_user_handle( hwnd );
2209 req->flags = 0; /* don't set anything, just retrieve */
2210 req->extra_offset = (offset >= 0) ? offset : -1;
2211 req->extra_size = (offset >= 0) ? size : 0;
2212 if (!wine_server_call_err( req ))
2214 switch(offset)
2216 case GWL_STYLE: retvalue = reply->old_style; break;
2217 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2218 case GWLP_ID: retvalue = reply->old_id; break;
2219 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2220 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2221 default:
2222 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2223 else SetLastError( ERROR_INVALID_INDEX );
2224 break;
2228 SERVER_END_REQ;
2229 return retvalue;
2232 /* now we have a valid wndPtr */
2234 if (offset >= 0)
2236 if (offset > (int)(wndPtr->cbWndExtra - size))
2238 WARN("Invalid offset %d\n", offset );
2239 WIN_ReleasePtr( wndPtr );
2240 SetLastError( ERROR_INVALID_INDEX );
2241 return 0;
2243 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2245 /* Special case for dialog window procedure */
2246 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2247 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2248 WIN_ReleasePtr( wndPtr );
2249 return retvalue;
2252 switch(offset)
2254 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2255 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2256 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2257 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2258 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2259 case GWLP_WNDPROC:
2260 /* This looks like a hack only for the edit control (see tests). This makes these controls
2261 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2262 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2264 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2265 retvalue = (ULONG_PTR)wndPtr->winproc;
2266 else
2267 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2268 break;
2269 default:
2270 WARN("Unknown offset %d\n", offset );
2271 SetLastError( ERROR_INVALID_INDEX );
2272 break;
2274 WIN_ReleasePtr(wndPtr);
2275 return retvalue;
2279 /**********************************************************************
2280 * WIN_SetWindowLong
2282 * Helper function for SetWindowLong().
2284 * 0 is the failure code. However, in the case of failure SetLastError
2285 * must be set to distinguish between a 0 return value and a failure.
2287 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2289 STYLESTRUCT style;
2290 BOOL ok, made_visible = FALSE;
2291 LONG_PTR retval = 0;
2292 WND *wndPtr;
2294 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2296 if (is_broadcast(hwnd))
2298 SetLastError( ERROR_INVALID_PARAMETER );
2299 return FALSE;
2302 if (!(wndPtr = WIN_GetPtr( hwnd )))
2304 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2305 return 0;
2307 if (wndPtr == WND_DESKTOP)
2309 /* can't change anything on the desktop window */
2310 SetLastError( ERROR_ACCESS_DENIED );
2311 return 0;
2313 if (wndPtr == WND_OTHER_PROCESS)
2315 if (offset == GWLP_WNDPROC)
2317 SetLastError( ERROR_ACCESS_DENIED );
2318 return 0;
2320 if (offset > 32767 || offset < -32767)
2322 SetLastError( ERROR_INVALID_INDEX );
2323 return 0;
2325 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2328 /* first some special cases */
2329 switch( offset )
2331 case GWL_STYLE:
2332 style.styleOld = wndPtr->dwStyle;
2333 style.styleNew = newval;
2334 WIN_ReleasePtr( wndPtr );
2335 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2336 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2337 newval = style.styleNew;
2338 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2339 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2340 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2341 WS_EX_WINDOWEDGE too */
2342 break;
2343 case GWL_EXSTYLE:
2344 style.styleOld = wndPtr->dwExStyle;
2345 style.styleNew = newval;
2346 WIN_ReleasePtr( wndPtr );
2347 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2348 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2349 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2350 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2351 /* WS_EX_WINDOWEDGE depends on some other styles */
2352 if (newval & WS_EX_DLGMODALFRAME)
2353 newval |= WS_EX_WINDOWEDGE;
2354 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2355 newval |= WS_EX_WINDOWEDGE;
2356 else
2357 newval &= ~WS_EX_WINDOWEDGE;
2358 break;
2359 case GWLP_HWNDPARENT:
2360 if (wndPtr->parent == GetDesktopWindow())
2362 WIN_ReleasePtr( wndPtr );
2363 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2365 else
2367 WIN_ReleasePtr( wndPtr );
2368 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2370 case GWLP_WNDPROC:
2372 WNDPROC proc;
2373 UINT old_flags = wndPtr->flags;
2374 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2375 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2376 if (proc) wndPtr->winproc = proc;
2377 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2378 else wndPtr->flags &= ~WIN_ISUNICODE;
2379 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2381 WIN_ReleasePtr( wndPtr );
2382 return retval;
2384 /* update is_unicode flag on the server side */
2385 break;
2387 case GWLP_ID:
2388 case GWLP_HINSTANCE:
2389 case GWLP_USERDATA:
2390 break;
2391 case DWLP_DLGPROC:
2392 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2393 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2395 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2396 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2397 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2398 WIN_ReleasePtr( wndPtr );
2399 return retval;
2401 /* fall through */
2402 default:
2403 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2405 WARN("Invalid offset %d\n", offset );
2406 WIN_ReleasePtr( wndPtr );
2407 SetLastError( ERROR_INVALID_INDEX );
2408 return 0;
2410 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2412 /* already set to the same value */
2413 WIN_ReleasePtr( wndPtr );
2414 return newval;
2416 break;
2419 SERVER_START_REQ( set_window_info )
2421 req->handle = wine_server_user_handle( hwnd );
2422 req->extra_offset = -1;
2423 switch(offset)
2425 case GWL_STYLE:
2426 req->flags = SET_WIN_STYLE;
2427 req->style = newval;
2428 break;
2429 case GWL_EXSTYLE:
2430 req->flags = SET_WIN_EXSTYLE;
2431 req->ex_style = newval;
2432 break;
2433 case GWLP_ID:
2434 req->flags = SET_WIN_ID;
2435 req->id = newval;
2436 break;
2437 case GWLP_HINSTANCE:
2438 req->flags = SET_WIN_INSTANCE;
2439 req->instance = wine_server_client_ptr( (void *)newval );
2440 break;
2441 case GWLP_WNDPROC:
2442 req->flags = SET_WIN_UNICODE;
2443 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2444 break;
2445 case GWLP_USERDATA:
2446 req->flags = SET_WIN_USERDATA;
2447 req->user_data = newval;
2448 break;
2449 default:
2450 req->flags = SET_WIN_EXTRA;
2451 req->extra_offset = offset;
2452 req->extra_size = size;
2453 set_win_data( &req->extra_value, newval, size );
2455 if ((ok = !wine_server_call_err( req )))
2457 switch(offset)
2459 case GWL_STYLE:
2460 wndPtr->dwStyle = newval;
2461 retval = reply->old_style;
2462 break;
2463 case GWL_EXSTYLE:
2464 wndPtr->dwExStyle = newval;
2465 retval = reply->old_ex_style;
2466 break;
2467 case GWLP_ID:
2468 wndPtr->wIDmenu = newval;
2469 retval = reply->old_id;
2470 break;
2471 case GWLP_HINSTANCE:
2472 wndPtr->hInstance = (HINSTANCE)newval;
2473 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2474 break;
2475 case GWLP_WNDPROC:
2476 break;
2477 case GWLP_USERDATA:
2478 wndPtr->userdata = newval;
2479 retval = reply->old_user_data;
2480 break;
2481 default:
2482 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2483 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2484 break;
2488 SERVER_END_REQ;
2490 if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2491 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2493 made_visible = !(wndPtr->flags & WIN_HIDDEN) && (wndPtr->dwStyle & WS_VISIBLE);
2494 invalidate_dce( wndPtr, NULL );
2496 WIN_ReleasePtr( wndPtr );
2498 if (!ok) return 0;
2500 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2502 style.styleOld = retval;
2503 style.styleNew = newval;
2504 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2505 if (made_visible) update_window_state( hwnd );
2506 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2509 return retval;
2513 /**********************************************************************
2514 * GetWindowWord (USER32.@)
2516 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2518 switch(offset)
2520 case GWLP_ID:
2521 case GWLP_HINSTANCE:
2522 case GWLP_HWNDPARENT:
2523 break;
2524 default:
2525 if (offset < 0)
2527 WARN("Invalid offset %d\n", offset );
2528 SetLastError( ERROR_INVALID_INDEX );
2529 return 0;
2531 break;
2533 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2537 /**********************************************************************
2538 * GetWindowLongA (USER32.@)
2540 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2542 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2546 /**********************************************************************
2547 * GetWindowLongW (USER32.@)
2549 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2551 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2555 /**********************************************************************
2556 * SetWindowWord (USER32.@)
2558 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2560 switch(offset)
2562 case GWLP_ID:
2563 case GWLP_HINSTANCE:
2564 case GWLP_HWNDPARENT:
2565 break;
2566 default:
2567 if (offset < 0)
2569 WARN("Invalid offset %d\n", offset );
2570 SetLastError( ERROR_INVALID_INDEX );
2571 return 0;
2573 break;
2575 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2579 /**********************************************************************
2580 * SetWindowLongA (USER32.@)
2582 * See SetWindowLongW.
2584 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2586 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2590 /**********************************************************************
2591 * SetWindowLongW (USER32.@) Set window attribute
2593 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2594 * value in a window's extra memory.
2596 * The _hwnd_ parameter specifies the window. is the handle to a
2597 * window that has extra memory. The _newval_ parameter contains the
2598 * new attribute or extra memory value. If positive, the _offset_
2599 * parameter is the byte-addressed location in the window's extra
2600 * memory to set. If negative, _offset_ specifies the window
2601 * attribute to set, and should be one of the following values:
2603 * GWL_EXSTYLE The window's extended window style
2605 * GWL_STYLE The window's window style.
2607 * GWLP_WNDPROC Pointer to the window's window procedure.
2609 * GWLP_HINSTANCE The window's pplication instance handle.
2611 * GWLP_ID The window's identifier.
2613 * GWLP_USERDATA The window's user-specified data.
2615 * If the window is a dialog box, the _offset_ parameter can be one of
2616 * the following values:
2618 * DWLP_DLGPROC The address of the window's dialog box procedure.
2620 * DWLP_MSGRESULT The return value of a message
2621 * that the dialog box procedure processed.
2623 * DWLP_USER Application specific information.
2625 * RETURNS
2627 * If successful, returns the previous value located at _offset_. Otherwise,
2628 * returns 0.
2630 * NOTES
2632 * Extra memory for a window class is specified by a nonzero cbWndExtra
2633 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2634 * time of class creation.
2636 * Using GWL_WNDPROC to set a new window procedure effectively creates
2637 * a window subclass. Use CallWindowProc() in the new windows procedure
2638 * to pass messages to the superclass's window procedure.
2640 * The user data is reserved for use by the application which created
2641 * the window.
2643 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2644 * instead, call the EnableWindow() function to change the window's
2645 * disabled state.
2647 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2648 * SetParent() instead.
2650 * Win95:
2651 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2652 * it sends WM_STYLECHANGING before changing the settings
2653 * and WM_STYLECHANGED afterwards.
2654 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2656 LONG WINAPI SetWindowLongW(
2657 HWND hwnd, /* [in] window to alter */
2658 INT offset, /* [in] offset, in bytes, of location to alter */
2659 LONG newval /* [in] new value of location */
2661 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2665 /*******************************************************************
2666 * GetWindowTextA (USER32.@)
2668 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2670 WCHAR *buffer;
2672 if (!lpString) return 0;
2674 if (WIN_IsCurrentProcess( hwnd ))
2675 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2677 /* when window belongs to other process, don't send a message */
2678 if (nMaxCount <= 0) return 0;
2679 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2680 get_server_window_text( hwnd, buffer, nMaxCount );
2681 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2682 lpString[nMaxCount-1] = 0;
2683 HeapFree( GetProcessHeap(), 0, buffer );
2684 return strlen(lpString);
2688 /*******************************************************************
2689 * InternalGetWindowText (USER32.@)
2691 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2693 WND *win;
2695 if (nMaxCount <= 0) return 0;
2696 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2697 if (win == WND_DESKTOP) lpString[0] = 0;
2698 else if (win != WND_OTHER_PROCESS)
2700 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2701 else lpString[0] = 0;
2702 WIN_ReleasePtr( win );
2704 else
2706 get_server_window_text( hwnd, lpString, nMaxCount );
2708 return strlenW(lpString);
2712 /*******************************************************************
2713 * GetWindowTextW (USER32.@)
2715 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2717 if (!lpString) return 0;
2719 if (WIN_IsCurrentProcess( hwnd ))
2720 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2722 /* when window belongs to other process, don't send a message */
2723 if (nMaxCount <= 0) return 0;
2724 get_server_window_text( hwnd, lpString, nMaxCount );
2725 return strlenW(lpString);
2729 /*******************************************************************
2730 * SetWindowTextA (USER32.@)
2731 * SetWindowText (USER32.@)
2733 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2735 if (is_broadcast(hwnd))
2737 SetLastError( ERROR_INVALID_PARAMETER );
2738 return FALSE;
2740 if (!WIN_IsCurrentProcess( hwnd ))
2741 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2742 debugstr_a(lpString), hwnd );
2743 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2747 /*******************************************************************
2748 * SetWindowTextW (USER32.@)
2750 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2752 if (is_broadcast(hwnd))
2754 SetLastError( ERROR_INVALID_PARAMETER );
2755 return FALSE;
2757 if (!WIN_IsCurrentProcess( hwnd ))
2758 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2759 debugstr_w(lpString), hwnd );
2760 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2764 /*******************************************************************
2765 * GetWindowTextLengthA (USER32.@)
2767 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2769 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2772 /*******************************************************************
2773 * GetWindowTextLengthW (USER32.@)
2775 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2777 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2781 /*******************************************************************
2782 * IsWindow (USER32.@)
2784 BOOL WINAPI IsWindow( HWND hwnd )
2786 WND *ptr;
2787 BOOL ret;
2789 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2790 if (ptr == WND_DESKTOP) return TRUE;
2792 if (ptr != WND_OTHER_PROCESS)
2794 WIN_ReleasePtr( ptr );
2795 return TRUE;
2798 /* check other processes */
2799 SERVER_START_REQ( get_window_info )
2801 req->handle = wine_server_user_handle( hwnd );
2802 ret = !wine_server_call_err( req );
2804 SERVER_END_REQ;
2805 return ret;
2809 /***********************************************************************
2810 * GetWindowThreadProcessId (USER32.@)
2812 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2814 WND *ptr;
2815 DWORD tid = 0;
2817 if (!(ptr = WIN_GetPtr( hwnd )))
2819 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2820 return 0;
2823 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2825 /* got a valid window */
2826 tid = ptr->tid;
2827 if (process) *process = GetCurrentProcessId();
2828 WIN_ReleasePtr( ptr );
2829 return tid;
2832 /* check other processes */
2833 SERVER_START_REQ( get_window_info )
2835 req->handle = wine_server_user_handle( hwnd );
2836 if (!wine_server_call_err( req ))
2838 tid = (DWORD)reply->tid;
2839 if (process) *process = (DWORD)reply->pid;
2842 SERVER_END_REQ;
2843 return tid;
2847 /*****************************************************************
2848 * GetParent (USER32.@)
2850 HWND WINAPI GetParent( HWND hwnd )
2852 WND *wndPtr;
2853 HWND retvalue = 0;
2855 if (!(wndPtr = WIN_GetPtr( hwnd )))
2857 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2858 return 0;
2860 if (wndPtr == WND_DESKTOP) return 0;
2861 if (wndPtr == WND_OTHER_PROCESS)
2863 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2864 if (style & (WS_POPUP | WS_CHILD))
2866 SERVER_START_REQ( get_window_tree )
2868 req->handle = wine_server_user_handle( hwnd );
2869 if (!wine_server_call_err( req ))
2871 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2872 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2875 SERVER_END_REQ;
2878 else
2880 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2881 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2882 WIN_ReleasePtr( wndPtr );
2884 return retvalue;
2888 /*****************************************************************
2889 * GetAncestor (USER32.@)
2891 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2893 WND *win;
2894 HWND *list, ret = 0;
2896 switch(type)
2898 case GA_PARENT:
2899 if (!(win = WIN_GetPtr( hwnd )))
2901 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2902 return 0;
2904 if (win == WND_DESKTOP) return 0;
2905 if (win != WND_OTHER_PROCESS)
2907 ret = win->parent;
2908 WIN_ReleasePtr( win );
2910 else /* need to query the server */
2912 SERVER_START_REQ( get_window_tree )
2914 req->handle = wine_server_user_handle( hwnd );
2915 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2917 SERVER_END_REQ;
2919 break;
2921 case GA_ROOT:
2922 if (!(list = list_window_parents( hwnd ))) return 0;
2924 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2925 else
2927 int count = 2;
2928 while (list[count]) count++;
2929 ret = list[count - 2]; /* get the one before the desktop */
2931 HeapFree( GetProcessHeap(), 0, list );
2932 break;
2934 case GA_ROOTOWNER:
2935 if (is_desktop_window( hwnd )) return 0;
2936 ret = WIN_GetFullHandle( hwnd );
2937 for (;;)
2939 HWND parent = GetParent( ret );
2940 if (!parent) break;
2941 ret = parent;
2943 break;
2945 return ret;
2949 /*****************************************************************
2950 * SetParent (USER32.@)
2952 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2954 HWND full_handle;
2955 HWND old_parent = 0;
2956 BOOL was_visible;
2957 WND *wndPtr;
2958 POINT pt;
2959 BOOL ret;
2961 if (is_broadcast(hwnd) || is_broadcast(parent))
2963 SetLastError(ERROR_INVALID_PARAMETER);
2964 return 0;
2967 if (!parent) parent = GetDesktopWindow();
2968 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2969 else parent = WIN_GetFullHandle( parent );
2971 if (!IsWindow( parent ))
2973 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2974 return 0;
2977 /* Some applications try to set a child as a parent */
2978 if (IsChild(hwnd, parent))
2980 SetLastError( ERROR_INVALID_PARAMETER );
2981 return 0;
2984 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2985 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2987 if (full_handle == parent)
2989 SetLastError( ERROR_INVALID_PARAMETER );
2990 return 0;
2993 /* Windows hides the window first, then shows it again
2994 * including the WM_SHOWWINDOW messages and all */
2995 was_visible = ShowWindow( hwnd, SW_HIDE );
2997 wndPtr = WIN_GetPtr( hwnd );
2998 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
3000 pt.x = wndPtr->rectWindow.left;
3001 pt.y = wndPtr->rectWindow.top;
3003 SERVER_START_REQ( set_parent )
3005 req->handle = wine_server_user_handle( hwnd );
3006 req->parent = wine_server_user_handle( parent );
3007 if ((ret = !wine_server_call( req )))
3009 old_parent = wine_server_ptr_handle( reply->old_parent );
3010 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3014 SERVER_END_REQ;
3015 WIN_ReleasePtr( wndPtr );
3016 if (!ret) return 0;
3018 USER_Driver->pSetParent( full_handle, parent, old_parent );
3020 /* SetParent additionally needs to make hwnd the topmost window
3021 in the x-order and send the expected WM_WINDOWPOSCHANGING and
3022 WM_WINDOWPOSCHANGED notification messages.
3024 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3026 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3028 return old_parent;
3032 /*******************************************************************
3033 * IsChild (USER32.@)
3035 BOOL WINAPI IsChild( HWND parent, HWND child )
3037 HWND *list = list_window_parents( child );
3038 int i;
3039 BOOL ret;
3041 if (!list) return FALSE;
3042 parent = WIN_GetFullHandle( parent );
3043 for (i = 0; list[i]; i++) if (list[i] == parent) break;
3044 ret = list[i] && list[i+1];
3045 HeapFree( GetProcessHeap(), 0, list );
3046 return ret;
3050 /***********************************************************************
3051 * IsWindowVisible (USER32.@)
3053 BOOL WINAPI IsWindowVisible( HWND hwnd )
3055 HWND *list;
3056 BOOL retval = TRUE;
3057 int i;
3059 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3060 if (!(list = list_window_parents( hwnd ))) return TRUE;
3061 if (list[0])
3063 for (i = 0; list[i+1]; i++)
3064 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3065 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3067 HeapFree( GetProcessHeap(), 0, list );
3068 return retval;
3072 /***********************************************************************
3073 * WIN_IsWindowDrawable
3075 * hwnd is drawable when it is visible, all parents are not
3076 * minimized, and it is itself not minimized unless we are
3077 * trying to draw its default class icon.
3079 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3081 HWND *list;
3082 BOOL retval = TRUE;
3083 int i;
3084 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3086 if (!(style & WS_VISIBLE)) return FALSE;
3087 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3089 if (!(list = list_window_parents( hwnd ))) return TRUE;
3090 if (list[0])
3092 for (i = 0; list[i+1]; i++)
3093 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3094 break;
3095 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3097 HeapFree( GetProcessHeap(), 0, list );
3098 return retval;
3102 /*******************************************************************
3103 * GetTopWindow (USER32.@)
3105 HWND WINAPI GetTopWindow( HWND hwnd )
3107 if (!hwnd) hwnd = GetDesktopWindow();
3108 return GetWindow( hwnd, GW_CHILD );
3112 /*******************************************************************
3113 * GetWindow (USER32.@)
3115 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3117 HWND retval = 0;
3119 if (rel == GW_OWNER) /* this one may be available locally */
3121 WND *wndPtr = WIN_GetPtr( hwnd );
3122 if (!wndPtr)
3124 SetLastError( ERROR_INVALID_HANDLE );
3125 return 0;
3127 if (wndPtr == WND_DESKTOP) return 0;
3128 if (wndPtr != WND_OTHER_PROCESS)
3130 retval = wndPtr->owner;
3131 WIN_ReleasePtr( wndPtr );
3132 return retval;
3134 /* else fall through to server call */
3137 SERVER_START_REQ( get_window_tree )
3139 req->handle = wine_server_user_handle( hwnd );
3140 if (!wine_server_call_err( req ))
3142 switch(rel)
3144 case GW_HWNDFIRST:
3145 retval = wine_server_ptr_handle( reply->first_sibling );
3146 break;
3147 case GW_HWNDLAST:
3148 retval = wine_server_ptr_handle( reply->last_sibling );
3149 break;
3150 case GW_HWNDNEXT:
3151 retval = wine_server_ptr_handle( reply->next_sibling );
3152 break;
3153 case GW_HWNDPREV:
3154 retval = wine_server_ptr_handle( reply->prev_sibling );
3155 break;
3156 case GW_OWNER:
3157 retval = wine_server_ptr_handle( reply->owner );
3158 break;
3159 case GW_CHILD:
3160 retval = wine_server_ptr_handle( reply->first_child );
3161 break;
3165 SERVER_END_REQ;
3166 return retval;
3170 /*******************************************************************
3171 * ShowOwnedPopups (USER32.@)
3173 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3175 int count = 0;
3176 WND *pWnd;
3177 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3179 if (!win_array) return TRUE;
3181 while (win_array[count]) count++;
3182 while (--count >= 0)
3184 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3185 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3186 if (pWnd == WND_OTHER_PROCESS) continue;
3187 if (fShow)
3189 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3191 WIN_ReleasePtr( pWnd );
3192 /* In Windows, ShowOwnedPopups(TRUE) generates
3193 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3194 * regardless of the state of the owner
3196 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3197 continue;
3200 else
3202 if (pWnd->dwStyle & WS_VISIBLE)
3204 WIN_ReleasePtr( pWnd );
3205 /* In Windows, ShowOwnedPopups(FALSE) generates
3206 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3207 * regardless of the state of the owner
3209 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3210 continue;
3213 WIN_ReleasePtr( pWnd );
3215 HeapFree( GetProcessHeap(), 0, win_array );
3216 return TRUE;
3220 /*******************************************************************
3221 * GetLastActivePopup (USER32.@)
3223 HWND WINAPI GetLastActivePopup( HWND hwnd )
3225 HWND retval = hwnd;
3227 SERVER_START_REQ( get_window_info )
3229 req->handle = wine_server_user_handle( hwnd );
3230 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3232 SERVER_END_REQ;
3233 return retval;
3237 /*******************************************************************
3238 * WIN_ListChildren
3240 * Build an array of the children of a given window. The array must be
3241 * freed with HeapFree. Returns NULL when no windows are found.
3243 HWND *WIN_ListChildren( HWND hwnd )
3245 if (!hwnd)
3247 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3248 return NULL;
3250 return list_window_children( 0, hwnd, NULL, 0 );
3254 /*******************************************************************
3255 * EnumWindows (USER32.@)
3257 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3259 HWND *list;
3260 BOOL ret = TRUE;
3261 int i;
3263 USER_CheckNotLock();
3265 /* We have to build a list of all windows first, to avoid */
3266 /* unpleasant side-effects, for instance if the callback */
3267 /* function changes the Z-order of the windows. */
3269 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3271 /* Now call the callback function for every window */
3273 for (i = 0; list[i]; i++)
3275 /* Make sure that the window still exists */
3276 if (!IsWindow( list[i] )) continue;
3277 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3279 HeapFree( GetProcessHeap(), 0, list );
3280 return ret;
3284 /**********************************************************************
3285 * EnumThreadWindows (USER32.@)
3287 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3289 HWND *list;
3290 int i;
3291 BOOL ret = TRUE;
3293 USER_CheckNotLock();
3295 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3297 /* Now call the callback function for every window */
3299 for (i = 0; list[i]; i++)
3300 if (!(ret = func( list[i], lParam ))) break;
3301 HeapFree( GetProcessHeap(), 0, list );
3302 return ret;
3306 /***********************************************************************
3307 * EnumDesktopWindows (USER32.@)
3309 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3311 HWND *list;
3312 int i;
3314 USER_CheckNotLock();
3316 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3318 for (i = 0; list[i]; i++)
3319 if (!func( list[i], lparam )) break;
3320 HeapFree( GetProcessHeap(), 0, list );
3321 return TRUE;
3325 /**********************************************************************
3326 * WIN_EnumChildWindows
3328 * Helper function for EnumChildWindows().
3330 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3332 HWND *childList;
3333 BOOL ret = FALSE;
3335 for ( ; *list; list++)
3337 /* Make sure that the window still exists */
3338 if (!IsWindow( *list )) continue;
3339 /* Build children list first */
3340 childList = WIN_ListChildren( *list );
3342 ret = func( *list, lParam );
3344 if (childList)
3346 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3347 HeapFree( GetProcessHeap(), 0, childList );
3349 if (!ret) return FALSE;
3351 return TRUE;
3355 /**********************************************************************
3356 * EnumChildWindows (USER32.@)
3358 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3360 HWND *list;
3361 BOOL ret;
3363 USER_CheckNotLock();
3365 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3366 ret = WIN_EnumChildWindows( list, func, lParam );
3367 HeapFree( GetProcessHeap(), 0, list );
3368 return ret;
3372 /*******************************************************************
3373 * AnyPopup (USER32.@)
3375 BOOL WINAPI AnyPopup(void)
3377 int i;
3378 BOOL retvalue;
3379 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3381 if (!list) return FALSE;
3382 for (i = 0; list[i]; i++)
3384 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3386 retvalue = (list[i] != 0);
3387 HeapFree( GetProcessHeap(), 0, list );
3388 return retvalue;
3392 /*******************************************************************
3393 * FlashWindow (USER32.@)
3395 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3397 WND *wndPtr;
3399 TRACE("%p\n", hWnd);
3401 if (IsIconic( hWnd ))
3403 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3405 wndPtr = WIN_GetPtr(hWnd);
3406 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3407 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3409 wndPtr->flags |= WIN_NCACTIVATED;
3411 else
3413 wndPtr->flags &= ~WIN_NCACTIVATED;
3415 WIN_ReleasePtr( wndPtr );
3416 return TRUE;
3418 else
3420 WPARAM wparam;
3422 wndPtr = WIN_GetPtr(hWnd);
3423 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3424 hWnd = wndPtr->obj.handle; /* make it a full handle */
3426 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3427 else wparam = (hWnd == GetForegroundWindow());
3429 WIN_ReleasePtr( wndPtr );
3430 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3431 return wparam;
3435 /*******************************************************************
3436 * FlashWindowEx (USER32.@)
3438 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3440 FIXME("%p\n", pfwi);
3441 return TRUE;
3444 /*******************************************************************
3445 * GetWindowContextHelpId (USER32.@)
3447 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3449 DWORD retval;
3450 WND *wnd = WIN_GetPtr( hwnd );
3451 if (!wnd || wnd == WND_DESKTOP) return 0;
3452 if (wnd == WND_OTHER_PROCESS)
3454 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3455 return 0;
3457 retval = wnd->helpContext;
3458 WIN_ReleasePtr( wnd );
3459 return retval;
3463 /*******************************************************************
3464 * SetWindowContextHelpId (USER32.@)
3466 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3468 WND *wnd = WIN_GetPtr( hwnd );
3469 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3470 if (wnd == WND_OTHER_PROCESS)
3472 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3473 return 0;
3475 wnd->helpContext = id;
3476 WIN_ReleasePtr( wnd );
3477 return TRUE;
3481 /*******************************************************************
3482 * DragDetect (USER32.@)
3484 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3486 MSG msg;
3487 RECT rect;
3488 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3489 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3491 rect.left = pt.x - wDragWidth;
3492 rect.right = pt.x + wDragWidth;
3494 rect.top = pt.y - wDragHeight;
3495 rect.bottom = pt.y + wDragHeight;
3497 SetCapture(hWnd);
3499 while(1)
3501 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3503 if( msg.message == WM_LBUTTONUP )
3505 ReleaseCapture();
3506 return 0;
3508 if( msg.message == WM_MOUSEMOVE )
3510 POINT tmp;
3511 tmp.x = (short)LOWORD(msg.lParam);
3512 tmp.y = (short)HIWORD(msg.lParam);
3513 if( !PtInRect( &rect, tmp ))
3515 ReleaseCapture();
3516 return 1;
3520 WaitMessage();
3522 return 0;
3525 /******************************************************************************
3526 * GetWindowModuleFileNameA (USER32.@)
3528 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3530 WND *win;
3531 HINSTANCE hinst;
3533 TRACE( "%p, %p, %u\n", hwnd, module, size );
3535 win = WIN_GetPtr( hwnd );
3536 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3538 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3539 return 0;
3541 hinst = win->hInstance;
3542 WIN_ReleasePtr( win );
3544 return GetModuleFileNameA( hinst, module, size );
3547 /******************************************************************************
3548 * GetWindowModuleFileNameW (USER32.@)
3550 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3552 WND *win;
3553 HINSTANCE hinst;
3555 TRACE( "%p, %p, %u\n", hwnd, module, size );
3557 win = WIN_GetPtr( hwnd );
3558 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3560 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3561 return 0;
3563 hinst = win->hInstance;
3564 WIN_ReleasePtr( win );
3566 return GetModuleFileNameW( hinst, module, size );
3569 /******************************************************************************
3570 * GetWindowInfo (USER32.@)
3572 * Note: tests show that Windows doesn't check cbSize of the structure.
3574 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3576 if (!pwi) return FALSE;
3577 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3579 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3580 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3581 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3583 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3584 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3586 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3587 pwi->wCreatorVersion = 0x0400;
3589 return TRUE;
3592 /******************************************************************************
3593 * SwitchDesktop (USER32.@)
3595 * NOTES: Sets the current input or interactive desktop.
3597 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3599 FIXME("(hwnd %p) stub!\n", hDesktop);
3600 return TRUE;
3604 /***********************************************************************
3605 * __wine_set_pixel_format
3607 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3609 WND *win = WIN_GetPtr( hwnd );
3611 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3613 WARN( "setting format %d on win %p not supported\n", format, hwnd );
3614 return FALSE;
3616 win->pixel_format = format;
3617 WIN_ReleasePtr( win );
3619 update_window_state( hwnd );
3620 return TRUE;
3624 /*****************************************************************************
3625 * SetLayeredWindowAttributes (USER32.@)
3627 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3629 BOOL ret;
3631 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3633 SERVER_START_REQ( set_window_layered_info )
3635 req->handle = wine_server_user_handle( hwnd );
3636 req->color_key = key;
3637 req->alpha = alpha;
3638 req->flags = flags;
3639 ret = !wine_server_call_err( req );
3641 SERVER_END_REQ;
3643 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3645 return ret;
3649 /*****************************************************************************
3650 * GetLayeredWindowAttributes (USER32.@)
3652 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3654 BOOL ret;
3656 SERVER_START_REQ( get_window_layered_info )
3658 req->handle = wine_server_user_handle( hwnd );
3659 if ((ret = !wine_server_call_err( req )))
3661 if (key) *key = reply->color_key;
3662 if (alpha) *alpha = reply->alpha;
3663 if (flags) *flags = reply->flags;
3666 SERVER_END_REQ;
3668 return ret;
3672 /*****************************************************************************
3673 * UpdateLayeredWindowIndirect (USER32.@)
3675 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3677 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3678 RECT window_rect, client_rect;
3679 SIZE offset;
3681 if (!info ||
3682 info->cbSize != sizeof(*info) ||
3683 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3684 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3685 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3687 SetLastError( ERROR_INVALID_PARAMETER );
3688 return FALSE;
3691 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3693 if (info->pptDst)
3695 offset.cx = info->pptDst->x - window_rect.left;
3696 offset.cy = info->pptDst->y - window_rect.top;
3697 OffsetRect( &client_rect, offset.cx, offset.cy );
3698 OffsetRect( &window_rect, offset.cx, offset.cy );
3699 flags &= ~SWP_NOMOVE;
3701 if (info->psize)
3703 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3704 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3705 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3707 SetLastError( ERROR_INVALID_PARAMETER );
3708 return FALSE;
3710 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3712 SetLastError( ERROR_INCORRECT_SIZE );
3713 return FALSE;
3715 client_rect.right += offset.cx;
3716 client_rect.bottom += offset.cy;
3717 window_rect.right += offset.cx;
3718 window_rect.bottom += offset.cy;
3719 flags &= ~SWP_NOSIZE;
3722 TRACE( "window %p win %s client %s\n", hwnd,
3723 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3725 if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3727 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3728 return TRUE;
3732 /*****************************************************************************
3733 * UpdateLayeredWindow (USER32.@)
3735 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3736 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3737 DWORD flags)
3739 UPDATELAYEREDWINDOWINFO info;
3741 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3743 SetLastError( ERROR_INVALID_PARAMETER );
3744 return FALSE;
3746 info.cbSize = sizeof(info);
3747 info.hdcDst = hdcDst;
3748 info.pptDst = pptDst;
3749 info.psize = psize;
3750 info.hdcSrc = hdcSrc;
3751 info.pptSrc = pptSrc;
3752 info.crKey = crKey;
3753 info.pblend = pblend;
3754 info.dwFlags = flags;
3755 info.prcDirty = NULL;
3756 return UpdateLayeredWindowIndirect( hwnd, &info );
3760 /******************************************************************************
3761 * GetProcessDefaultLayout [USER32.@]
3763 * Gets the default layout for parentless windows.
3765 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3767 if (!layout)
3769 SetLastError( ERROR_NOACCESS );
3770 return FALSE;
3772 if (process_layout == ~0u)
3774 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3775 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3776 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3777 '\\','%','0','4','x','%','0','4','x',
3778 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3779 WCHAR *str, buffer[MAX_PATH];
3780 DWORD i, len, version_layout = 0;
3781 DWORD user_lang = GetUserDefaultLangID();
3782 DWORD *languages;
3783 void *data = NULL;
3785 GetModuleFileNameW( 0, buffer, MAX_PATH );
3786 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3787 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3788 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3789 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3791 len /= sizeof(DWORD);
3792 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3793 if (i == len) /* try neutral language */
3794 for (i = 0; i < len; i++)
3795 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3796 if (i == len) i = 0; /* default to the first one */
3798 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3799 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3800 TRACE( "found description %s\n", debugstr_w( str ));
3801 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3803 done:
3804 HeapFree( GetProcessHeap(), 0, data );
3805 process_layout = version_layout;
3807 *layout = process_layout;
3808 return TRUE;
3812 /******************************************************************************
3813 * SetProcessDefaultLayout [USER32.@]
3815 * Sets the default layout for parentless windows.
3817 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3819 process_layout = layout;
3820 return TRUE;
3824 /* 64bit versions */
3826 #ifdef GetWindowLongPtrW
3827 #undef GetWindowLongPtrW
3828 #endif
3830 #ifdef GetWindowLongPtrA
3831 #undef GetWindowLongPtrA
3832 #endif
3834 #ifdef SetWindowLongPtrW
3835 #undef SetWindowLongPtrW
3836 #endif
3838 #ifdef SetWindowLongPtrA
3839 #undef SetWindowLongPtrA
3840 #endif
3842 /*****************************************************************************
3843 * GetWindowLongPtrW (USER32.@)
3845 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3847 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3850 /*****************************************************************************
3851 * GetWindowLongPtrA (USER32.@)
3853 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3855 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3858 /*****************************************************************************
3859 * SetWindowLongPtrW (USER32.@)
3861 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3863 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3866 /*****************************************************************************
3867 * SetWindowLongPtrA (USER32.@)
3869 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3871 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );