winevulkan: Avoid zero-sized allocations.
[wine.git] / dlls / user32 / win.c
blobbb7920376401fc0c8541d4867343e742922043a6
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 <assert.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <limits.h>
26 #include "user_private.h"
27 #include "winnls.h"
28 #include "winver.h"
29 #include "wine/server.h"
30 #include "wine/asm.h"
31 #include "win.h"
32 #include "controls.h"
33 #include "winerror.h"
34 #include "wine/exception.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(win);
39 static DWORD process_layout = ~0u;
42 /**********************************************************************/
44 /* helper for Get/SetWindowLong */
45 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
47 if (size == sizeof(WORD))
49 WORD ret;
50 memcpy( &ret, ptr, sizeof(ret) );
51 return ret;
53 else if (size == sizeof(DWORD))
55 DWORD ret;
56 memcpy( &ret, ptr, sizeof(ret) );
57 return ret;
59 else
61 LONG_PTR ret;
62 memcpy( &ret, ptr, sizeof(ret) );
63 return ret;
67 /* helper for Get/SetWindowLong */
68 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
70 if (size == sizeof(WORD))
72 WORD newval = val;
73 memcpy( ptr, &newval, sizeof(newval) );
75 else if (size == sizeof(DWORD))
77 DWORD newval = val;
78 memcpy( ptr, &newval, sizeof(newval) );
80 else
82 memcpy( ptr, &val, sizeof(val) );
87 /***********************************************************************
88 * alloc_user_handle
90 HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type )
92 return UlongToHandle( NtUserCallTwoParam( (UINT_PTR)ptr, type, NtUserAllocHandle ));
96 /***********************************************************************
97 * get_user_handle_ptr
99 void *get_user_handle_ptr( HANDLE handle, unsigned int type )
101 return (void *)NtUserCallTwoParam( HandleToUlong(handle), type, NtUserGetHandlePtr );
105 /***********************************************************************
106 * release_user_handle_ptr
108 void release_user_handle_ptr( void *ptr )
110 assert( ptr && ptr != OBJ_OTHER_PROCESS );
111 USER_Unlock();
115 /***********************************************************************
116 * free_user_handle
118 void *free_user_handle( HANDLE handle, unsigned int type )
120 return UlongToHandle( NtUserCallTwoParam( HandleToUlong(handle), type, NtUserFreeHandle ));
124 /***********************************************************************
125 * create_window_handle
127 * Create a window handle with the server.
129 static WND *create_window_handle( HWND parent, HWND owner, UNICODE_STRING *name,
130 HINSTANCE instance, BOOL unicode,
131 DWORD style, DWORD ex_style )
133 WND *win;
134 HWND handle = 0, full_parent = 0, full_owner = 0;
135 struct tagCLASS *class = NULL;
136 int extra_bytes = 0;
137 DPI_AWARENESS awareness = GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() );
138 UINT dpi = 0;
140 SERVER_START_REQ( create_window )
142 req->parent = wine_server_user_handle( parent );
143 req->owner = wine_server_user_handle( owner );
144 req->instance = wine_server_client_ptr( instance );
145 req->dpi = GetDpiForSystem();
146 req->awareness = awareness;
147 req->style = style;
148 req->ex_style = ex_style;
149 if (!(req->atom = get_int_atom_value( name )) && name->Length)
150 wine_server_add_data( req, name->Buffer, name->Length );
151 if (!wine_server_call_err( req ))
153 handle = wine_server_ptr_handle( reply->handle );
154 full_parent = wine_server_ptr_handle( reply->parent );
155 full_owner = wine_server_ptr_handle( reply->owner );
156 extra_bytes = reply->extra;
157 dpi = reply->dpi;
158 awareness = reply->awareness;
159 class = wine_server_get_ptr( reply->class_ptr );
162 SERVER_END_REQ;
164 if (!handle)
166 WARN( "error %d creating window\n", GetLastError() );
167 return NULL;
170 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
171 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
173 SERVER_START_REQ( destroy_window )
175 req->handle = wine_server_user_handle( handle );
176 wine_server_call( req );
178 SERVER_END_REQ;
179 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
180 return NULL;
183 if (!parent) /* if parent is 0 we don't have a desktop window yet */
185 struct user_thread_info *thread_info = get_user_thread_info();
187 if (name->Buffer == (LPCWSTR)DESKTOP_CLASS_ATOM)
189 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
190 else assert( full_parent == thread_info->top_window );
191 if (full_parent && !NtUserCallHwnd( thread_info->top_window, NtUserCreateDesktopWindow ))
192 ERR( "failed to create desktop window\n" );
193 register_builtin_classes();
195 else /* HWND_MESSAGE parent */
197 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
201 USER_Lock();
203 win->obj.handle = handle;
204 win->obj.type = NTUSER_OBJ_WINDOW;
205 win->parent = full_parent;
206 win->owner = full_owner;
207 win->class = class;
208 win->winproc = get_class_winproc( class );
209 win->cbWndExtra = extra_bytes;
210 win->dpi = dpi;
211 win->dpi_awareness = awareness;
212 NtUserCallTwoParam( HandleToUlong(handle), (UINT_PTR)win, NtUserSetHandlePtr );
213 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
214 return win;
218 /***********************************************************************
219 * free_window_handle
221 * Free a window handle.
223 static void free_window_handle( HWND hwnd )
225 struct user_object *ptr;
227 if ((ptr = get_user_handle_ptr( hwnd, NTUSER_OBJ_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
229 SERVER_START_REQ( destroy_window )
231 req->handle = wine_server_user_handle( hwnd );
232 wine_server_call( req );
233 NtUserCallTwoParam( HandleToUlong(hwnd), 0, NtUserSetHandlePtr );
235 SERVER_END_REQ;
236 USER_Unlock();
237 HeapFree( GetProcessHeap(), 0, ptr );
242 /*******************************************************************
243 * list_window_children
245 * Build an array of the children of a given window. The array must be
246 * freed with HeapFree. Returns NULL when no windows are found.
248 static HWND *list_window_children( HDESK desktop, HWND hwnd, UNICODE_STRING *class, DWORD tid )
250 HWND *list;
251 int i, size = 128;
252 ATOM atom = class ? get_int_atom_value( class ) : 0;
254 /* empty class is not the same as NULL class */
255 if (!atom && class && !class->Length) return NULL;
257 for (;;)
259 int count = 0;
261 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
263 SERVER_START_REQ( get_window_children )
265 req->desktop = wine_server_obj_handle( desktop );
266 req->parent = wine_server_user_handle( hwnd );
267 req->tid = tid;
268 req->atom = atom;
269 if (!atom && class) wine_server_add_data( req, class->Buffer, class->Length );
270 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
271 if (!wine_server_call( req )) count = reply->count;
273 SERVER_END_REQ;
274 if (count && count < size)
276 /* start from the end since HWND is potentially larger than user_handle_t */
277 for (i = count - 1; i >= 0; i--)
278 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
279 list[count] = 0;
280 return list;
282 HeapFree( GetProcessHeap(), 0, list );
283 if (!count) break;
284 size = count + 1; /* restart with a large enough buffer */
286 return NULL;
290 /*******************************************************************
291 * send_parent_notify
293 static void send_parent_notify( HWND hwnd, UINT msg )
295 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
296 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
298 HWND parent = GetParent(hwnd);
299 if (parent && parent != GetDesktopWindow())
300 SendMessageW( parent, WM_PARENTNOTIFY,
301 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
306 /*******************************************************************
307 * update_window_state
309 * Trigger an update of the window's driver state and surface.
311 void update_window_state( HWND hwnd )
313 DPI_AWARENESS_CONTEXT context;
314 RECT window_rect, client_rect, valid_rects[2];
316 if (!WIN_IsCurrentThread( hwnd ))
318 PostMessageW( hwnd, WM_WINE_UPDATEWINDOWSTATE, 0, 0 );
319 return;
322 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
323 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
324 valid_rects[0] = valid_rects[1] = client_rect;
325 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
326 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW,
327 &window_rect, &client_rect, valid_rects );
328 SetThreadDpiAwarenessContext( context );
332 /*******************************************************************
333 * get_hwnd_message_parent
335 * Return the parent for HWND_MESSAGE windows.
337 HWND get_hwnd_message_parent(void)
339 struct user_thread_info *thread_info = get_user_thread_info();
341 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
342 return thread_info->msg_window;
346 /*******************************************************************
347 * is_desktop_window
349 * Check if window is the desktop or the HWND_MESSAGE top parent.
351 BOOL is_desktop_window( HWND hwnd )
353 struct user_thread_info *thread_info = get_user_thread_info();
355 if (!hwnd) return FALSE;
356 if (hwnd == thread_info->top_window) return TRUE;
357 if (hwnd == thread_info->msg_window) return TRUE;
359 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
361 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
362 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
364 return FALSE;
368 /*******************************************************************
369 * Dummy window surface for windows that shouldn't get painted.
372 static void CDECL dummy_surface_lock( struct window_surface *window_surface )
374 /* nothing to do */
377 static void CDECL dummy_surface_unlock( struct window_surface *window_surface )
379 /* nothing to do */
382 static void *CDECL dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
384 static DWORD dummy_data;
386 info->bmiHeader.biSize = sizeof( info->bmiHeader );
387 info->bmiHeader.biWidth = dummy_surface.rect.right;
388 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
389 info->bmiHeader.biPlanes = 1;
390 info->bmiHeader.biBitCount = 32;
391 info->bmiHeader.biCompression = BI_RGB;
392 info->bmiHeader.biSizeImage = 0;
393 info->bmiHeader.biXPelsPerMeter = 0;
394 info->bmiHeader.biYPelsPerMeter = 0;
395 info->bmiHeader.biClrUsed = 0;
396 info->bmiHeader.biClrImportant = 0;
397 return &dummy_data;
400 static RECT *CDECL dummy_surface_get_bounds( struct window_surface *window_surface )
402 static RECT dummy_bounds;
403 return &dummy_bounds;
406 static void CDECL dummy_surface_set_region( struct window_surface *window_surface, HRGN region )
408 /* nothing to do */
411 static void CDECL dummy_surface_flush( struct window_surface *window_surface )
413 /* nothing to do */
416 static void CDECL dummy_surface_destroy( struct window_surface *window_surface )
418 /* nothing to do */
421 static const struct window_surface_funcs dummy_surface_funcs =
423 dummy_surface_lock,
424 dummy_surface_unlock,
425 dummy_surface_get_bitmap_info,
426 dummy_surface_get_bounds,
427 dummy_surface_set_region,
428 dummy_surface_flush,
429 dummy_surface_destroy
432 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
434 /*******************************************************************
435 * Off-screen window surface.
438 struct offscreen_window_surface
440 struct window_surface header;
441 CRITICAL_SECTION cs;
442 RECT bounds;
443 char *bits;
444 BITMAPINFO info;
447 static const struct window_surface_funcs offscreen_window_surface_funcs;
449 static inline void reset_bounds( RECT *bounds )
451 bounds->left = bounds->top = INT_MAX;
452 bounds->right = bounds->bottom = INT_MIN;
455 static struct offscreen_window_surface *impl_from_window_surface( struct window_surface *base )
457 if (!base || base->funcs != &offscreen_window_surface_funcs) return NULL;
458 return CONTAINING_RECORD( base, struct offscreen_window_surface, header );
461 static void CDECL offscreen_window_surface_lock( struct window_surface *base )
463 struct offscreen_window_surface *impl = impl_from_window_surface( base );
464 EnterCriticalSection( &impl->cs );
467 static void CDECL offscreen_window_surface_unlock( struct window_surface *base )
469 struct offscreen_window_surface *impl = impl_from_window_surface( base );
470 LeaveCriticalSection( &impl->cs );
473 static RECT *CDECL offscreen_window_surface_get_bounds( struct window_surface *base )
475 struct offscreen_window_surface *impl = impl_from_window_surface( base );
476 return &impl->bounds;
479 static void *CDECL offscreen_window_surface_get_bitmap_info( struct window_surface *base, BITMAPINFO *info )
481 struct offscreen_window_surface *impl = impl_from_window_surface( base );
482 memcpy( info, &impl->info, offsetof( BITMAPINFO, bmiColors[0] ) );
483 return impl->bits;
486 static void CDECL offscreen_window_surface_set_region( struct window_surface *base, HRGN region )
490 static void CDECL offscreen_window_surface_flush( struct window_surface *base )
492 struct offscreen_window_surface *impl = impl_from_window_surface( base );
493 base->funcs->lock( base );
494 reset_bounds( &impl->bounds );
495 base->funcs->unlock( base );
498 static void CDECL offscreen_window_surface_destroy( struct window_surface *base )
500 struct offscreen_window_surface *impl = impl_from_window_surface( base );
501 impl->cs.DebugInfo->Spare[0] = 0;
502 DeleteCriticalSection( &impl->cs );
503 free( impl );
506 static const struct window_surface_funcs offscreen_window_surface_funcs =
508 offscreen_window_surface_lock,
509 offscreen_window_surface_unlock,
510 offscreen_window_surface_get_bitmap_info,
511 offscreen_window_surface_get_bounds,
512 offscreen_window_surface_set_region,
513 offscreen_window_surface_flush,
514 offscreen_window_surface_destroy
517 void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface )
519 struct offscreen_window_surface *impl;
520 SIZE_T size;
521 RECT surface_rect = *visible_rect;
523 TRACE( "visible_rect %s, surface %p.\n", wine_dbgstr_rect( visible_rect ), surface );
525 OffsetRect( &surface_rect, -surface_rect.left, -surface_rect.top );
526 surface_rect.right = (surface_rect.right + 0x1f) & ~0x1f;
527 surface_rect.bottom = (surface_rect.bottom + 0x1f) & ~0x1f;
529 /* check that old surface is an offscreen_window_surface, or release it */
530 if ((impl = impl_from_window_surface( *surface )))
532 /* if the rect didn't change, keep the same surface */
533 if (EqualRect( &surface_rect, &impl->header.rect )) return;
534 window_surface_release( &impl->header );
536 else if (*surface) window_surface_release( *surface );
538 /* create a new window surface */
539 *surface = NULL;
540 size = surface_rect.right * surface_rect.bottom * 4;
541 if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return;
543 impl->header.funcs = &offscreen_window_surface_funcs;
544 impl->header.ref = 1;
545 impl->header.rect = surface_rect;
547 InitializeCriticalSection( &impl->cs );
548 impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
549 reset_bounds( &impl->bounds );
551 impl->bits = (char *)&impl->info.bmiColors[0];
552 impl->info.bmiHeader.biSize = sizeof( impl->info );
553 impl->info.bmiHeader.biWidth = surface_rect.right;
554 impl->info.bmiHeader.biHeight = surface_rect.bottom;
555 impl->info.bmiHeader.biPlanes = 1;
556 impl->info.bmiHeader.biBitCount = 32;
557 impl->info.bmiHeader.biCompression = BI_RGB;
558 impl->info.bmiHeader.biSizeImage = size;
560 TRACE( "created window surface %p\n", &impl->header );
562 *surface = &impl->header;
565 /*******************************************************************
566 * register_window_surface
568 * Register a window surface in the global list, possibly replacing another one.
570 void register_window_surface( struct window_surface *old, struct window_surface *new )
572 if (old == &dummy_surface) old = NULL;
573 if (new == &dummy_surface) new = NULL;
574 NtUserCallTwoParam( (UINT_PTR)old, (UINT_PTR)new, NtUserRegisterWindowSurface );
578 /*******************************************************************
579 * flush_window_surfaces
581 * Flush pending output from all window surfaces.
583 void flush_window_surfaces( BOOL idle )
585 NtUserCallOneParam( idle, NtUserFlushWindowSurfaces );
589 /***********************************************************************
590 * WIN_GetPtr
592 * Return a pointer to the WND structure if local to the process,
593 * or WND_OTHER_PROCESS if handle may be valid in other process.
594 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
596 WND *WIN_GetPtr( HWND hwnd )
598 WND *ptr;
600 if ((ptr = get_user_handle_ptr( hwnd, NTUSER_OBJ_WINDOW )) == WND_OTHER_PROCESS)
602 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
604 return ptr;
608 /***********************************************************************
609 * WIN_IsCurrentProcess
611 * Check whether a given window belongs to the current process (and return the full handle).
613 HWND WIN_IsCurrentProcess( HWND hwnd )
615 WND *ptr;
616 HWND ret;
618 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
619 ret = ptr->obj.handle;
620 WIN_ReleasePtr( ptr );
621 return ret;
625 /***********************************************************************
626 * WIN_IsCurrentThread
628 * Check whether a given window belongs to the current thread (and return the full handle).
630 HWND WIN_IsCurrentThread( HWND hwnd )
632 WND *ptr;
633 HWND ret = 0;
635 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
636 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
637 WIN_ReleasePtr( ptr );
638 return ret;
642 /***********************************************************************
643 * win_set_flags
645 * Set the flags of a window and return the previous value.
647 UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask )
649 UINT ret;
650 WND *ptr = WIN_GetPtr( hwnd );
652 if (!ptr || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
653 ret = ptr->flags;
654 ptr->flags = (ret & ~clear_mask) | set_mask;
655 WIN_ReleasePtr( ptr );
656 return ret;
660 /***********************************************************************
661 * WIN_GetFullHandle
663 * Convert a possibly truncated window handle to a full 32-bit handle.
665 HWND WIN_GetFullHandle( HWND hwnd )
667 WND *ptr;
669 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
670 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
671 /* do sign extension for -2 and -3 */
672 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
674 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
676 if (ptr == WND_DESKTOP)
678 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
679 else return get_hwnd_message_parent();
682 if (ptr != WND_OTHER_PROCESS)
684 hwnd = ptr->obj.handle;
685 WIN_ReleasePtr( ptr );
687 else /* may belong to another process */
689 SERVER_START_REQ( get_window_info )
691 req->handle = wine_server_user_handle( hwnd );
692 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
694 SERVER_END_REQ;
696 return hwnd;
700 /***********************************************************************
701 * WIN_SetOwner
703 * Change the owner of a window.
705 static HWND WIN_SetOwner( HWND hwnd, HWND owner )
707 WND *win = WIN_GetPtr( hwnd );
708 HWND ret = 0;
710 if (!win || win == WND_DESKTOP) return 0;
711 if (win == WND_OTHER_PROCESS)
713 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
714 return 0;
716 SERVER_START_REQ( set_window_owner )
718 req->handle = wine_server_user_handle( hwnd );
719 req->owner = wine_server_user_handle( owner );
720 if (!wine_server_call( req ))
722 win->owner = wine_server_ptr_handle( reply->full_owner );
723 ret = wine_server_ptr_handle( reply->prev_owner );
726 SERVER_END_REQ;
727 WIN_ReleasePtr( win );
728 return ret;
732 /***********************************************************************
733 * WIN_SetStyle
735 * Change the style of a window.
737 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
739 BOOL ok, made_visible = FALSE;
740 STYLESTRUCT style;
741 WND *win = WIN_GetPtr( hwnd );
743 if (!win || win == WND_DESKTOP) return 0;
744 if (win == WND_OTHER_PROCESS)
746 if (IsWindow(hwnd))
747 return SendMessageW(hwnd, WM_WINE_SETSTYLE, set_bits, clear_bits);
748 return 0;
750 style.styleOld = win->dwStyle;
751 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
752 if (style.styleNew == style.styleOld)
754 WIN_ReleasePtr( win );
755 return style.styleNew;
757 SERVER_START_REQ( set_window_info )
759 req->handle = wine_server_user_handle( hwnd );
760 req->flags = SET_WIN_STYLE;
761 req->style = style.styleNew;
762 req->extra_offset = -1;
763 if ((ok = !wine_server_call( req )))
765 style.styleOld = reply->old_style;
766 win->dwStyle = style.styleNew;
769 SERVER_END_REQ;
771 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
773 made_visible = (style.styleNew & WS_VISIBLE) != 0;
774 invalidate_dce( win, NULL );
776 WIN_ReleasePtr( win );
778 if (!ok) return 0;
780 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
781 if (made_visible) update_window_state( hwnd );
783 return style.styleOld;
787 /***********************************************************************
788 * WIN_GetRectangles
790 * Get the window and client rectangles.
792 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
794 WND *win = WIN_GetPtr( hwnd );
795 BOOL ret = TRUE;
797 if (!win)
799 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
800 return FALSE;
802 if (win == WND_DESKTOP)
804 RECT rect;
805 rect.left = rect.top = 0;
806 if (hwnd == get_hwnd_message_parent())
808 rect.right = 100;
809 rect.bottom = 100;
810 rect = rect_win_to_thread_dpi( hwnd, rect );
812 else
814 rect = get_primary_monitor_rect();
816 if (rectWindow) *rectWindow = rect;
817 if (rectClient) *rectClient = rect;
818 return TRUE;
820 if (win != WND_OTHER_PROCESS)
822 RECT window_rect = win->window_rect, client_rect = win->client_rect;
824 switch (relative)
826 case COORDS_CLIENT:
827 OffsetRect( &window_rect, -win->client_rect.left, -win->client_rect.top );
828 OffsetRect( &client_rect, -win->client_rect.left, -win->client_rect.top );
829 if (win->dwExStyle & WS_EX_LAYOUTRTL)
830 mirror_rect( &win->client_rect, &window_rect );
831 break;
832 case COORDS_WINDOW:
833 OffsetRect( &window_rect, -win->window_rect.left, -win->window_rect.top );
834 OffsetRect( &client_rect, -win->window_rect.left, -win->window_rect.top );
835 if (win->dwExStyle & WS_EX_LAYOUTRTL)
836 mirror_rect( &win->window_rect, &client_rect );
837 break;
838 case COORDS_PARENT:
839 if (win->parent)
841 WND *parent = WIN_GetPtr( win->parent );
842 if (parent == WND_DESKTOP) break;
843 if (!parent || parent == WND_OTHER_PROCESS)
845 WIN_ReleasePtr( win );
846 goto other_process;
848 if (parent->flags & WIN_CHILDREN_MOVED)
850 WIN_ReleasePtr( parent );
851 WIN_ReleasePtr( win );
852 goto other_process;
854 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
856 mirror_rect( &parent->client_rect, &window_rect );
857 mirror_rect( &parent->client_rect, &client_rect );
859 WIN_ReleasePtr( parent );
861 break;
862 case COORDS_SCREEN:
863 while (win->parent)
865 WND *parent = WIN_GetPtr( win->parent );
866 if (parent == WND_DESKTOP) break;
867 if (!parent || parent == WND_OTHER_PROCESS)
869 WIN_ReleasePtr( win );
870 goto other_process;
872 WIN_ReleasePtr( win );
873 if (parent->flags & WIN_CHILDREN_MOVED)
875 WIN_ReleasePtr( parent );
876 goto other_process;
878 win = parent;
879 if (win->parent)
881 OffsetRect( &window_rect, win->client_rect.left, win->client_rect.top );
882 OffsetRect( &client_rect, win->client_rect.left, win->client_rect.top );
885 break;
887 if (rectWindow) *rectWindow = rect_win_to_thread_dpi( hwnd, window_rect );
888 if (rectClient) *rectClient = rect_win_to_thread_dpi( hwnd, client_rect );
889 WIN_ReleasePtr( win );
890 return TRUE;
893 other_process:
894 SERVER_START_REQ( get_window_rectangles )
896 req->handle = wine_server_user_handle( hwnd );
897 req->relative = relative;
898 req->dpi = get_thread_dpi();
899 if ((ret = !wine_server_call_err( req )))
901 if (rectWindow)
903 rectWindow->left = reply->window.left;
904 rectWindow->top = reply->window.top;
905 rectWindow->right = reply->window.right;
906 rectWindow->bottom = reply->window.bottom;
908 if (rectClient)
910 rectClient->left = reply->client.left;
911 rectClient->top = reply->client.top;
912 rectClient->right = reply->client.right;
913 rectClient->bottom = reply->client.bottom;
917 SERVER_END_REQ;
918 return ret;
922 /***********************************************************************
923 * WIN_DestroyWindow
925 * Destroy storage associated to a window. "Internals" p.358
927 LRESULT WIN_DestroyWindow( HWND hwnd )
929 WND *wndPtr;
930 HWND *list;
931 HMENU menu = 0, sys_menu;
932 struct window_surface *surface;
934 TRACE("%p\n", hwnd );
936 /* destroy default IME window */
937 if (win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)
939 TRACE("unregister IME window for %p\n", hwnd);
940 imm_unregister_window( 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 SendNotifyMessageW( 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 HeapFree( GetProcessHeap(), 0, wndPtr->text );
980 wndPtr->text = NULL;
981 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
982 wndPtr->pScroll = NULL;
983 DestroyIcon( wndPtr->hIconSmall2 );
984 surface = wndPtr->surface;
985 wndPtr->surface = NULL;
986 WIN_ReleasePtr( wndPtr );
988 if (menu) DestroyMenu( menu );
989 if (sys_menu) DestroyMenu( sys_menu );
990 if (surface)
992 register_window_surface( surface, NULL );
993 window_surface_release( surface );
996 USER_Driver->pDestroyWindow( hwnd );
998 free_window_handle( hwnd );
999 return 0;
1003 /***********************************************************************
1004 * next_thread_window
1006 static WND *next_thread_window( HWND *hwnd )
1008 return (WND *)NtUserCallOneParam( (UINT_PTR)hwnd, NtUserNextThreadWindow );
1012 /***********************************************************************
1013 * destroy_thread_windows
1015 * Destroy all window owned by the current thread.
1017 void destroy_thread_windows(void)
1019 WND *win, *free_list = NULL, **free_list_ptr = &free_list;
1020 HWND hwnd = 0;
1022 USER_Lock();
1023 while ((win = next_thread_window( &hwnd )))
1025 free_dce( win->dce, win->obj.handle );
1026 NtUserCallTwoParam( HandleToUlong(hwnd), 0, NtUserSetHandlePtr );
1027 win->obj.handle = *free_list_ptr;
1028 free_list_ptr = (WND **)&win->obj.handle;
1030 if (free_list)
1032 SERVER_START_REQ( destroy_window )
1034 req->handle = 0; /* destroy all thread windows */
1035 wine_server_call( req );
1037 SERVER_END_REQ;
1039 USER_Unlock();
1041 while ((win = free_list))
1043 free_list = win->obj.handle;
1044 TRACE( "destroying %p\n", win );
1046 if ((win->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD && win->wIDmenu)
1047 DestroyMenu( UlongToHandle(win->wIDmenu) );
1048 if (win->hSysMenu) DestroyMenu( win->hSysMenu );
1049 if (win->surface)
1051 register_window_surface( win->surface, NULL );
1052 window_surface_release( win->surface );
1054 HeapFree( GetProcessHeap(), 0, win );
1059 /***********************************************************************
1060 * WIN_FixCoordinates
1062 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1063 * returns default show mode in sw.
1065 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1067 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1068 POINT pos[2];
1070 if (cs->dwExStyle & WS_EX_MDICHILD)
1072 UINT id = 0;
1074 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1075 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1077 TRACE("MDI child id %04x\n", id);
1080 if (cs->style & (WS_CHILD | WS_POPUP))
1082 if (cs->dwExStyle & WS_EX_MDICHILD)
1084 if (IS_DEFAULT(cs->x))
1086 cs->x = pos[0].x;
1087 cs->y = pos[0].y;
1089 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1090 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1092 else
1094 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1095 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1098 else /* overlapped window */
1100 HMONITOR monitor;
1101 MONITORINFO mon_info;
1102 STARTUPINFOW info;
1104 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1106 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1107 mon_info.cbSize = sizeof(mon_info);
1108 GetMonitorInfoW( monitor, &mon_info );
1109 GetStartupInfoW( &info );
1111 if (IS_DEFAULT(cs->x))
1113 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1114 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1115 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1118 if (IS_DEFAULT(cs->cx))
1120 if (info.dwFlags & STARTF_USESIZE)
1122 cs->cx = info.dwXSize;
1123 cs->cy = info.dwYSize;
1125 else
1127 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1128 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1131 /* neither x nor cx are default. Check the y values .
1132 * In the trace we see Outlook and Outlook Express using
1133 * cy set to CW_USEDEFAULT when opening the address book.
1135 else if (IS_DEFAULT(cs->cy))
1137 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1138 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1141 #undef IS_DEFAULT
1144 /***********************************************************************
1145 * dump_window_styles
1147 static void dump_window_styles( DWORD style, DWORD exstyle )
1149 TRACE( "style:" );
1150 if(style & WS_POPUP) TRACE(" WS_POPUP");
1151 if(style & WS_CHILD) TRACE(" WS_CHILD");
1152 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1153 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1154 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1155 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1156 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1157 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1158 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1159 else
1161 if(style & WS_BORDER) TRACE(" WS_BORDER");
1162 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1164 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1165 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1166 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1167 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1168 if (style & WS_CHILD)
1170 if(style & WS_GROUP) TRACE(" WS_GROUP");
1171 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1173 else
1175 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1176 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1179 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1180 #define DUMPED_STYLES \
1181 ((DWORD)(WS_POPUP | \
1182 WS_CHILD | \
1183 WS_MINIMIZE | \
1184 WS_VISIBLE | \
1185 WS_DISABLED | \
1186 WS_CLIPSIBLINGS | \
1187 WS_CLIPCHILDREN | \
1188 WS_MAXIMIZE | \
1189 WS_BORDER | \
1190 WS_DLGFRAME | \
1191 WS_VSCROLL | \
1192 WS_HSCROLL | \
1193 WS_SYSMENU | \
1194 WS_THICKFRAME | \
1195 WS_GROUP | \
1196 WS_TABSTOP | \
1197 WS_MINIMIZEBOX | \
1198 WS_MAXIMIZEBOX))
1200 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1201 TRACE("\n");
1202 #undef DUMPED_STYLES
1204 TRACE( "exstyle:" );
1205 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1206 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1207 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1208 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1209 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1210 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1211 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1212 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1213 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1214 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1215 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1216 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1217 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1218 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1219 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1220 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1221 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1222 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1223 if(exstyle & WS_EX_NOINHERITLAYOUT) TRACE(" WS_EX_NOINHERITLAYOUT");
1224 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1225 if(exstyle & WS_EX_COMPOSITED) TRACE(" WS_EX_COMPOSITED");
1226 if(exstyle & WS_EX_NOACTIVATE) TRACE(" WS_EX_NOACTIVATE");
1228 #define DUMPED_EX_STYLES \
1229 ((DWORD)(WS_EX_DLGMODALFRAME | \
1230 WS_EX_DRAGDETECT | \
1231 WS_EX_NOPARENTNOTIFY | \
1232 WS_EX_TOPMOST | \
1233 WS_EX_ACCEPTFILES | \
1234 WS_EX_TRANSPARENT | \
1235 WS_EX_MDICHILD | \
1236 WS_EX_TOOLWINDOW | \
1237 WS_EX_WINDOWEDGE | \
1238 WS_EX_CLIENTEDGE | \
1239 WS_EX_CONTEXTHELP | \
1240 WS_EX_RIGHT | \
1241 WS_EX_RTLREADING | \
1242 WS_EX_LEFTSCROLLBAR | \
1243 WS_EX_CONTROLPARENT | \
1244 WS_EX_STATICEDGE | \
1245 WS_EX_APPWINDOW | \
1246 WS_EX_LAYERED | \
1247 WS_EX_NOINHERITLAYOUT | \
1248 WS_EX_LAYOUTRTL | \
1249 WS_EX_COMPOSITED |\
1250 WS_EX_NOACTIVATE))
1252 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1253 TRACE("\n");
1254 #undef DUMPED_EX_STYLES
1257 /***********************************************************************
1258 * map_dpi_create_struct
1260 static void map_dpi_create_struct( CREATESTRUCTW *cs, UINT dpi_from, UINT dpi_to )
1262 if (!dpi_from && !dpi_to) return;
1263 if (!dpi_from || !dpi_to)
1265 POINT pt = { cs->x, cs->y };
1266 UINT mon_dpi = get_monitor_dpi( MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ));
1267 if (!dpi_from) dpi_from = mon_dpi;
1268 else dpi_to = mon_dpi;
1270 if (dpi_from == dpi_to) return;
1271 cs->x = MulDiv( cs->x, dpi_to, dpi_from );
1272 cs->y = MulDiv( cs->y, dpi_to, dpi_from );
1273 cs->cx = MulDiv( cs->cx, dpi_to, dpi_from );
1274 cs->cy = MulDiv( cs->cy, dpi_to, dpi_from );
1277 /***********************************************************************
1278 * fix_exstyle
1280 static DWORD fix_exstyle( DWORD style, DWORD exstyle )
1282 if ((exstyle & WS_EX_DLGMODALFRAME) ||
1283 (!(exstyle & WS_EX_STATICEDGE) &&
1284 (style & (WS_DLGFRAME | WS_THICKFRAME))))
1285 exstyle |= WS_EX_WINDOWEDGE;
1286 else
1287 exstyle &= ~WS_EX_WINDOWEDGE;
1288 return exstyle;
1291 /***********************************************************************
1292 * WIN_CreateWindowEx
1294 * Implementation of CreateWindowEx().
1296 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1298 INT cx, cy, style, ex_style, sw = SW_SHOW;
1299 LRESULT result;
1300 RECT rect;
1301 WND *wndPtr;
1302 HWND hwnd, parent, owner, top_child = 0;
1303 UINT win_dpi, thread_dpi = get_thread_dpi();
1304 DPI_AWARENESS_CONTEXT context;
1305 MDICREATESTRUCTW mdi_cs;
1306 UNICODE_STRING class;
1307 CBT_CREATEWNDW cbtc;
1308 CREATESTRUCTW cbcs;
1310 if (!get_class_info( module, className, NULL, &class, FALSE )) return FALSE;
1312 TRACE("%s %s%s%s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1313 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1314 debugstr_w(className), class.Buffer != className ? "->" : "",
1315 class.Buffer != className ? debugstr_wn(class.Buffer, class.Length / sizeof(WCHAR)) : "",
1316 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1317 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1318 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1320 /* Fix the styles for MDI children */
1321 if (cs->dwExStyle & WS_EX_MDICHILD)
1323 if (!(win_get_flags( cs->hwndParent ) & WIN_ISMDICLIENT))
1325 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1326 return 0;
1329 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1330 * MDICREATESTRUCT members have the originally passed values.
1332 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1333 * have the same layout.
1335 mdi_cs.szClass = cs->lpszClass;
1336 mdi_cs.szTitle = cs->lpszName;
1337 mdi_cs.hOwner = cs->hInstance;
1338 mdi_cs.x = cs->x;
1339 mdi_cs.y = cs->y;
1340 mdi_cs.cx = cs->cx;
1341 mdi_cs.cy = cs->cy;
1342 mdi_cs.style = cs->style;
1343 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1345 cs->lpCreateParams = &mdi_cs;
1347 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1349 if (cs->style & WS_POPUP)
1351 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1352 return 0;
1354 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1356 else
1358 cs->style &= ~WS_POPUP;
1359 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1360 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1363 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1365 if (top_child)
1367 /* Restore current maximized child */
1368 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1370 TRACE("Restoring current maximized child %p\n", top_child);
1371 if (cs->style & WS_MAXIMIZE)
1373 /* if the new window is maximized don't bother repainting */
1374 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1375 ShowWindow( top_child, SW_SHOWNORMAL );
1376 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1378 else ShowWindow( top_child, SW_SHOWNORMAL );
1383 /* Find the parent window */
1385 parent = cs->hwndParent;
1386 owner = 0;
1388 if (cs->hwndParent == HWND_MESSAGE)
1390 cs->hwndParent = parent = get_hwnd_message_parent();
1392 else if (cs->hwndParent)
1394 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1396 parent = GetDesktopWindow();
1397 owner = cs->hwndParent;
1399 else
1401 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1402 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1403 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1406 else
1408 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1410 WARN("No parent for child window\n" );
1411 SetLastError(ERROR_TLW_WITH_WSCHILD);
1412 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1415 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1416 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1417 (IS_INTRESOURCE(className) || wcsicmp( className, L"Message" )))
1419 DWORD layout;
1420 GetProcessDefaultLayout( &layout );
1421 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1422 parent = GetDesktopWindow();
1426 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1427 cs->dwExStyle = fix_exstyle(cs->style, cs->dwExStyle);
1429 /* Create the window structure */
1431 style = cs->style & ~WS_VISIBLE;
1432 ex_style = cs->dwExStyle & ~WS_EX_LAYERED;
1433 if (!(wndPtr = create_window_handle( parent, owner, &class, module,
1434 unicode, style, ex_style )))
1435 return 0;
1436 hwnd = wndPtr->obj.handle;
1438 /* Fill the window structure */
1440 wndPtr->tid = GetCurrentThreadId();
1441 wndPtr->hInstance = cs->hInstance;
1442 wndPtr->text = NULL;
1443 wndPtr->dwStyle = style;
1444 wndPtr->dwExStyle = ex_style;
1445 wndPtr->wIDmenu = 0;
1446 wndPtr->helpContext = 0;
1447 wndPtr->pScroll = NULL;
1448 wndPtr->userdata = 0;
1449 wndPtr->hIcon = 0;
1450 wndPtr->hIconSmall = 0;
1451 wndPtr->hIconSmall2 = 0;
1452 wndPtr->hSysMenu = 0;
1454 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1455 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1456 SetRect( &wndPtr->normal_rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1458 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1460 /* call the WH_CBT hook */
1462 WIN_ReleasePtr( wndPtr );
1463 cbcs = *cs;
1464 cbtc.lpcs = &cbcs;
1465 cbtc.hwndInsertAfter = HWND_TOP;
1466 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode ) ||
1467 !(wndPtr = WIN_GetPtr( hwnd )))
1469 free_window_handle( hwnd );
1470 return 0;
1474 * Correct the window styles.
1476 * It affects only the style loaded into the WIN structure.
1479 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1481 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1482 if (!(wndPtr->dwStyle & WS_POPUP))
1483 wndPtr->dwStyle |= WS_CAPTION;
1486 wndPtr->dwExStyle = cs->dwExStyle;
1487 /* WS_EX_WINDOWEDGE depends on some other styles */
1488 if ((wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)) &&
1489 !(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1490 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1492 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1493 wndPtr->flags |= WIN_NEED_SIZE;
1495 SERVER_START_REQ( set_window_info )
1497 req->handle = wine_server_user_handle( hwnd );
1498 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1499 req->style = wndPtr->dwStyle;
1500 req->ex_style = wndPtr->dwExStyle;
1501 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1502 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1503 req->extra_offset = -1;
1504 wine_server_call( req );
1506 SERVER_END_REQ;
1508 /* Set the window menu */
1510 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1512 if (cs->hMenu)
1514 if (!MENU_SetMenu(hwnd, cs->hMenu))
1516 WIN_ReleasePtr( wndPtr );
1517 free_window_handle( hwnd );
1518 return 0;
1521 else
1523 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1524 if (menuName)
1526 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1527 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1531 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1533 win_dpi = wndPtr->dpi;
1534 WIN_ReleasePtr( wndPtr );
1536 if (parent) map_dpi_create_struct( cs, thread_dpi, win_dpi );
1538 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1540 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1542 cx = cs->cx;
1543 cy = cs->cy;
1544 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1546 MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd );
1547 cx = max( min( cx, info.ptMaxTrackSize.x ), info.ptMinTrackSize.x );
1548 cy = max( min( cy, info.ptMaxTrackSize.y ), info.ptMinTrackSize.y );
1551 if (cx < 0) cx = 0;
1552 if (cy < 0) cy = 0;
1553 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1554 /* check for wraparound */
1555 if (cs->x > 0x7fffffff - cx) rect.right = 0x7fffffff;
1556 if (cs->y > 0x7fffffff - cy) rect.bottom = 0x7fffffff;
1557 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1559 /* send WM_NCCREATE */
1561 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd, cs->x, cs->y, cs->cx, cs->cy, wine_dbgstr_rect(&rect) );
1562 if (unicode)
1563 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1564 else
1565 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1566 if (!result)
1568 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1569 goto failed;
1572 /* create default IME window */
1574 if (imm_register_window && !is_desktop_window( hwnd ) &&
1575 parent != get_hwnd_message_parent() && imm_register_window( hwnd ))
1577 TRACE("register IME window for %p\n", hwnd);
1578 win_set_flags( hwnd, WIN_HAS_IME_WIN, 0 );
1581 /* send WM_NCCALCSIZE */
1583 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1585 /* yes, even if the CBT hook was called with HWND_TOP */
1586 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1587 RECT client_rect = rect;
1589 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1590 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1591 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1592 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1593 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1595 else goto failed;
1597 /* send WM_CREATE */
1599 if (unicode)
1600 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1601 else
1602 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1603 if (result == -1) goto failed;
1605 /* call the driver */
1607 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1609 NtUserNotifyWinEvent( EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0 );
1611 /* send the size messages */
1613 if (!(win_get_flags( hwnd ) & WIN_NEED_SIZE))
1615 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1616 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1617 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1618 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1621 /* Show the window, maximizing or minimizing if needed */
1623 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1624 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1626 RECT newPos;
1627 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1629 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1630 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1631 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1632 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1633 newPos.bottom - newPos.top, swFlag );
1636 /* Notify the parent window only */
1638 send_parent_notify( hwnd, WM_CREATE );
1639 if (!IsWindow( hwnd ))
1641 SetThreadDpiAwarenessContext( context );
1642 return 0;
1645 if (parent == GetDesktopWindow())
1646 PostMessageW( parent, WM_PARENTNOTIFY, WM_CREATE, (LPARAM)hwnd );
1648 if (cs->style & WS_VISIBLE)
1650 if (cs->style & WS_MAXIMIZE)
1651 sw = SW_SHOW;
1652 else if (cs->style & WS_MINIMIZE)
1653 sw = SW_SHOWMINIMIZED;
1655 ShowWindow( hwnd, sw );
1656 if (cs->dwExStyle & WS_EX_MDICHILD)
1658 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1659 /* ShowWindow won't activate child windows */
1660 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1664 /* Call WH_SHELL hook */
1666 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1667 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1669 TRACE("created window %p\n", hwnd);
1670 SetThreadDpiAwarenessContext( context );
1671 return hwnd;
1673 failed:
1674 WIN_DestroyWindow( hwnd );
1675 SetThreadDpiAwarenessContext( context );
1676 return 0;
1680 /***********************************************************************
1681 * CreateWindowExA (USER32.@)
1683 HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExA( DWORD exStyle, LPCSTR className,
1684 LPCSTR windowName, DWORD style, INT x,
1685 INT y, INT width, INT height,
1686 HWND parent, HMENU menu,
1687 HINSTANCE instance, LPVOID data )
1689 CREATESTRUCTA cs;
1691 cs.lpCreateParams = data;
1692 cs.hInstance = instance;
1693 cs.hMenu = menu;
1694 cs.hwndParent = parent;
1695 cs.x = x;
1696 cs.y = y;
1697 cs.cx = width;
1698 cs.cy = height;
1699 cs.style = style;
1700 cs.lpszName = windowName;
1701 cs.lpszClass = className;
1702 cs.dwExStyle = exStyle;
1704 if (!IS_INTRESOURCE(className))
1706 WCHAR bufferW[256];
1707 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, ARRAY_SIZE( bufferW )))
1708 return 0;
1709 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1711 /* Note: we rely on the fact that CREATESTRUCTA and */
1712 /* CREATESTRUCTW have the same layout. */
1713 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1717 /***********************************************************************
1718 * CreateWindowExW (USER32.@)
1720 HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
1721 LPCWSTR windowName, DWORD style, INT x,
1722 INT y, INT width, INT height,
1723 HWND parent, HMENU menu,
1724 HINSTANCE instance, LPVOID data )
1726 CREATESTRUCTW cs;
1728 cs.lpCreateParams = data;
1729 cs.hInstance = instance;
1730 cs.hMenu = menu;
1731 cs.hwndParent = parent;
1732 cs.x = x;
1733 cs.y = y;
1734 cs.cx = width;
1735 cs.cy = height;
1736 cs.style = style;
1737 cs.lpszName = windowName;
1738 cs.lpszClass = className;
1739 cs.dwExStyle = exStyle;
1741 return wow_handlers.create_window( &cs, className, instance, TRUE );
1745 /***********************************************************************
1746 * WIN_SendDestroyMsg
1748 static void WIN_SendDestroyMsg( HWND hwnd )
1750 GUITHREADINFO info;
1752 info.cbSize = sizeof(info);
1753 if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ))
1755 if (hwnd == info.hwndCaret) DestroyCaret();
1756 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1759 if (hwnd == NtUserGetClipboardOwner()) CLIPBOARD_ReleaseOwner( 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;
1845 BOOL got_one = FALSE;
1846 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1847 if (list)
1849 for (i = 0; list[i]; i++)
1851 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1852 if (WIN_IsCurrentThread( list[i] ))
1854 DestroyWindow( list[i] );
1855 got_one = TRUE;
1856 continue;
1858 WIN_SetOwner( list[i], 0 );
1860 HeapFree( GetProcessHeap(), 0, list );
1862 if (!got_one) break;
1866 /* Send destroy messages */
1868 WIN_SendDestroyMsg( hwnd );
1869 if (!IsWindow( hwnd )) return TRUE;
1871 /* Destroy the window storage */
1873 WIN_DestroyWindow( hwnd );
1874 return TRUE;
1878 /***********************************************************************
1879 * CloseWindow (USER32.@)
1881 BOOL WINAPI CloseWindow( HWND hwnd )
1883 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1884 ShowWindow( hwnd, SW_MINIMIZE );
1885 return TRUE;
1889 /***********************************************************************
1890 * OpenIcon (USER32.@)
1892 BOOL WINAPI OpenIcon( HWND hwnd )
1894 if (!IsIconic( hwnd )) return FALSE;
1895 ShowWindow( hwnd, SW_SHOWNORMAL );
1896 return TRUE;
1900 /***********************************************************************
1901 * FindWindowExW (USER32.@)
1903 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1905 HWND *list;
1906 HWND retvalue = 0;
1907 int i = 0, len = 0;
1908 WCHAR *buffer = NULL;
1910 if (!parent && child) parent = GetDesktopWindow();
1911 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1913 if (title)
1915 len = lstrlenW(title) + 1; /* one extra char to check for chars beyond the end */
1916 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1919 if (className)
1921 UNICODE_STRING str;
1922 if (IS_INTRESOURCE(className))
1924 str.Buffer = (WCHAR *)className;
1925 str.Length = str.MaximumLength = 0;
1927 else RtlInitUnicodeString( &str, className );
1928 list = list_window_children( 0, parent, &str, 0 );
1930 else list = list_window_children( 0, parent, NULL, 0 );
1931 if (!list) goto done;
1933 if (child)
1935 child = WIN_GetFullHandle( child );
1936 while (list[i] && list[i] != child) i++;
1937 if (!list[i]) goto done;
1938 i++; /* start from next window */
1941 if (title)
1943 while (list[i])
1945 if (NtUserInternalGetWindowText( list[i], buffer, len + 1 ))
1947 if (!wcsicmp( buffer, title )) break;
1949 else
1951 if (!title[0]) break;
1953 i++;
1956 retvalue = list[i];
1958 done:
1959 HeapFree( GetProcessHeap(), 0, list );
1960 HeapFree( GetProcessHeap(), 0, buffer );
1961 return retvalue;
1966 /***********************************************************************
1967 * FindWindowA (USER32.@)
1969 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1971 HWND ret = FindWindowExA( 0, 0, className, title );
1972 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1973 return ret;
1977 /***********************************************************************
1978 * FindWindowExA (USER32.@)
1980 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1982 LPWSTR titleW = NULL;
1983 HWND hwnd = 0;
1985 if (title)
1987 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1988 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1989 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1992 if (!IS_INTRESOURCE(className))
1994 WCHAR classW[256];
1995 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, ARRAY_SIZE( classW )))
1996 hwnd = FindWindowExW( parent, child, classW, titleW );
1998 else
2000 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
2003 HeapFree( GetProcessHeap(), 0, titleW );
2004 return hwnd;
2008 /***********************************************************************
2009 * FindWindowW (USER32.@)
2011 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2013 return FindWindowExW( 0, 0, className, title );
2017 /**********************************************************************
2018 * GetDesktopWindow (USER32.@)
2020 HWND WINAPI GetDesktopWindow(void)
2022 struct user_thread_info *thread_info = get_user_thread_info();
2024 if (thread_info->top_window) return thread_info->top_window;
2025 return UlongToHandle( NtUserCallNoParam( NtUserGetDesktopWindow ));
2029 /*******************************************************************
2030 * EnableWindow (USER32.@)
2032 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2034 BOOL retvalue;
2036 if (is_broadcast(hwnd))
2038 SetLastError( ERROR_INVALID_PARAMETER );
2039 return FALSE;
2042 TRACE("( %p, %d )\n", hwnd, enable);
2044 if (enable)
2046 retvalue = (WIN_SetStyle( hwnd, 0, WS_DISABLED ) & WS_DISABLED) != 0;
2047 if (retvalue) SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2049 else
2051 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
2053 retvalue = (WIN_SetStyle( hwnd, WS_DISABLED, 0 ) & WS_DISABLED) != 0;
2054 if (!retvalue)
2056 if (hwnd == GetFocus())
2057 SetFocus( 0 ); /* A disabled window can't have the focus */
2059 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2062 return retvalue;
2066 /***********************************************************************
2067 * IsWindowEnabled (USER32.@)
2069 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2071 LONG ret;
2073 SetLastError(NO_ERROR);
2074 ret = GetWindowLongW( hWnd, GWL_STYLE );
2075 if (!ret && GetLastError() != NO_ERROR) return FALSE;
2076 return !(ret & WS_DISABLED);
2079 /***********************************************************************
2080 * IsWindowUnicode (USER32.@)
2082 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2084 return NtUserCallHwnd( hwnd, NtUserIsWindowUnicode );
2088 /***********************************************************************
2089 * GetWindowDpiAwarenessContext (USER32.@)
2091 DPI_AWARENESS_CONTEXT WINAPI GetWindowDpiAwarenessContext( HWND hwnd )
2093 return (DPI_AWARENESS_CONTEXT)NtUserCallHwnd( hwnd, NtUserGetWindowDpiAwarenessContext );
2097 /***********************************************************************
2098 * GetDpiForWindow (USER32.@)
2100 UINT WINAPI GetDpiForWindow( HWND hwnd )
2102 return NtUserCallHwnd( hwnd, NtUserGetDpiForWindow );
2106 /**********************************************************************
2107 * WIN_SetWindowLong
2109 * Helper function for SetWindowLong().
2111 * 0 is the failure code. However, in the case of failure SetLastError
2112 * must be set to distinguish between a 0 return value and a failure.
2114 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2116 STYLESTRUCT style;
2117 BOOL ok, made_visible = FALSE;
2118 LONG_PTR retval = 0;
2119 WND *wndPtr;
2121 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2123 if (is_broadcast(hwnd))
2125 SetLastError( ERROR_INVALID_PARAMETER );
2126 return FALSE;
2129 if (!(wndPtr = WIN_GetPtr( hwnd )))
2131 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2132 return 0;
2134 if (wndPtr == WND_DESKTOP)
2136 /* can't change anything on the desktop window */
2137 SetLastError( ERROR_ACCESS_DENIED );
2138 return 0;
2140 if (wndPtr == WND_OTHER_PROCESS)
2142 if (offset == GWLP_WNDPROC)
2144 SetLastError( ERROR_ACCESS_DENIED );
2145 return 0;
2147 if (offset > 32767 || offset < -32767)
2149 SetLastError( ERROR_INVALID_INDEX );
2150 return 0;
2152 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2155 /* first some special cases */
2156 switch( offset )
2158 case GWL_STYLE:
2159 style.styleOld = wndPtr->dwStyle;
2160 style.styleNew = newval;
2161 WIN_ReleasePtr( wndPtr );
2162 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2163 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2164 newval = style.styleNew;
2165 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2166 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2167 /* WS_MINIMIZE can't be reset */
2168 if (wndPtr->dwStyle & WS_MINIMIZE) newval |= WS_MINIMIZE;
2169 break;
2170 case GWL_EXSTYLE:
2171 style.styleOld = wndPtr->dwExStyle;
2172 style.styleNew = newval;
2173 WIN_ReleasePtr( wndPtr );
2174 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2175 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2176 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2177 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2178 newval = fix_exstyle(wndPtr->dwStyle, newval);
2179 break;
2180 case GWLP_HWNDPARENT:
2181 if (wndPtr->parent == GetDesktopWindow())
2183 WIN_ReleasePtr( wndPtr );
2184 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2186 else
2188 WIN_ReleasePtr( wndPtr );
2189 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2191 case GWLP_WNDPROC:
2193 WNDPROC proc;
2194 UINT old_flags = wndPtr->flags;
2195 retval = unicode ? GetWindowLongPtrW( hwnd, offset ) : GetWindowLongPtrA( hwnd, offset );
2196 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2197 if (proc) wndPtr->winproc = proc;
2198 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2199 else wndPtr->flags &= ~WIN_ISUNICODE;
2200 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2202 WIN_ReleasePtr( wndPtr );
2203 return retval;
2205 /* update is_unicode flag on the server side */
2206 break;
2208 case GWLP_ID:
2209 case GWLP_HINSTANCE:
2210 case GWLP_USERDATA:
2211 break;
2212 case DWLP_DLGPROC:
2213 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2214 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2216 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2217 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2218 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2219 WIN_ReleasePtr( wndPtr );
2220 return retval;
2222 /* fall through */
2223 default:
2224 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2226 WARN("Invalid offset %d\n", offset );
2227 WIN_ReleasePtr( wndPtr );
2228 SetLastError( ERROR_INVALID_INDEX );
2229 return 0;
2231 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2233 /* already set to the same value */
2234 WIN_ReleasePtr( wndPtr );
2235 return newval;
2237 break;
2240 SERVER_START_REQ( set_window_info )
2242 req->handle = wine_server_user_handle( hwnd );
2243 req->extra_offset = -1;
2244 switch(offset)
2246 case GWL_STYLE:
2247 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE;
2248 req->style = newval;
2249 req->ex_style = fix_exstyle(newval, wndPtr->dwExStyle);
2250 break;
2251 case GWL_EXSTYLE:
2252 req->flags = SET_WIN_EXSTYLE;
2253 req->ex_style = newval;
2254 break;
2255 case GWLP_ID:
2256 req->flags = SET_WIN_ID;
2257 req->extra_value = newval;
2258 break;
2259 case GWLP_HINSTANCE:
2260 req->flags = SET_WIN_INSTANCE;
2261 req->instance = wine_server_client_ptr( (void *)newval );
2262 break;
2263 case GWLP_WNDPROC:
2264 req->flags = SET_WIN_UNICODE;
2265 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2266 break;
2267 case GWLP_USERDATA:
2268 req->flags = SET_WIN_USERDATA;
2269 req->user_data = newval;
2270 break;
2271 default:
2272 req->flags = SET_WIN_EXTRA;
2273 req->extra_offset = offset;
2274 req->extra_size = size;
2275 set_win_data( &req->extra_value, newval, size );
2277 if ((ok = !wine_server_call_err( req )))
2279 switch(offset)
2281 case GWL_STYLE:
2282 wndPtr->dwStyle = newval;
2283 wndPtr->dwExStyle = fix_exstyle(wndPtr->dwStyle, wndPtr->dwExStyle);
2284 retval = reply->old_style;
2285 break;
2286 case GWL_EXSTYLE:
2287 wndPtr->dwExStyle = newval;
2288 retval = reply->old_ex_style;
2289 break;
2290 case GWLP_ID:
2291 wndPtr->wIDmenu = newval;
2292 retval = reply->old_id;
2293 break;
2294 case GWLP_HINSTANCE:
2295 wndPtr->hInstance = (HINSTANCE)newval;
2296 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2297 break;
2298 case GWLP_WNDPROC:
2299 break;
2300 case GWLP_USERDATA:
2301 wndPtr->userdata = newval;
2302 retval = reply->old_user_data;
2303 break;
2304 default:
2305 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2306 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2307 break;
2311 SERVER_END_REQ;
2313 if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2314 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2316 made_visible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
2317 invalidate_dce( wndPtr, NULL );
2319 WIN_ReleasePtr( wndPtr );
2321 if (!ok) return 0;
2323 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2325 style.styleOld = retval;
2326 style.styleNew = newval;
2327 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2328 if (made_visible) update_window_state( hwnd );
2329 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2332 return retval;
2336 /**********************************************************************
2337 * GetWindowWord (USER32.@)
2339 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2341 return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowWord );
2345 /**********************************************************************
2346 * GetWindowLongA (USER32.@)
2348 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2350 switch (offset)
2352 #ifdef _WIN64
2353 case GWLP_WNDPROC:
2354 case GWLP_HINSTANCE:
2355 case GWLP_HWNDPARENT:
2356 WARN( "Invalid offset %d\n", offset );
2357 SetLastError( ERROR_INVALID_INDEX );
2358 return 0;
2359 #endif
2360 default:
2361 return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongA );
2366 /**********************************************************************
2367 * GetWindowLongW (USER32.@)
2369 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2371 switch (offset)
2373 #ifdef _WIN64
2374 case GWLP_WNDPROC:
2375 case GWLP_HINSTANCE:
2376 case GWLP_HWNDPARENT:
2377 WARN( "Invalid offset %d\n", offset );
2378 SetLastError( ERROR_INVALID_INDEX );
2379 return 0;
2380 #endif
2381 default:
2382 return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongW );
2387 /**********************************************************************
2388 * SetWindowWord (USER32.@)
2390 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2392 switch(offset)
2394 case GWLP_ID:
2395 case GWLP_HINSTANCE:
2396 case GWLP_HWNDPARENT:
2397 break;
2398 default:
2399 if (offset < 0)
2401 WARN("Invalid offset %d\n", offset );
2402 SetLastError( ERROR_INVALID_INDEX );
2403 return 0;
2405 break;
2407 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2411 /**********************************************************************
2412 * SetWindowLongA (USER32.@)
2414 * See SetWindowLongW.
2416 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2418 switch (offset)
2420 #ifdef _WIN64
2421 case GWLP_WNDPROC:
2422 case GWLP_HINSTANCE:
2423 case GWLP_HWNDPARENT:
2424 WARN( "Invalid offset %d\n", offset );
2425 SetLastError( ERROR_INVALID_INDEX );
2426 return 0;
2427 #endif
2428 default:
2429 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2434 /**********************************************************************
2435 * SetWindowLongW (USER32.@) Set window attribute
2437 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2438 * value in a window's extra memory.
2440 * The _hwnd_ parameter specifies the handle to a window that
2441 * has extra memory. The _newval_ parameter contains the new
2442 * attribute or extra memory value. If positive, the _offset_
2443 * parameter is the byte-addressed location in the window's extra
2444 * memory to set. If negative, _offset_ specifies the window
2445 * attribute to set, and should be one of the following values:
2447 * GWL_EXSTYLE The window's extended window style
2449 * GWL_STYLE The window's window style.
2451 * GWLP_WNDPROC Pointer to the window's window procedure.
2453 * GWLP_HINSTANCE The window's application instance handle.
2455 * GWLP_ID The window's identifier.
2457 * GWLP_USERDATA The window's user-specified data.
2459 * If the window is a dialog box, the _offset_ parameter can be one of
2460 * the following values:
2462 * DWLP_DLGPROC The address of the window's dialog box procedure.
2464 * DWLP_MSGRESULT The return value of a message
2465 * that the dialog box procedure processed.
2467 * DWLP_USER Application specific information.
2469 * RETURNS
2471 * If successful, returns the previous value located at _offset_. Otherwise,
2472 * returns 0.
2474 * NOTES
2476 * Extra memory for a window class is specified by a nonzero cbWndExtra
2477 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2478 * time of class creation.
2480 * Using GWL_WNDPROC to set a new window procedure effectively creates
2481 * a window subclass. Use CallWindowProc() in the new windows procedure
2482 * to pass messages to the superclass's window procedure.
2484 * The user data is reserved for use by the application which created
2485 * the window.
2487 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2488 * instead, call the EnableWindow() function to change the window's
2489 * disabled state.
2491 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2492 * SetParent() instead.
2494 * Win95:
2495 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2496 * it sends WM_STYLECHANGING before changing the settings
2497 * and WM_STYLECHANGED afterwards.
2498 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2500 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongW(
2501 HWND hwnd, /* [in] window to alter */
2502 INT offset, /* [in] offset, in bytes, of location to alter */
2503 LONG newval /* [in] new value of location */
2506 switch (offset)
2508 #ifdef _WIN64
2509 case GWLP_WNDPROC:
2510 case GWLP_HINSTANCE:
2511 case GWLP_HWNDPARENT:
2512 WARN("Invalid offset %d\n", offset );
2513 SetLastError( ERROR_INVALID_INDEX );
2514 return 0;
2515 #endif
2516 default:
2517 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2522 /*******************************************************************
2523 * GetWindowTextA (USER32.@)
2525 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2527 WCHAR *buffer;
2528 int ret = 0;
2530 if (!lpString || nMaxCount <= 0) return 0;
2532 __TRY
2534 lpString[0] = 0;
2536 if (WIN_IsCurrentProcess( hwnd ))
2538 ret = (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2540 else if ((buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) )))
2542 /* when window belongs to other process, don't send a message */
2543 NtUserInternalGetWindowText( hwnd, buffer, nMaxCount );
2544 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2545 lpString[nMaxCount-1] = 0;
2546 HeapFree( GetProcessHeap(), 0, buffer );
2547 ret = strlen(lpString);
2550 __EXCEPT_PAGE_FAULT
2552 ret = 0;
2554 __ENDTRY
2556 return ret;
2560 /*******************************************************************
2561 * GetWindowTextW (USER32.@)
2563 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2565 int ret;
2567 if (!lpString || nMaxCount <= 0) return 0;
2569 __TRY
2571 lpString[0] = 0;
2573 if (WIN_IsCurrentProcess( hwnd ))
2575 ret = (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2577 else
2579 /* when window belongs to other process, don't send a message */
2580 ret = NtUserInternalGetWindowText( hwnd, lpString, nMaxCount );
2583 __EXCEPT_PAGE_FAULT
2585 ret = 0;
2587 __ENDTRY
2589 return ret;
2593 /*******************************************************************
2594 * SetWindowTextA (USER32.@)
2595 * SetWindowText (USER32.@)
2597 BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextA( HWND hwnd, LPCSTR lpString )
2599 if (is_broadcast(hwnd))
2601 SetLastError( ERROR_INVALID_PARAMETER );
2602 return FALSE;
2604 if (!WIN_IsCurrentProcess( hwnd ))
2605 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2606 debugstr_a(lpString), hwnd );
2607 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2611 /*******************************************************************
2612 * SetWindowTextW (USER32.@)
2614 BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2616 if (is_broadcast(hwnd))
2618 SetLastError( ERROR_INVALID_PARAMETER );
2619 return FALSE;
2621 if (!WIN_IsCurrentProcess( hwnd ))
2622 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2623 debugstr_w(lpString), hwnd );
2624 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2628 /*******************************************************************
2629 * GetWindowTextLengthA (USER32.@)
2631 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2633 CPINFO info;
2635 if (WIN_IsCurrentProcess( hwnd )) return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2637 /* when window belongs to other process, don't send a message */
2638 GetCPInfo( CP_ACP, &info );
2639 return NtUserCallHwnd( hwnd, NtUserGetWindowTextLength ) * info.MaxCharSize;
2642 /*******************************************************************
2643 * GetWindowTextLengthW (USER32.@)
2645 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2647 if (WIN_IsCurrentProcess( hwnd )) return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2649 /* when window belongs to other process, don't send a message */
2650 return NtUserCallHwnd( hwnd, NtUserGetWindowTextLength );
2654 /*******************************************************************
2655 * IsWindow (USER32.@)
2657 BOOL WINAPI IsWindow( HWND hwnd )
2659 return NtUserCallHwnd( hwnd, NtUserIsWindow );
2663 /***********************************************************************
2664 * GetWindowThreadProcessId (USER32.@)
2666 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2668 return NtUserCallHwndParam( hwnd, (UINT_PTR)process, NtUserGetWindowThread );
2672 /*****************************************************************
2673 * GetParent (USER32.@)
2675 HWND WINAPI GetParent( HWND hwnd )
2677 return UlongToHandle( NtUserCallHwnd( hwnd, NtUserGetParent ));
2681 /*****************************************************************
2682 * SetParent (USER32.@)
2684 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2686 WINDOWPOS winpos;
2687 HWND full_handle;
2688 HWND old_parent = 0;
2689 BOOL was_visible;
2690 WND *wndPtr;
2691 BOOL ret;
2692 DPI_AWARENESS_CONTEXT context;
2693 RECT window_rect, old_screen_rect, new_screen_rect;
2695 TRACE("(%p %p)\n", hwnd, parent);
2697 if (is_broadcast(hwnd) || is_broadcast(parent))
2699 SetLastError(ERROR_INVALID_PARAMETER);
2700 return 0;
2703 if (!parent) parent = GetDesktopWindow();
2704 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2705 else parent = WIN_GetFullHandle( parent );
2707 if (!IsWindow( parent ))
2709 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2710 return 0;
2713 /* Some applications try to set a child as a parent */
2714 if (IsChild(hwnd, parent))
2716 SetLastError( ERROR_INVALID_PARAMETER );
2717 return 0;
2720 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2721 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2723 if (full_handle == parent)
2725 SetLastError( ERROR_INVALID_PARAMETER );
2726 return 0;
2729 /* Windows hides the window first, then shows it again
2730 * including the WM_SHOWWINDOW messages and all */
2731 was_visible = ShowWindow( hwnd, SW_HIDE );
2733 wndPtr = WIN_GetPtr( hwnd );
2734 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2736 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
2737 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, NULL );
2738 SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
2739 WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_screen_rect, NULL );
2740 SetThreadDpiAwarenessContext( context );
2742 SERVER_START_REQ( set_parent )
2744 req->handle = wine_server_user_handle( hwnd );
2745 req->parent = wine_server_user_handle( parent );
2746 if ((ret = !wine_server_call_err( req )))
2748 old_parent = wine_server_ptr_handle( reply->old_parent );
2749 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2750 wndPtr->dpi = reply->dpi;
2751 wndPtr->dpi_awareness = reply->awareness;
2755 SERVER_END_REQ;
2756 WIN_ReleasePtr( wndPtr );
2757 if (!ret) return 0;
2759 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
2760 WIN_GetRectangles( hwnd, COORDS_SCREEN, &new_screen_rect, NULL );
2761 SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
2763 USER_Driver->pSetParent( full_handle, parent, old_parent );
2765 winpos.hwnd = hwnd;
2766 winpos.hwndInsertAfter = HWND_TOP;
2767 winpos.x = window_rect.left;
2768 winpos.y = window_rect.top;
2769 winpos.cx = 0;
2770 winpos.cy = 0;
2771 winpos.flags = SWP_NOSIZE;
2773 USER_SetWindowPos( &winpos, new_screen_rect.left - old_screen_rect.left,
2774 new_screen_rect.top - old_screen_rect.top );
2776 if (was_visible) ShowWindow( hwnd, SW_SHOW );
2778 SetThreadDpiAwarenessContext( context );
2779 return old_parent;
2783 /*******************************************************************
2784 * IsChild (USER32.@)
2786 BOOL WINAPI IsChild( HWND parent, HWND child )
2788 return NtUserCallHwndParam( parent, HandleToUlong(child), NtUserIsChild );
2792 /***********************************************************************
2793 * IsWindowVisible (USER32.@)
2795 BOOL WINAPI IsWindowVisible( HWND hwnd )
2797 return NtUserCallHwnd( hwnd, NtUserIsWindowVisible );
2801 /***********************************************************************
2802 * WIN_IsWindowDrawable
2804 * hwnd is drawable when it is visible, all parents are not
2805 * minimized, and it is itself not minimized unless we are
2806 * trying to draw its default class icon.
2808 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2810 /* FIXME: move callers to win32u */
2811 return NtUserCallHwndParam( hwnd, icon, NtUserIsWindowDrawable );
2815 /*******************************************************************
2816 * GetTopWindow (USER32.@)
2818 HWND WINAPI GetTopWindow( HWND hwnd )
2820 if (!hwnd) hwnd = GetDesktopWindow();
2821 return GetWindow( hwnd, GW_CHILD );
2825 /*******************************************************************
2826 * GetWindow (USER32.@)
2828 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2830 return UlongToHandle( NtUserCallHwndParam( hwnd, rel, NtUserGetWindowRelative ));
2834 /*******************************************************************
2835 * ShowOwnedPopups (USER32.@)
2837 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2839 int count = 0;
2840 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2842 if (!win_array) return TRUE;
2844 while (win_array[count]) count++;
2845 while (--count >= 0)
2847 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2848 if (fShow)
2850 if (win_get_flags( win_array[count] ) & WIN_NEEDS_SHOW_OWNEDPOPUP)
2851 /* In Windows, ShowOwnedPopups(TRUE) generates
2852 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2853 * regardless of the state of the owner
2855 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2857 else
2859 if (GetWindowLongW( win_array[count], GWL_STYLE ) & WS_VISIBLE)
2860 /* In Windows, ShowOwnedPopups(FALSE) generates
2861 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2862 * regardless of the state of the owner
2864 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2867 HeapFree( GetProcessHeap(), 0, win_array );
2868 return TRUE;
2872 /*******************************************************************
2873 * GetLastActivePopup (USER32.@)
2875 HWND WINAPI GetLastActivePopup( HWND hwnd )
2877 HWND retval = hwnd;
2879 SERVER_START_REQ( get_window_info )
2881 req->handle = wine_server_user_handle( hwnd );
2882 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2884 SERVER_END_REQ;
2885 return retval;
2889 /*******************************************************************
2890 * WIN_ListChildren
2892 * Build an array of the children of a given window. The array must be
2893 * freed with HeapFree. Returns NULL when no windows are found.
2895 HWND *WIN_ListChildren( HWND hwnd )
2897 if (!hwnd)
2899 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2900 return NULL;
2902 return list_window_children( 0, hwnd, NULL, 0 );
2906 /*******************************************************************
2907 * EnumWindows (USER32.@)
2909 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2911 HWND *list;
2912 BOOL ret = TRUE;
2913 int i;
2915 USER_CheckNotLock();
2917 /* We have to build a list of all windows first, to avoid */
2918 /* unpleasant side-effects, for instance if the callback */
2919 /* function changes the Z-order of the windows. */
2921 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2923 /* Now call the callback function for every window */
2925 for (i = 0; list[i]; i++)
2927 /* Make sure that the window still exists */
2928 if (!IsWindow( list[i] )) continue;
2929 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2931 HeapFree( GetProcessHeap(), 0, list );
2932 return ret;
2936 /**********************************************************************
2937 * EnumThreadWindows (USER32.@)
2939 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2941 HWND *list;
2942 int i;
2943 BOOL ret = TRUE;
2945 USER_CheckNotLock();
2947 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
2949 /* Now call the callback function for every window */
2951 for (i = 0; list[i]; i++)
2952 if (!(ret = func( list[i], lParam ))) break;
2953 HeapFree( GetProcessHeap(), 0, list );
2954 return ret;
2958 /***********************************************************************
2959 * EnumDesktopWindows (USER32.@)
2961 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
2963 HWND *list;
2964 int i;
2966 USER_CheckNotLock();
2968 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
2970 for (i = 0; list[i]; i++)
2971 if (!func( list[i], lparam )) break;
2972 HeapFree( GetProcessHeap(), 0, list );
2973 return TRUE;
2977 #ifdef __i386__
2978 /* Some apps pass a non-stdcall proc to EnumChildWindows,
2979 * so we need a small assembly wrapper to call the proc.
2981 extern LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam );
2982 __ASM_GLOBAL_FUNC( enum_callback_wrapper,
2983 "pushl %ebp\n\t"
2984 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
2985 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2986 "movl %esp,%ebp\n\t"
2987 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
2988 "pushl 16(%ebp)\n\t"
2989 "pushl 12(%ebp)\n\t"
2990 "call *8(%ebp)\n\t"
2991 "leave\n\t"
2992 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
2993 __ASM_CFI(".cfi_same_value %ebp\n\t")
2994 "ret" )
2995 #else
2996 static inline LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam )
2998 return proc( hwnd, lparam );
3000 #endif /* __i386__ */
3002 /**********************************************************************
3003 * WIN_EnumChildWindows
3005 * Helper function for EnumChildWindows().
3007 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3009 HWND *childList;
3010 BOOL ret = FALSE;
3012 for ( ; *list; list++)
3014 /* Make sure that the window still exists */
3015 if (!IsWindow( *list )) continue;
3016 /* Build children list first */
3017 childList = WIN_ListChildren( *list );
3019 ret = enum_callback_wrapper( func, *list, lParam );
3021 if (childList)
3023 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3024 HeapFree( GetProcessHeap(), 0, childList );
3026 if (!ret) return FALSE;
3028 return TRUE;
3032 /**********************************************************************
3033 * EnumChildWindows (USER32.@)
3035 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3037 HWND *list;
3038 BOOL ret;
3040 USER_CheckNotLock();
3042 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3043 ret = WIN_EnumChildWindows( list, func, lParam );
3044 HeapFree( GetProcessHeap(), 0, list );
3045 return ret;
3049 /*******************************************************************
3050 * AnyPopup (USER32.@)
3052 BOOL WINAPI AnyPopup(void)
3054 int i;
3055 BOOL retvalue;
3056 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3058 if (!list) return FALSE;
3059 for (i = 0; list[i]; i++)
3061 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3063 retvalue = (list[i] != 0);
3064 HeapFree( GetProcessHeap(), 0, list );
3065 return retvalue;
3069 /*******************************************************************
3070 * FlashWindow (USER32.@)
3072 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3074 FLASHWINFO finfo;
3076 finfo.cbSize = sizeof(FLASHWINFO);
3077 finfo.dwFlags = bInvert ? FLASHW_ALL : FLASHW_STOP;
3078 finfo.uCount = 1;
3079 finfo.dwTimeout = 0;
3080 finfo.hwnd = hWnd;
3081 return NtUserFlashWindowEx( &finfo );
3085 /*******************************************************************
3086 * GetWindowContextHelpId (USER32.@)
3088 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3090 DWORD retval;
3091 WND *wnd = WIN_GetPtr( hwnd );
3092 if (!wnd || wnd == WND_DESKTOP) return 0;
3093 if (wnd == WND_OTHER_PROCESS)
3095 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3096 return 0;
3098 retval = wnd->helpContext;
3099 WIN_ReleasePtr( wnd );
3100 return retval;
3104 /*******************************************************************
3105 * SetWindowContextHelpId (USER32.@)
3107 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3109 WND *wnd = WIN_GetPtr( hwnd );
3110 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3111 if (wnd == WND_OTHER_PROCESS)
3113 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3114 return FALSE;
3116 wnd->helpContext = id;
3117 WIN_ReleasePtr( wnd );
3118 return TRUE;
3122 /*******************************************************************
3123 * DragDetect (USER32.@)
3125 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3127 MSG msg;
3128 RECT rect;
3129 WORD wDragWidth, wDragHeight;
3131 TRACE( "%p,%s\n", hWnd, wine_dbgstr_point( &pt ) );
3133 if (!(NtUserGetKeyState( VK_LBUTTON ) & 0x8000))
3134 return FALSE;
3136 wDragWidth = GetSystemMetrics(SM_CXDRAG);
3137 wDragHeight= GetSystemMetrics(SM_CYDRAG);
3138 SetRect(&rect, pt.x - wDragWidth, pt.y - wDragHeight, pt.x + wDragWidth, pt.y + wDragHeight);
3140 SetCapture(hWnd);
3142 while(1)
3144 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3146 if( msg.message == WM_LBUTTONUP )
3148 ReleaseCapture();
3149 return FALSE;
3151 if( msg.message == WM_MOUSEMOVE )
3153 POINT tmp;
3154 tmp.x = (short)LOWORD(msg.lParam);
3155 tmp.y = (short)HIWORD(msg.lParam);
3156 if( !PtInRect( &rect, tmp ))
3158 ReleaseCapture();
3159 return TRUE;
3163 WaitMessage();
3165 return FALSE;
3168 /******************************************************************************
3169 * GetWindowModuleFileNameA (USER32.@)
3171 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3173 WND *win;
3174 HINSTANCE hinst;
3176 TRACE( "%p, %p, %u\n", hwnd, module, size );
3178 win = WIN_GetPtr( hwnd );
3179 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3181 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3182 return 0;
3184 hinst = win->hInstance;
3185 WIN_ReleasePtr( win );
3187 return GetModuleFileNameA( hinst, module, size );
3190 /******************************************************************************
3191 * GetWindowModuleFileNameW (USER32.@)
3193 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3195 WND *win;
3196 HINSTANCE hinst;
3198 TRACE( "%p, %p, %u\n", hwnd, module, size );
3200 win = WIN_GetPtr( hwnd );
3201 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3203 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3204 return 0;
3206 hinst = win->hInstance;
3207 WIN_ReleasePtr( win );
3209 return GetModuleFileNameW( hinst, module, size );
3212 /******************************************************************************
3213 * GetWindowInfo (USER32.@)
3215 * Note: tests show that Windows doesn't check cbSize of the structure.
3217 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, WINDOWINFO *info )
3219 return NtUserCallHwndParam( hwnd, (UINT_PTR)info, NtUserGetWindowInfo );
3222 /******************************************************************************
3223 * SwitchDesktop (USER32.@)
3225 * NOTES: Sets the current input or interactive desktop.
3227 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3229 FIXME("(hwnd %p) stub!\n", hDesktop);
3230 return TRUE;
3234 /***********************************************************************
3235 * __wine_set_pixel_format
3237 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3239 WND *win = WIN_GetPtr( hwnd );
3241 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3243 WARN( "setting format %d on win %p not supported\n", format, hwnd );
3244 return FALSE;
3246 win->pixel_format = format;
3247 WIN_ReleasePtr( win );
3249 update_window_state( hwnd );
3250 return TRUE;
3254 /*****************************************************************************
3255 * SetLayeredWindowAttributes (USER32.@)
3257 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3259 BOOL ret;
3261 TRACE("(%p,%08x,%d,%x)\n", hwnd, key, alpha, flags);
3263 SERVER_START_REQ( set_window_layered_info )
3265 req->handle = wine_server_user_handle( hwnd );
3266 req->color_key = key;
3267 req->alpha = alpha;
3268 req->flags = flags;
3269 ret = !wine_server_call_err( req );
3271 SERVER_END_REQ;
3273 if (ret)
3275 USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3276 update_window_state( hwnd );
3279 return ret;
3283 /*****************************************************************************
3284 * UpdateLayeredWindowIndirect (USER32.@)
3286 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3288 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3289 RECT window_rect, client_rect;
3290 SIZE offset;
3292 if (!info ||
3293 info->cbSize != sizeof(*info) ||
3294 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3295 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3296 NtUserGetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3298 SetLastError( ERROR_INVALID_PARAMETER );
3299 return FALSE;
3302 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3304 if (info->pptDst)
3306 offset.cx = info->pptDst->x - window_rect.left;
3307 offset.cy = info->pptDst->y - window_rect.top;
3308 OffsetRect( &client_rect, offset.cx, offset.cy );
3309 OffsetRect( &window_rect, offset.cx, offset.cy );
3310 flags &= ~SWP_NOMOVE;
3312 if (info->psize)
3314 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3315 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3316 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3318 SetLastError( ERROR_INVALID_PARAMETER );
3319 return FALSE;
3321 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3323 SetLastError( ERROR_INCORRECT_SIZE );
3324 return FALSE;
3326 client_rect.right += offset.cx;
3327 client_rect.bottom += offset.cy;
3328 window_rect.right += offset.cx;
3329 window_rect.bottom += offset.cy;
3330 flags &= ~SWP_NOSIZE;
3333 TRACE( "window %p win %s client %s\n", hwnd,
3334 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3336 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3337 return USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect );
3341 /*****************************************************************************
3342 * UpdateLayeredWindow (USER32.@)
3344 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3345 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3346 DWORD flags)
3348 UPDATELAYEREDWINDOWINFO info;
3350 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3352 SetLastError( ERROR_INVALID_PARAMETER );
3353 return FALSE;
3355 info.cbSize = sizeof(info);
3356 info.hdcDst = hdcDst;
3357 info.pptDst = pptDst;
3358 info.psize = psize;
3359 info.hdcSrc = hdcSrc;
3360 info.pptSrc = pptSrc;
3361 info.crKey = crKey;
3362 info.pblend = pblend;
3363 info.dwFlags = flags;
3364 info.prcDirty = NULL;
3365 return UpdateLayeredWindowIndirect( hwnd, &info );
3369 /******************************************************************************
3370 * GetProcessDefaultLayout [USER32.@]
3372 * Gets the default layout for parentless windows.
3374 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3376 if (!layout)
3378 SetLastError( ERROR_NOACCESS );
3379 return FALSE;
3381 if (process_layout == ~0u)
3383 WCHAR *str, buffer[MAX_PATH];
3384 DWORD i, version_layout = 0;
3385 UINT len;
3386 DWORD user_lang = GetUserDefaultLangID();
3387 DWORD *languages;
3388 void *data = NULL;
3390 GetModuleFileNameW( 0, buffer, MAX_PATH );
3391 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3392 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3393 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3394 if (!VerQueryValueW( data, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done;
3396 len /= sizeof(DWORD);
3397 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3398 if (i == len) /* try neutral language */
3399 for (i = 0; i < len; i++)
3400 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3401 if (i == len) i = 0; /* default to the first one */
3403 swprintf( buffer, ARRAY_SIZE(buffer), L"\\StringFileInfo\\%04x%04x\\FileDescription",
3404 LOWORD(languages[i]), HIWORD(languages[i]) );
3405 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3406 TRACE( "found description %s\n", debugstr_w( str ));
3407 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3409 done:
3410 HeapFree( GetProcessHeap(), 0, data );
3411 process_layout = version_layout;
3413 *layout = process_layout;
3414 return TRUE;
3418 /******************************************************************************
3419 * SetProcessDefaultLayout [USER32.@]
3421 * Sets the default layout for parentless windows.
3423 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3425 process_layout = layout;
3426 return TRUE;
3430 /* 64bit versions */
3432 #ifdef GetWindowLongPtrW
3433 #undef GetWindowLongPtrW
3434 #endif
3436 #ifdef GetWindowLongPtrA
3437 #undef GetWindowLongPtrA
3438 #endif
3440 #ifdef SetWindowLongPtrW
3441 #undef SetWindowLongPtrW
3442 #endif
3444 #ifdef SetWindowLongPtrA
3445 #undef SetWindowLongPtrA
3446 #endif
3448 /*****************************************************************************
3449 * GetWindowLongPtrW (USER32.@)
3451 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3453 return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongPtrW );
3456 /*****************************************************************************
3457 * GetWindowLongPtrA (USER32.@)
3459 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3461 return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongPtrA );
3464 /*****************************************************************************
3465 * SetWindowLongPtrW (USER32.@)
3467 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3469 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3472 /*****************************************************************************
3473 * SetWindowLongPtrA (USER32.@)
3475 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3477 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3480 /*****************************************************************************
3481 * RegisterTouchWindow (USER32.@)
3483 BOOL WINAPI RegisterTouchWindow(HWND hwnd, ULONG flags)
3485 FIXME("(%p %08x): stub\n", hwnd, flags);
3486 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3487 return FALSE;
3490 /*****************************************************************************
3491 * UnregisterTouchWindow (USER32.@)
3493 BOOL WINAPI UnregisterTouchWindow(HWND hwnd)
3495 FIXME("(%p): stub\n", hwnd);
3496 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3497 return FALSE;
3500 /*****************************************************************************
3501 * CloseTouchInputHandle (USER32.@)
3503 BOOL WINAPI CloseTouchInputHandle(HTOUCHINPUT handle)
3505 FIXME("(%p): stub\n", handle);
3506 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3507 return FALSE;
3510 /*****************************************************************************
3511 * GetTouchInputInfo (USER32.@)
3513 BOOL WINAPI GetTouchInputInfo(HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size)
3515 FIXME("(%p %u %p %u): stub\n", handle, count, ptr, size);
3516 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3517 return FALSE;
3520 /*****************************************************************************
3521 * GetGestureInfo (USER32.@)
3523 BOOL WINAPI GetGestureInfo(HGESTUREINFO handle, PGESTUREINFO ptr)
3525 FIXME("(%p %p): stub\n", handle, ptr);
3526 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3527 return FALSE;
3530 /*****************************************************************************
3531 * GetWindowDisplayAffinity (USER32.@)
3533 BOOL WINAPI GetWindowDisplayAffinity(HWND hwnd, DWORD *affinity)
3535 FIXME("(%p, %p): stub\n", hwnd, affinity);
3537 if (!hwnd || !affinity)
3539 SetLastError(hwnd ? ERROR_NOACCESS : ERROR_INVALID_WINDOW_HANDLE);
3540 return FALSE;
3543 *affinity = WDA_NONE;
3544 return TRUE;
3547 /*****************************************************************************
3548 * SetWindowDisplayAffinity (USER32.@)
3550 BOOL WINAPI SetWindowDisplayAffinity(HWND hwnd, DWORD affinity)
3552 FIXME("(%p, %u): stub\n", hwnd, affinity);
3554 if (!hwnd)
3556 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
3557 return FALSE;
3560 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3561 return FALSE;
3564 /**********************************************************************
3565 * SetWindowCompositionAttribute (USER32.@)
3567 BOOL WINAPI SetWindowCompositionAttribute(HWND hwnd, void *data)
3569 FIXME("(%p, %p): stub\n", hwnd, data);
3570 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3571 return FALSE;
3574 /***********************************************************************
3575 * InternalGetWindowIcon (USER32.@)
3577 HICON WINAPI InternalGetWindowIcon( HWND hwnd, UINT type )
3579 WND *win = WIN_GetPtr( hwnd );
3580 HICON ret;
3582 TRACE( "hwnd %p, type %#x\n", hwnd, type );
3584 if (!win)
3586 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3587 return 0;
3589 if (win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3591 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3592 return 0;
3595 switch (type)
3597 case ICON_BIG:
3598 ret = win->hIcon;
3599 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON );
3600 break;
3602 case ICON_SMALL:
3603 case ICON_SMALL2:
3604 ret = win->hIconSmall ? win->hIconSmall : win->hIconSmall2;
3605 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICONSM );
3606 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON );
3607 break;
3609 default:
3610 SetLastError( ERROR_INVALID_PARAMETER );
3611 WIN_ReleasePtr( win );
3612 return 0;
3615 if (!ret) ret = LoadIconW( 0, (const WCHAR *)IDI_APPLICATION );
3617 WIN_ReleasePtr( win );
3618 return CopyIcon( ret );