winebus.sys: Rename UDEV bus device variables to be consistent.
[wine.git] / dlls / user32 / win.c
blob7c2471d27469bb24375da7a946e99aa3282a57cf
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 <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winnls.h"
30 #include "winver.h"
31 #include "wine/server.h"
32 #include "wine/asm.h"
33 #include "win.h"
34 #include "user_private.h"
35 #include "controls.h"
36 #include "winerror.h"
37 #include "wine/gdi_driver.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
42 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
43 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
45 static DWORD process_layout = ~0u;
47 static struct list window_surfaces = LIST_INIT( window_surfaces );
49 static CRITICAL_SECTION surfaces_section;
50 static CRITICAL_SECTION_DEBUG critsect_debug =
52 0, 0, &surfaces_section,
53 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
54 0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
56 static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };
58 /**********************************************************************/
60 /* helper for Get/SetWindowLong */
61 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
63 if (size == sizeof(WORD))
65 WORD ret;
66 memcpy( &ret, ptr, sizeof(ret) );
67 return ret;
69 else if (size == sizeof(DWORD))
71 DWORD ret;
72 memcpy( &ret, ptr, sizeof(ret) );
73 return ret;
75 else
77 LONG_PTR ret;
78 memcpy( &ret, ptr, sizeof(ret) );
79 return ret;
83 /* helper for Get/SetWindowLong */
84 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
86 if (size == sizeof(WORD))
88 WORD newval = val;
89 memcpy( ptr, &newval, sizeof(newval) );
91 else if (size == sizeof(DWORD))
93 DWORD newval = val;
94 memcpy( ptr, &newval, sizeof(newval) );
96 else
98 memcpy( ptr, &val, sizeof(val) );
103 static void *user_handles[NB_USER_HANDLES];
105 /***********************************************************************
106 * alloc_user_handle
108 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
110 HANDLE handle = 0;
112 SERVER_START_REQ( alloc_user_handle )
114 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
116 SERVER_END_REQ;
118 if (handle)
120 UINT index = USER_HANDLE_TO_INDEX( handle );
122 assert( index < NB_USER_HANDLES );
123 ptr->handle = handle;
124 ptr->type = type;
125 InterlockedExchangePointer( &user_handles[index], ptr );
127 return handle;
131 /***********************************************************************
132 * get_user_handle_ptr
134 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
136 struct user_object *ptr;
137 WORD index = USER_HANDLE_TO_INDEX( handle );
139 if (index >= NB_USER_HANDLES) return NULL;
141 USER_Lock();
142 if ((ptr = user_handles[index]))
144 if (ptr->type == type &&
145 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
146 !HIWORD(handle) || HIWORD(handle) == 0xffff))
147 return ptr;
148 ptr = NULL;
150 else ptr = OBJ_OTHER_PROCESS;
151 USER_Unlock();
152 return ptr;
156 /***********************************************************************
157 * release_user_handle_ptr
159 void release_user_handle_ptr( void *ptr )
161 assert( ptr && ptr != OBJ_OTHER_PROCESS );
162 USER_Unlock();
166 /***********************************************************************
167 * free_user_handle
169 void *free_user_handle( HANDLE handle, enum user_obj_type type )
171 struct user_object *ptr;
172 WORD index = USER_HANDLE_TO_INDEX( handle );
174 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
176 SERVER_START_REQ( free_user_handle )
178 req->handle = wine_server_user_handle( handle );
179 if (wine_server_call( req )) ptr = NULL;
180 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
182 SERVER_END_REQ;
183 USER_Unlock();
185 return ptr;
189 /***********************************************************************
190 * create_window_handle
192 * Create a window handle with the server.
194 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
195 HINSTANCE instance, BOOL unicode )
197 WORD index;
198 WND *win;
199 HWND handle = 0, full_parent = 0, full_owner = 0;
200 struct tagCLASS *class = NULL;
201 int extra_bytes = 0;
202 DPI_AWARENESS awareness = GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() );
203 UINT dpi = 0;
205 SERVER_START_REQ( create_window )
207 req->parent = wine_server_user_handle( parent );
208 req->owner = wine_server_user_handle( owner );
209 req->instance = wine_server_client_ptr( instance );
210 req->dpi = GetDpiForSystem();
211 req->awareness = awareness;
212 if (!(req->atom = get_int_atom_value( name )) && name)
213 wine_server_add_data( req, name, lstrlenW(name)*sizeof(WCHAR) );
214 if (!wine_server_call_err( req ))
216 handle = wine_server_ptr_handle( reply->handle );
217 full_parent = wine_server_ptr_handle( reply->parent );
218 full_owner = wine_server_ptr_handle( reply->owner );
219 extra_bytes = reply->extra;
220 dpi = reply->dpi;
221 awareness = reply->awareness;
222 class = wine_server_get_ptr( reply->class_ptr );
225 SERVER_END_REQ;
227 if (!handle)
229 WARN( "error %d creating window\n", GetLastError() );
230 return NULL;
233 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
234 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
236 SERVER_START_REQ( destroy_window )
238 req->handle = wine_server_user_handle( handle );
239 wine_server_call( req );
241 SERVER_END_REQ;
242 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
243 return NULL;
246 if (!parent) /* if parent is 0 we don't have a desktop window yet */
248 struct user_thread_info *thread_info = get_user_thread_info();
250 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
252 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
253 else assert( full_parent == thread_info->top_window );
254 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
255 ERR( "failed to create desktop window\n" );
257 else /* HWND_MESSAGE parent */
259 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
263 USER_Lock();
265 index = USER_HANDLE_TO_INDEX(handle);
266 assert( index < NB_USER_HANDLES );
267 win->obj.handle = handle;
268 win->obj.type = USER_WINDOW;
269 win->parent = full_parent;
270 win->owner = full_owner;
271 win->class = class;
272 win->winproc = get_class_winproc( class );
273 win->cbWndExtra = extra_bytes;
274 win->dpi = dpi;
275 win->dpi_awareness = awareness;
276 InterlockedExchangePointer( &user_handles[index], win );
277 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
278 return win;
282 /***********************************************************************
283 * free_window_handle
285 * Free a window handle.
287 static void free_window_handle( HWND hwnd )
289 struct user_object *ptr;
290 WORD index = USER_HANDLE_TO_INDEX(hwnd);
292 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
294 SERVER_START_REQ( destroy_window )
296 req->handle = wine_server_user_handle( hwnd );
297 wine_server_call( req );
298 InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
300 SERVER_END_REQ;
301 USER_Unlock();
302 HeapFree( GetProcessHeap(), 0, ptr );
307 /*******************************************************************
308 * list_window_children
310 * Build an array of the children of a given window. The array must be
311 * freed with HeapFree. Returns NULL when no windows are found.
313 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
315 HWND *list;
316 int i, size = 128;
317 ATOM atom = get_int_atom_value( class );
319 /* empty class is not the same as NULL class */
320 if (!atom && class && !class[0]) return NULL;
322 for (;;)
324 int count = 0;
326 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
328 SERVER_START_REQ( get_window_children )
330 req->desktop = wine_server_obj_handle( desktop );
331 req->parent = wine_server_user_handle( hwnd );
332 req->tid = tid;
333 req->atom = atom;
334 if (!atom && class) wine_server_add_data( req, class, lstrlenW(class)*sizeof(WCHAR) );
335 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
336 if (!wine_server_call( req )) count = reply->count;
338 SERVER_END_REQ;
339 if (count && count < size)
341 /* start from the end since HWND is potentially larger than user_handle_t */
342 for (i = count - 1; i >= 0; i--)
343 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
344 list[count] = 0;
345 return list;
347 HeapFree( GetProcessHeap(), 0, list );
348 if (!count) break;
349 size = count + 1; /* restart with a large enough buffer */
351 return NULL;
355 /*******************************************************************
356 * list_window_parents
358 * Build an array of all parents of a given window, starting with
359 * the immediate parent. The array must be freed with HeapFree.
361 static HWND *list_window_parents( HWND hwnd )
363 WND *win;
364 HWND current, *list;
365 int i, pos = 0, size = 16, count;
367 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
369 current = hwnd;
370 for (;;)
372 if (!(win = WIN_GetPtr( current ))) goto empty;
373 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
374 if (win == WND_DESKTOP)
376 if (!pos) goto empty;
377 list[pos] = 0;
378 return list;
380 list[pos] = current = win->parent;
381 WIN_ReleasePtr( win );
382 if (!current) return list;
383 if (++pos == size - 1)
385 /* need to grow the list */
386 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
387 if (!new_list) goto empty;
388 list = new_list;
389 size += 16;
393 /* at least one parent belongs to another process, have to query the server */
395 for (;;)
397 count = 0;
398 SERVER_START_REQ( get_window_parents )
400 req->handle = wine_server_user_handle( hwnd );
401 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
402 if (!wine_server_call( req )) count = reply->count;
404 SERVER_END_REQ;
405 if (!count) goto empty;
406 if (size > count)
408 /* start from the end since HWND is potentially larger than user_handle_t */
409 for (i = count - 1; i >= 0; i--)
410 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
411 list[count] = 0;
412 return list;
414 HeapFree( GetProcessHeap(), 0, list );
415 size = count + 1;
416 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
419 empty:
420 HeapFree( GetProcessHeap(), 0, list );
421 return NULL;
425 /*******************************************************************
426 * send_parent_notify
428 static void send_parent_notify( HWND hwnd, UINT msg )
430 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
431 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
433 HWND parent = GetParent(hwnd);
434 if (parent && parent != GetDesktopWindow())
435 SendMessageW( parent, WM_PARENTNOTIFY,
436 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
441 /*******************************************************************
442 * update_window_state
444 * Trigger an update of the window's driver state and surface.
446 void update_window_state( HWND hwnd )
448 DPI_AWARENESS_CONTEXT context;
449 RECT window_rect, client_rect, valid_rects[2];
451 if (!WIN_IsCurrentThread( hwnd ))
453 PostMessageW( hwnd, WM_WINE_UPDATEWINDOWSTATE, 0, 0 );
454 return;
457 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
458 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
459 valid_rects[0] = valid_rects[1] = client_rect;
460 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
461 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW,
462 &window_rect, &client_rect, valid_rects );
463 SetThreadDpiAwarenessContext( context );
467 /*******************************************************************
468 * get_server_window_text
470 * Retrieve the window text from the server.
472 static data_size_t get_server_window_text( HWND hwnd, WCHAR *text, data_size_t count )
474 data_size_t len = 0, needed = 0;
476 SERVER_START_REQ( get_window_text )
478 req->handle = wine_server_user_handle( hwnd );
479 if (count) wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
480 if (!wine_server_call_err( req ))
482 needed = reply->length;
483 len = wine_server_reply_size(reply);
486 SERVER_END_REQ;
487 if (text) text[len / sizeof(WCHAR)] = 0;
488 return needed;
492 /*******************************************************************
493 * get_hwnd_message_parent
495 * Return the parent for HWND_MESSAGE windows.
497 HWND get_hwnd_message_parent(void)
499 struct user_thread_info *thread_info = get_user_thread_info();
501 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
502 return thread_info->msg_window;
506 /*******************************************************************
507 * is_desktop_window
509 * Check if window is the desktop or the HWND_MESSAGE top parent.
511 BOOL is_desktop_window( HWND hwnd )
513 struct user_thread_info *thread_info = get_user_thread_info();
515 if (!hwnd) return FALSE;
516 if (hwnd == thread_info->top_window) return TRUE;
517 if (hwnd == thread_info->msg_window) return TRUE;
519 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
521 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
522 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
524 return FALSE;
528 /*******************************************************************
529 * Dummy window surface for windows that shouldn't get painted.
532 static void CDECL dummy_surface_lock( struct window_surface *window_surface )
534 /* nothing to do */
537 static void CDECL dummy_surface_unlock( struct window_surface *window_surface )
539 /* nothing to do */
542 static void *CDECL dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
544 static DWORD dummy_data;
546 info->bmiHeader.biSize = sizeof( info->bmiHeader );
547 info->bmiHeader.biWidth = dummy_surface.rect.right;
548 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
549 info->bmiHeader.biPlanes = 1;
550 info->bmiHeader.biBitCount = 32;
551 info->bmiHeader.biCompression = BI_RGB;
552 info->bmiHeader.biSizeImage = 0;
553 info->bmiHeader.biXPelsPerMeter = 0;
554 info->bmiHeader.biYPelsPerMeter = 0;
555 info->bmiHeader.biClrUsed = 0;
556 info->bmiHeader.biClrImportant = 0;
557 return &dummy_data;
560 static RECT *CDECL dummy_surface_get_bounds( struct window_surface *window_surface )
562 static RECT dummy_bounds;
563 return &dummy_bounds;
566 static void CDECL dummy_surface_set_region( struct window_surface *window_surface, HRGN region )
568 /* nothing to do */
571 static void CDECL dummy_surface_flush( struct window_surface *window_surface )
573 /* nothing to do */
576 static void CDECL dummy_surface_destroy( struct window_surface *window_surface )
578 /* nothing to do */
581 static const struct window_surface_funcs dummy_surface_funcs =
583 dummy_surface_lock,
584 dummy_surface_unlock,
585 dummy_surface_get_bitmap_info,
586 dummy_surface_get_bounds,
587 dummy_surface_set_region,
588 dummy_surface_flush,
589 dummy_surface_destroy
592 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
594 /*******************************************************************
595 * Off-screen window surface.
598 struct offscreen_window_surface
600 struct window_surface header;
601 CRITICAL_SECTION cs;
602 RECT bounds;
603 char *bits;
604 BITMAPINFO info;
607 static const struct window_surface_funcs offscreen_window_surface_funcs;
609 static inline void reset_bounds( RECT *bounds )
611 bounds->left = bounds->top = INT_MAX;
612 bounds->right = bounds->bottom = INT_MIN;
615 static struct offscreen_window_surface *impl_from_window_surface( struct window_surface *base )
617 if (!base || base->funcs != &offscreen_window_surface_funcs) return NULL;
618 return CONTAINING_RECORD( base, struct offscreen_window_surface, header );
621 static void CDECL offscreen_window_surface_lock( struct window_surface *base )
623 struct offscreen_window_surface *impl = impl_from_window_surface( base );
624 EnterCriticalSection( &impl->cs );
627 static void CDECL offscreen_window_surface_unlock( struct window_surface *base )
629 struct offscreen_window_surface *impl = impl_from_window_surface( base );
630 LeaveCriticalSection( &impl->cs );
633 static RECT *CDECL offscreen_window_surface_get_bounds( struct window_surface *base )
635 struct offscreen_window_surface *impl = impl_from_window_surface( base );
636 return &impl->bounds;
639 static void *CDECL offscreen_window_surface_get_bitmap_info( struct window_surface *base, BITMAPINFO *info )
641 struct offscreen_window_surface *impl = impl_from_window_surface( base );
642 memcpy( info, &impl->info, offsetof( BITMAPINFO, bmiColors[0] ) );
643 return impl->bits;
646 static void CDECL offscreen_window_surface_set_region( struct window_surface *base, HRGN region )
650 static void CDECL offscreen_window_surface_flush( struct window_surface *base )
652 struct offscreen_window_surface *impl = impl_from_window_surface( base );
653 base->funcs->lock( base );
654 reset_bounds( &impl->bounds );
655 base->funcs->unlock( base );
658 static void CDECL offscreen_window_surface_destroy( struct window_surface *base )
660 struct offscreen_window_surface *impl = impl_from_window_surface( base );
661 impl->cs.DebugInfo->Spare[0] = 0;
662 DeleteCriticalSection( &impl->cs );
663 free( impl );
666 static const struct window_surface_funcs offscreen_window_surface_funcs =
668 offscreen_window_surface_lock,
669 offscreen_window_surface_unlock,
670 offscreen_window_surface_get_bitmap_info,
671 offscreen_window_surface_get_bounds,
672 offscreen_window_surface_set_region,
673 offscreen_window_surface_flush,
674 offscreen_window_surface_destroy
677 void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface )
679 struct offscreen_window_surface *impl;
680 SIZE_T size;
681 RECT surface_rect = *visible_rect;
683 TRACE( "visible_rect %s, surface %p.\n", wine_dbgstr_rect( visible_rect ), surface );
685 OffsetRect( &surface_rect, -surface_rect.left, -surface_rect.top );
686 surface_rect.right = (surface_rect.right + 0x1f) & ~0x1f;
687 surface_rect.bottom = (surface_rect.bottom + 0x1f) & ~0x1f;
689 /* check that old surface is an offscreen_window_surface, or release it */
690 if ((impl = impl_from_window_surface( *surface )))
692 /* if the rect didn't change, keep the same surface */
693 if (EqualRect( &surface_rect, &impl->header.rect )) return;
694 window_surface_release( &impl->header );
696 else if (*surface) window_surface_release( *surface );
698 /* create a new window surface */
699 *surface = NULL;
700 size = surface_rect.right * surface_rect.bottom * 4;
701 if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return;
703 impl->header.funcs = &offscreen_window_surface_funcs;
704 impl->header.ref = 1;
705 impl->header.rect = surface_rect;
707 InitializeCriticalSection( &impl->cs );
708 impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
709 reset_bounds( &impl->bounds );
711 impl->bits = (char *)&impl->info.bmiColors[0];
712 impl->info.bmiHeader.biSize = sizeof( impl->info );
713 impl->info.bmiHeader.biWidth = surface_rect.right;
714 impl->info.bmiHeader.biHeight = surface_rect.bottom;
715 impl->info.bmiHeader.biPlanes = 1;
716 impl->info.bmiHeader.biBitCount = 32;
717 impl->info.bmiHeader.biCompression = BI_RGB;
718 impl->info.bmiHeader.biSizeImage = size;
720 TRACE( "created window surface %p\n", &impl->header );
722 *surface = &impl->header;
725 /*******************************************************************
726 * register_window_surface
728 * Register a window surface in the global list, possibly replacing another one.
730 void register_window_surface( struct window_surface *old, struct window_surface *new )
732 if (old == new) return;
733 EnterCriticalSection( &surfaces_section );
734 if (old && old != &dummy_surface) list_remove( &old->entry );
735 if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
736 LeaveCriticalSection( &surfaces_section );
740 /*******************************************************************
741 * flush_window_surfaces
743 * Flush pending output from all window surfaces.
745 void flush_window_surfaces( BOOL idle )
747 static DWORD last_idle;
748 DWORD now;
749 struct window_surface *surface;
751 EnterCriticalSection( &surfaces_section );
752 now = GetTickCount();
753 if (idle) last_idle = now;
754 /* if not idle, we only flush if there's evidence that the app never goes idle */
755 else if ((int)(now - last_idle) < 50) goto done;
757 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
758 surface->funcs->flush( surface );
759 done:
760 LeaveCriticalSection( &surfaces_section );
764 /***********************************************************************
765 * WIN_GetPtr
767 * Return a pointer to the WND structure if local to the process,
768 * or WND_OTHER_PROCESS if handle may be valid in other process.
769 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
771 WND *WIN_GetPtr( HWND hwnd )
773 WND *ptr;
775 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
777 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
779 return ptr;
783 /***********************************************************************
784 * WIN_IsCurrentProcess
786 * Check whether a given window belongs to the current process (and return the full handle).
788 HWND WIN_IsCurrentProcess( HWND hwnd )
790 WND *ptr;
791 HWND ret;
793 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
794 ret = ptr->obj.handle;
795 WIN_ReleasePtr( ptr );
796 return ret;
800 /***********************************************************************
801 * WIN_IsCurrentThread
803 * Check whether a given window belongs to the current thread (and return the full handle).
805 HWND WIN_IsCurrentThread( HWND hwnd )
807 WND *ptr;
808 HWND ret = 0;
810 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
811 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
812 WIN_ReleasePtr( ptr );
813 return ret;
817 /***********************************************************************
818 * win_set_flags
820 * Set the flags of a window and return the previous value.
822 UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask )
824 UINT ret;
825 WND *ptr = WIN_GetPtr( hwnd );
827 if (!ptr || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
828 ret = ptr->flags;
829 ptr->flags = (ret & ~clear_mask) | set_mask;
830 WIN_ReleasePtr( ptr );
831 return ret;
835 /***********************************************************************
836 * WIN_GetFullHandle
838 * Convert a possibly truncated window handle to a full 32-bit handle.
840 HWND WIN_GetFullHandle( HWND hwnd )
842 WND *ptr;
844 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
845 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
846 /* do sign extension for -2 and -3 */
847 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
849 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
851 if (ptr == WND_DESKTOP)
853 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
854 else return get_hwnd_message_parent();
857 if (ptr != WND_OTHER_PROCESS)
859 hwnd = ptr->obj.handle;
860 WIN_ReleasePtr( ptr );
862 else /* may belong to another process */
864 SERVER_START_REQ( get_window_info )
866 req->handle = wine_server_user_handle( hwnd );
867 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
869 SERVER_END_REQ;
871 return hwnd;
875 /***********************************************************************
876 * WIN_SetOwner
878 * Change the owner of a window.
880 static HWND WIN_SetOwner( HWND hwnd, HWND owner )
882 WND *win = WIN_GetPtr( hwnd );
883 HWND ret = 0;
885 if (!win || win == WND_DESKTOP) return 0;
886 if (win == WND_OTHER_PROCESS)
888 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
889 return 0;
891 SERVER_START_REQ( set_window_owner )
893 req->handle = wine_server_user_handle( hwnd );
894 req->owner = wine_server_user_handle( owner );
895 if (!wine_server_call( req ))
897 win->owner = wine_server_ptr_handle( reply->full_owner );
898 ret = wine_server_ptr_handle( reply->prev_owner );
901 SERVER_END_REQ;
902 WIN_ReleasePtr( win );
903 return ret;
907 /***********************************************************************
908 * WIN_SetStyle
910 * Change the style of a window.
912 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
914 BOOL ok, made_visible = FALSE;
915 STYLESTRUCT style;
916 WND *win = WIN_GetPtr( hwnd );
918 if (!win || win == WND_DESKTOP) return 0;
919 if (win == WND_OTHER_PROCESS)
921 if (IsWindow(hwnd))
922 return SendMessageW(hwnd, WM_WINE_SETSTYLE, set_bits, clear_bits);
923 return 0;
925 style.styleOld = win->dwStyle;
926 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
927 if (style.styleNew == style.styleOld)
929 WIN_ReleasePtr( win );
930 return style.styleNew;
932 SERVER_START_REQ( set_window_info )
934 req->handle = wine_server_user_handle( hwnd );
935 req->flags = SET_WIN_STYLE;
936 req->style = style.styleNew;
937 req->extra_offset = -1;
938 if ((ok = !wine_server_call( req )))
940 style.styleOld = reply->old_style;
941 win->dwStyle = style.styleNew;
944 SERVER_END_REQ;
946 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
948 made_visible = (style.styleNew & WS_VISIBLE) != 0;
949 invalidate_dce( win, NULL );
951 WIN_ReleasePtr( win );
953 if (!ok) return 0;
955 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
956 if (made_visible) update_window_state( hwnd );
958 return style.styleOld;
962 /***********************************************************************
963 * WIN_GetRectangles
965 * Get the window and client rectangles.
967 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
969 WND *win = WIN_GetPtr( hwnd );
970 BOOL ret = TRUE;
972 if (!win)
974 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
975 return FALSE;
977 if (win == WND_DESKTOP)
979 RECT rect;
980 rect.left = rect.top = 0;
981 if (hwnd == get_hwnd_message_parent())
983 rect.right = 100;
984 rect.bottom = 100;
985 rect = rect_win_to_thread_dpi( hwnd, rect );
987 else
989 rect = get_primary_monitor_rect();
991 if (rectWindow) *rectWindow = rect;
992 if (rectClient) *rectClient = rect;
993 return TRUE;
995 if (win != WND_OTHER_PROCESS)
997 RECT window_rect = win->window_rect, client_rect = win->client_rect;
999 switch (relative)
1001 case COORDS_CLIENT:
1002 OffsetRect( &window_rect, -win->client_rect.left, -win->client_rect.top );
1003 OffsetRect( &client_rect, -win->client_rect.left, -win->client_rect.top );
1004 if (win->dwExStyle & WS_EX_LAYOUTRTL)
1005 mirror_rect( &win->client_rect, &window_rect );
1006 break;
1007 case COORDS_WINDOW:
1008 OffsetRect( &window_rect, -win->window_rect.left, -win->window_rect.top );
1009 OffsetRect( &client_rect, -win->window_rect.left, -win->window_rect.top );
1010 if (win->dwExStyle & WS_EX_LAYOUTRTL)
1011 mirror_rect( &win->window_rect, &client_rect );
1012 break;
1013 case COORDS_PARENT:
1014 if (win->parent)
1016 WND *parent = WIN_GetPtr( win->parent );
1017 if (parent == WND_DESKTOP) break;
1018 if (!parent || parent == WND_OTHER_PROCESS)
1020 WIN_ReleasePtr( win );
1021 goto other_process;
1023 if (parent->flags & WIN_CHILDREN_MOVED)
1025 WIN_ReleasePtr( parent );
1026 WIN_ReleasePtr( win );
1027 goto other_process;
1029 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
1031 mirror_rect( &parent->client_rect, &window_rect );
1032 mirror_rect( &parent->client_rect, &client_rect );
1034 WIN_ReleasePtr( parent );
1036 break;
1037 case COORDS_SCREEN:
1038 while (win->parent)
1040 WND *parent = WIN_GetPtr( win->parent );
1041 if (parent == WND_DESKTOP) break;
1042 if (!parent || parent == WND_OTHER_PROCESS)
1044 WIN_ReleasePtr( win );
1045 goto other_process;
1047 WIN_ReleasePtr( win );
1048 if (parent->flags & WIN_CHILDREN_MOVED)
1050 WIN_ReleasePtr( parent );
1051 goto other_process;
1053 win = parent;
1054 if (win->parent)
1056 OffsetRect( &window_rect, win->client_rect.left, win->client_rect.top );
1057 OffsetRect( &client_rect, win->client_rect.left, win->client_rect.top );
1060 break;
1062 if (rectWindow) *rectWindow = rect_win_to_thread_dpi( hwnd, window_rect );
1063 if (rectClient) *rectClient = rect_win_to_thread_dpi( hwnd, client_rect );
1064 WIN_ReleasePtr( win );
1065 return TRUE;
1068 other_process:
1069 SERVER_START_REQ( get_window_rectangles )
1071 req->handle = wine_server_user_handle( hwnd );
1072 req->relative = relative;
1073 req->dpi = get_thread_dpi();
1074 if ((ret = !wine_server_call_err( req )))
1076 if (rectWindow)
1078 rectWindow->left = reply->window.left;
1079 rectWindow->top = reply->window.top;
1080 rectWindow->right = reply->window.right;
1081 rectWindow->bottom = reply->window.bottom;
1083 if (rectClient)
1085 rectClient->left = reply->client.left;
1086 rectClient->top = reply->client.top;
1087 rectClient->right = reply->client.right;
1088 rectClient->bottom = reply->client.bottom;
1092 SERVER_END_REQ;
1093 return ret;
1097 /***********************************************************************
1098 * WIN_DestroyWindow
1100 * Destroy storage associated to a window. "Internals" p.358
1102 LRESULT WIN_DestroyWindow( HWND hwnd )
1104 WND *wndPtr;
1105 HWND *list;
1106 HMENU menu = 0, sys_menu;
1107 struct window_surface *surface;
1109 TRACE("%p\n", hwnd );
1111 /* destroy default IME window */
1112 if (win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)
1114 TRACE("unregister IME window for %p\n", hwnd);
1115 imm_unregister_window( hwnd );
1118 /* free child windows */
1119 if ((list = WIN_ListChildren( hwnd )))
1121 int i;
1122 for (i = 0; list[i]; i++)
1124 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
1125 else SendNotifyMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1127 HeapFree( GetProcessHeap(), 0, list );
1130 /* Unlink now so we won't bother with the children later on */
1131 SERVER_START_REQ( set_parent )
1133 req->handle = wine_server_user_handle( hwnd );
1134 req->parent = 0;
1135 wine_server_call( req );
1137 SERVER_END_REQ;
1140 * Send the WM_NCDESTROY to the window being destroyed.
1142 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
1144 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
1146 /* free resources associated with the window */
1148 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1149 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1150 menu = (HMENU)wndPtr->wIDmenu;
1151 sys_menu = wndPtr->hSysMenu;
1152 free_dce( wndPtr->dce, hwnd );
1153 wndPtr->dce = NULL;
1154 HeapFree( GetProcessHeap(), 0, wndPtr->text );
1155 wndPtr->text = NULL;
1156 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
1157 wndPtr->pScroll = NULL;
1158 DestroyIcon( wndPtr->hIconSmall2 );
1159 surface = wndPtr->surface;
1160 wndPtr->surface = NULL;
1161 WIN_ReleasePtr( wndPtr );
1163 if (menu) DestroyMenu( menu );
1164 if (sys_menu) DestroyMenu( sys_menu );
1165 if (surface)
1167 register_window_surface( surface, NULL );
1168 window_surface_release( surface );
1171 USER_Driver->pDestroyWindow( hwnd );
1173 free_window_handle( hwnd );
1174 return 0;
1178 /***********************************************************************
1179 * next_thread_window
1181 static WND *next_thread_window( HWND *hwnd )
1183 struct user_object *ptr;
1184 WND *win;
1185 WORD index = *hwnd ? USER_HANDLE_TO_INDEX( *hwnd ) + 1 : 0;
1187 USER_Lock();
1188 while (index < NB_USER_HANDLES)
1190 if (!(ptr = user_handles[index++])) continue;
1191 if (ptr->type != USER_WINDOW) continue;
1192 win = (WND *)ptr;
1193 if (win->tid != GetCurrentThreadId()) continue;
1194 *hwnd = ptr->handle;
1195 return win;
1197 USER_Unlock();
1198 return NULL;
1202 /***********************************************************************
1203 * destroy_thread_windows
1205 * Destroy all window owned by the current thread.
1207 void destroy_thread_windows(void)
1209 WND *wndPtr;
1210 HWND hwnd = 0, *list;
1211 HMENU menu, sys_menu;
1212 struct window_surface *surface;
1213 int i;
1215 while ((wndPtr = next_thread_window( &hwnd )))
1217 /* destroy the client-side storage */
1219 list = WIN_ListChildren( hwnd );
1220 menu = ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) ? (HMENU)wndPtr->wIDmenu : 0;
1221 sys_menu = wndPtr->hSysMenu;
1222 free_dce( wndPtr->dce, hwnd );
1223 surface = wndPtr->surface;
1224 InterlockedCompareExchangePointer( &user_handles[USER_HANDLE_TO_INDEX(hwnd)], NULL, wndPtr );
1225 WIN_ReleasePtr( wndPtr );
1226 HeapFree( GetProcessHeap(), 0, wndPtr );
1227 if (menu) DestroyMenu( menu );
1228 if (sys_menu) DestroyMenu( sys_menu );
1229 if (surface)
1231 register_window_surface( surface, NULL );
1232 window_surface_release( surface );
1235 /* free child windows */
1237 if (!list) continue;
1238 for (i = 0; list[i]; i++)
1239 if (!WIN_IsCurrentThread( list[i] ))
1240 SendNotifyMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1241 HeapFree( GetProcessHeap(), 0, list );
1246 /***********************************************************************
1247 * WIN_FixCoordinates
1249 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1250 * returns default show mode in sw.
1252 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1254 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1255 POINT pos[2];
1257 if (cs->dwExStyle & WS_EX_MDICHILD)
1259 UINT id = 0;
1261 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1262 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1264 TRACE("MDI child id %04x\n", id);
1267 if (cs->style & (WS_CHILD | WS_POPUP))
1269 if (cs->dwExStyle & WS_EX_MDICHILD)
1271 if (IS_DEFAULT(cs->x))
1273 cs->x = pos[0].x;
1274 cs->y = pos[0].y;
1276 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1277 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1279 else
1281 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1282 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1285 else /* overlapped window */
1287 HMONITOR monitor;
1288 MONITORINFO mon_info;
1289 STARTUPINFOW info;
1291 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1293 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1294 mon_info.cbSize = sizeof(mon_info);
1295 GetMonitorInfoW( monitor, &mon_info );
1296 GetStartupInfoW( &info );
1298 if (IS_DEFAULT(cs->x))
1300 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1301 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1302 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1305 if (IS_DEFAULT(cs->cx))
1307 if (info.dwFlags & STARTF_USESIZE)
1309 cs->cx = info.dwXSize;
1310 cs->cy = info.dwYSize;
1312 else
1314 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1315 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1318 /* neither x nor cx are default. Check the y values .
1319 * In the trace we see Outlook and Outlook Express using
1320 * cy set to CW_USEDEFAULT when opening the address book.
1322 else if (IS_DEFAULT(cs->cy))
1324 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1325 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1328 #undef IS_DEFAULT
1331 /***********************************************************************
1332 * dump_window_styles
1334 static void dump_window_styles( DWORD style, DWORD exstyle )
1336 TRACE( "style:" );
1337 if(style & WS_POPUP) TRACE(" WS_POPUP");
1338 if(style & WS_CHILD) TRACE(" WS_CHILD");
1339 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1340 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1341 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1342 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1343 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1344 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1345 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1346 else
1348 if(style & WS_BORDER) TRACE(" WS_BORDER");
1349 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1351 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1352 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1353 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1354 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1355 if (style & WS_CHILD)
1357 if(style & WS_GROUP) TRACE(" WS_GROUP");
1358 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1360 else
1362 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1363 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1366 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1367 #define DUMPED_STYLES \
1368 ((DWORD)(WS_POPUP | \
1369 WS_CHILD | \
1370 WS_MINIMIZE | \
1371 WS_VISIBLE | \
1372 WS_DISABLED | \
1373 WS_CLIPSIBLINGS | \
1374 WS_CLIPCHILDREN | \
1375 WS_MAXIMIZE | \
1376 WS_BORDER | \
1377 WS_DLGFRAME | \
1378 WS_VSCROLL | \
1379 WS_HSCROLL | \
1380 WS_SYSMENU | \
1381 WS_THICKFRAME | \
1382 WS_GROUP | \
1383 WS_TABSTOP | \
1384 WS_MINIMIZEBOX | \
1385 WS_MAXIMIZEBOX))
1387 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1388 TRACE("\n");
1389 #undef DUMPED_STYLES
1391 TRACE( "exstyle:" );
1392 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1393 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1394 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1395 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1396 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1397 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1398 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1399 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1400 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1401 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1402 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1403 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1404 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1405 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1406 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1407 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1408 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1409 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1410 if(exstyle & WS_EX_NOINHERITLAYOUT) TRACE(" WS_EX_NOINHERITLAYOUT");
1411 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1412 if(exstyle & WS_EX_COMPOSITED) TRACE(" WS_EX_COMPOSITED");
1413 if(exstyle & WS_EX_NOACTIVATE) TRACE(" WS_EX_NOACTIVATE");
1415 #define DUMPED_EX_STYLES \
1416 ((DWORD)(WS_EX_DLGMODALFRAME | \
1417 WS_EX_DRAGDETECT | \
1418 WS_EX_NOPARENTNOTIFY | \
1419 WS_EX_TOPMOST | \
1420 WS_EX_ACCEPTFILES | \
1421 WS_EX_TRANSPARENT | \
1422 WS_EX_MDICHILD | \
1423 WS_EX_TOOLWINDOW | \
1424 WS_EX_WINDOWEDGE | \
1425 WS_EX_CLIENTEDGE | \
1426 WS_EX_CONTEXTHELP | \
1427 WS_EX_RIGHT | \
1428 WS_EX_RTLREADING | \
1429 WS_EX_LEFTSCROLLBAR | \
1430 WS_EX_CONTROLPARENT | \
1431 WS_EX_STATICEDGE | \
1432 WS_EX_APPWINDOW | \
1433 WS_EX_LAYERED | \
1434 WS_EX_NOINHERITLAYOUT | \
1435 WS_EX_LAYOUTRTL | \
1436 WS_EX_COMPOSITED |\
1437 WS_EX_NOACTIVATE))
1439 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1440 TRACE("\n");
1441 #undef DUMPED_EX_STYLES
1444 /***********************************************************************
1445 * map_dpi_create_struct
1447 static void map_dpi_create_struct( CREATESTRUCTW *cs, UINT dpi_from, UINT dpi_to )
1449 if (!dpi_from && !dpi_to) return;
1450 if (!dpi_from || !dpi_to)
1452 POINT pt = { cs->x, cs->y };
1453 UINT mon_dpi = get_monitor_dpi( MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ));
1454 if (!dpi_from) dpi_from = mon_dpi;
1455 else dpi_to = mon_dpi;
1457 if (dpi_from == dpi_to) return;
1458 cs->x = MulDiv( cs->x, dpi_to, dpi_from );
1459 cs->y = MulDiv( cs->y, dpi_to, dpi_from );
1460 cs->cx = MulDiv( cs->cx, dpi_to, dpi_from );
1461 cs->cy = MulDiv( cs->cy, dpi_to, dpi_from );
1464 /***********************************************************************
1465 * WIN_CreateWindowEx
1467 * Implementation of CreateWindowEx().
1469 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1471 INT cx, cy, style, sw = SW_SHOW;
1472 LRESULT result;
1473 RECT rect;
1474 WND *wndPtr;
1475 HWND hwnd, parent, owner, top_child = 0;
1476 const WCHAR *p = className;
1477 UINT win_dpi, thread_dpi = get_thread_dpi();
1478 DPI_AWARENESS_CONTEXT context;
1479 MDICREATESTRUCTW mdi_cs;
1480 CBT_CREATEWNDW cbtc;
1481 CREATESTRUCTW cbcs;
1483 className = CLASS_GetVersionedName(className, NULL, NULL, TRUE);
1485 TRACE("%s %s%s%s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1486 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1487 debugstr_w(p), p != className ? "->" : "", p != className ? debugstr_w(className) : "",
1488 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1489 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1490 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1492 /* Fix the styles for MDI children */
1493 if (cs->dwExStyle & WS_EX_MDICHILD)
1495 if (!(win_get_flags( cs->hwndParent ) & WIN_ISMDICLIENT))
1497 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1498 return 0;
1501 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1502 * MDICREATESTRUCT members have the originally passed values.
1504 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1505 * have the same layout.
1507 mdi_cs.szClass = cs->lpszClass;
1508 mdi_cs.szTitle = cs->lpszName;
1509 mdi_cs.hOwner = cs->hInstance;
1510 mdi_cs.x = cs->x;
1511 mdi_cs.y = cs->y;
1512 mdi_cs.cx = cs->cx;
1513 mdi_cs.cy = cs->cy;
1514 mdi_cs.style = cs->style;
1515 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1517 cs->lpCreateParams = &mdi_cs;
1519 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1521 if (cs->style & WS_POPUP)
1523 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1524 return 0;
1526 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1528 else
1530 cs->style &= ~WS_POPUP;
1531 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1532 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1535 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1537 if (top_child)
1539 /* Restore current maximized child */
1540 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1542 TRACE("Restoring current maximized child %p\n", top_child);
1543 if (cs->style & WS_MAXIMIZE)
1545 /* if the new window is maximized don't bother repainting */
1546 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1547 ShowWindow( top_child, SW_SHOWNORMAL );
1548 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1550 else ShowWindow( top_child, SW_SHOWNORMAL );
1555 /* Find the parent window */
1557 parent = cs->hwndParent;
1558 owner = 0;
1560 if (cs->hwndParent == HWND_MESSAGE)
1562 cs->hwndParent = parent = get_hwnd_message_parent();
1564 else if (cs->hwndParent)
1566 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1568 parent = GetDesktopWindow();
1569 owner = cs->hwndParent;
1571 else
1573 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1574 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1575 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1578 else
1580 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1582 WARN("No parent for child window\n" );
1583 SetLastError(ERROR_TLW_WITH_WSCHILD);
1584 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1587 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1588 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1589 (IS_INTRESOURCE(className) || wcsicmp( className, L"Message" )))
1591 DWORD layout;
1592 GetProcessDefaultLayout( &layout );
1593 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1594 parent = GetDesktopWindow();
1598 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1600 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1601 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1602 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1603 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1604 else
1605 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1607 /* Create the window structure */
1609 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1611 WNDCLASSW wc;
1612 /* if it's a comctl32 class, GetClassInfo will load it, then we can retry */
1613 if (GetLastError() != ERROR_INVALID_HANDLE ||
1614 !GetClassInfoW( 0, className, &wc ) ||
1615 !(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1616 return 0;
1618 hwnd = wndPtr->obj.handle;
1620 /* Fill the window structure */
1622 wndPtr->tid = GetCurrentThreadId();
1623 wndPtr->hInstance = cs->hInstance;
1624 wndPtr->text = NULL;
1625 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1626 wndPtr->dwExStyle = cs->dwExStyle;
1627 wndPtr->wIDmenu = 0;
1628 wndPtr->helpContext = 0;
1629 wndPtr->pScroll = NULL;
1630 wndPtr->userdata = 0;
1631 wndPtr->hIcon = 0;
1632 wndPtr->hIconSmall = 0;
1633 wndPtr->hIconSmall2 = 0;
1634 wndPtr->hSysMenu = 0;
1636 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1637 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1638 SetRect( &wndPtr->normal_rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1640 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1643 * Correct the window styles.
1645 * It affects only the style loaded into the WIN structure.
1648 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1650 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1651 if (!(wndPtr->dwStyle & WS_POPUP))
1652 wndPtr->dwStyle |= WS_CAPTION;
1655 /* WS_EX_WINDOWEDGE depends on some other styles */
1656 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1657 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1658 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1660 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1661 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1662 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1664 else
1665 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1667 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1668 wndPtr->flags |= WIN_NEED_SIZE;
1670 SERVER_START_REQ( set_window_info )
1672 req->handle = wine_server_user_handle( hwnd );
1673 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1674 req->style = wndPtr->dwStyle;
1675 req->ex_style = wndPtr->dwExStyle;
1676 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1677 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1678 req->extra_offset = -1;
1679 wine_server_call( req );
1681 SERVER_END_REQ;
1683 /* Set the window menu */
1685 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1687 if (cs->hMenu)
1689 if (!MENU_SetMenu(hwnd, cs->hMenu))
1691 WIN_ReleasePtr( wndPtr );
1692 free_window_handle( hwnd );
1693 return 0;
1696 else
1698 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1699 if (menuName)
1701 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1702 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1706 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1708 style = wndPtr->dwStyle;
1709 win_dpi = wndPtr->dpi;
1710 WIN_ReleasePtr( wndPtr );
1712 if (parent) map_dpi_create_struct( cs, thread_dpi, win_dpi );
1714 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1716 /* call the WH_CBT hook */
1718 /* the window style passed to the hook must be the real window style,
1719 * rather than just the window style that the caller to CreateWindowEx
1720 * passed in, so we have to copy the original CREATESTRUCT and get the
1721 * the real style. */
1722 cbcs = *cs;
1723 cbcs.style = style;
1724 cbtc.lpcs = &cbcs;
1725 cbtc.hwndInsertAfter = HWND_TOP;
1726 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1728 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1730 cx = cs->cx;
1731 cy = cs->cy;
1732 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1734 MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd );
1735 cx = max( min( cx, info.ptMaxTrackSize.x ), info.ptMinTrackSize.x );
1736 cy = max( min( cy, info.ptMaxTrackSize.y ), info.ptMinTrackSize.y );
1739 if (cx < 0) cx = 0;
1740 if (cy < 0) cy = 0;
1741 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1742 /* check for wraparound */
1743 if (cs->x > 0x7fffffff - cx) rect.right = 0x7fffffff;
1744 if (cs->y > 0x7fffffff - cy) rect.bottom = 0x7fffffff;
1745 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1747 /* send WM_NCCREATE */
1749 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd, cs->x, cs->y, cs->cx, cs->cy, wine_dbgstr_rect(&rect) );
1750 if (unicode)
1751 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1752 else
1753 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1754 if (!result)
1756 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1757 goto failed;
1760 /* create default IME window */
1762 if (imm_register_window && !is_desktop_window( hwnd ) &&
1763 parent != get_hwnd_message_parent() && imm_register_window( hwnd ))
1765 TRACE("register IME window for %p\n", hwnd);
1766 win_set_flags( hwnd, WIN_HAS_IME_WIN, 0 );
1769 /* send WM_NCCALCSIZE */
1771 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1773 /* yes, even if the CBT hook was called with HWND_TOP */
1774 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1775 RECT client_rect = rect;
1777 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1778 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1779 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1780 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1781 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1783 else goto failed;
1785 /* send WM_CREATE */
1787 if (unicode)
1788 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1789 else
1790 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1791 if (result == -1) goto failed;
1793 /* call the driver */
1795 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1797 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1799 /* send the size messages */
1801 if (!(win_get_flags( hwnd ) & WIN_NEED_SIZE))
1803 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1804 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1805 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1806 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1809 /* Show the window, maximizing or minimizing if needed */
1811 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1812 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1814 RECT newPos;
1815 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1817 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1818 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1819 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1820 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1821 newPos.bottom - newPos.top, swFlag );
1824 /* Notify the parent window only */
1826 send_parent_notify( hwnd, WM_CREATE );
1827 if (!IsWindow( hwnd ))
1829 SetThreadDpiAwarenessContext( context );
1830 return 0;
1833 if (parent == GetDesktopWindow())
1834 PostMessageW( parent, WM_PARENTNOTIFY, WM_CREATE, (LPARAM)hwnd );
1836 if (cs->style & WS_VISIBLE)
1838 if (cs->style & WS_MAXIMIZE)
1839 sw = SW_SHOW;
1840 else if (cs->style & WS_MINIMIZE)
1841 sw = SW_SHOWMINIMIZED;
1843 ShowWindow( hwnd, sw );
1844 if (cs->dwExStyle & WS_EX_MDICHILD)
1846 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1847 /* ShowWindow won't activate child windows */
1848 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1852 /* Call WH_SHELL hook */
1854 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1855 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1857 TRACE("created window %p\n", hwnd);
1858 SetThreadDpiAwarenessContext( context );
1859 return hwnd;
1861 failed:
1862 WIN_DestroyWindow( hwnd );
1863 SetThreadDpiAwarenessContext( context );
1864 return 0;
1868 /***********************************************************************
1869 * CreateWindowExA (USER32.@)
1871 HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExA( DWORD exStyle, LPCSTR className,
1872 LPCSTR windowName, DWORD style, INT x,
1873 INT y, INT width, INT height,
1874 HWND parent, HMENU menu,
1875 HINSTANCE instance, LPVOID data )
1877 CREATESTRUCTA cs;
1879 cs.lpCreateParams = data;
1880 cs.hInstance = instance;
1881 cs.hMenu = menu;
1882 cs.hwndParent = parent;
1883 cs.x = x;
1884 cs.y = y;
1885 cs.cx = width;
1886 cs.cy = height;
1887 cs.style = style;
1888 cs.lpszName = windowName;
1889 cs.lpszClass = className;
1890 cs.dwExStyle = exStyle;
1892 if (!IS_INTRESOURCE(className))
1894 WCHAR bufferW[256];
1895 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, ARRAY_SIZE( bufferW )))
1896 return 0;
1897 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1899 /* Note: we rely on the fact that CREATESTRUCTA and */
1900 /* CREATESTRUCTW have the same layout. */
1901 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1905 /***********************************************************************
1906 * CreateWindowExW (USER32.@)
1908 HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
1909 LPCWSTR windowName, DWORD style, INT x,
1910 INT y, INT width, INT height,
1911 HWND parent, HMENU menu,
1912 HINSTANCE instance, LPVOID data )
1914 CREATESTRUCTW cs;
1916 cs.lpCreateParams = data;
1917 cs.hInstance = instance;
1918 cs.hMenu = menu;
1919 cs.hwndParent = parent;
1920 cs.x = x;
1921 cs.y = y;
1922 cs.cx = width;
1923 cs.cy = height;
1924 cs.style = style;
1925 cs.lpszName = windowName;
1926 cs.lpszClass = className;
1927 cs.dwExStyle = exStyle;
1929 return wow_handlers.create_window( &cs, className, instance, TRUE );
1933 /***********************************************************************
1934 * WIN_SendDestroyMsg
1936 static void WIN_SendDestroyMsg( HWND hwnd )
1938 GUITHREADINFO info;
1940 info.cbSize = sizeof(info);
1941 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1943 if (hwnd == info.hwndCaret) DestroyCaret();
1944 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1947 if (hwnd == GetClipboardOwner()) CLIPBOARD_ReleaseOwner( hwnd );
1950 * Send the WM_DESTROY to the window.
1952 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1955 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1956 * make sure that the window still exists when we come back.
1958 if (IsWindow(hwnd))
1960 HWND* pWndArray;
1961 int i;
1963 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1965 for (i = 0; pWndArray[i]; i++)
1967 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1969 HeapFree( GetProcessHeap(), 0, pWndArray );
1971 else
1972 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1976 /***********************************************************************
1977 * DestroyWindow (USER32.@)
1979 BOOL WINAPI DestroyWindow( HWND hwnd )
1981 BOOL is_child;
1983 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1985 SetLastError( ERROR_ACCESS_DENIED );
1986 return FALSE;
1989 TRACE("(%p)\n", hwnd);
1991 /* Call hooks */
1993 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1995 if (MENU_IsMenuActive() == hwnd)
1996 EndMenu();
1998 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
2000 if (is_child)
2002 if (!USER_IsExitingThread( GetCurrentThreadId() ))
2003 send_parent_notify( hwnd, WM_DESTROY );
2005 else if (!GetWindow( hwnd, GW_OWNER ))
2007 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2008 /* FIXME: clean up palette - see "Internals" p.352 */
2011 if (!IsWindow(hwnd)) return TRUE;
2013 /* Hide the window */
2014 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
2016 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2017 if (is_child)
2018 ShowWindow( hwnd, SW_HIDE );
2019 else
2020 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
2021 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
2024 if (!IsWindow(hwnd)) return TRUE;
2026 /* Recursively destroy owned windows */
2028 if (!is_child)
2030 for (;;)
2032 int i;
2033 BOOL got_one = FALSE;
2034 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2035 if (list)
2037 for (i = 0; list[i]; i++)
2039 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
2040 if (WIN_IsCurrentThread( list[i] ))
2042 DestroyWindow( list[i] );
2043 got_one = TRUE;
2044 continue;
2046 WIN_SetOwner( list[i], 0 );
2048 HeapFree( GetProcessHeap(), 0, list );
2050 if (!got_one) break;
2054 /* Send destroy messages */
2056 WIN_SendDestroyMsg( hwnd );
2057 if (!IsWindow( hwnd )) return TRUE;
2059 /* Destroy the window storage */
2061 WIN_DestroyWindow( hwnd );
2062 return TRUE;
2066 /***********************************************************************
2067 * CloseWindow (USER32.@)
2069 BOOL WINAPI CloseWindow( HWND hwnd )
2071 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
2072 ShowWindow( hwnd, SW_MINIMIZE );
2073 return TRUE;
2077 /***********************************************************************
2078 * OpenIcon (USER32.@)
2080 BOOL WINAPI OpenIcon( HWND hwnd )
2082 if (!IsIconic( hwnd )) return FALSE;
2083 ShowWindow( hwnd, SW_SHOWNORMAL );
2084 return TRUE;
2088 /***********************************************************************
2089 * FindWindowExW (USER32.@)
2091 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
2093 HWND *list;
2094 HWND retvalue = 0;
2095 int i = 0, len = 0;
2096 WCHAR *buffer = NULL;
2098 if (!parent && child) parent = GetDesktopWindow();
2099 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2101 if (title)
2103 len = lstrlenW(title) + 1; /* one extra char to check for chars beyond the end */
2104 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
2107 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
2109 if (child)
2111 child = WIN_GetFullHandle( child );
2112 while (list[i] && list[i] != child) i++;
2113 if (!list[i]) goto done;
2114 i++; /* start from next window */
2117 if (title)
2119 while (list[i])
2121 if (InternalGetWindowText( list[i], buffer, len + 1 ))
2123 if (!wcsicmp( buffer, title )) break;
2125 else
2127 if (!title[0]) break;
2129 i++;
2132 retvalue = list[i];
2134 done:
2135 HeapFree( GetProcessHeap(), 0, list );
2136 HeapFree( GetProcessHeap(), 0, buffer );
2137 return retvalue;
2142 /***********************************************************************
2143 * FindWindowA (USER32.@)
2145 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
2147 HWND ret = FindWindowExA( 0, 0, className, title );
2148 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
2149 return ret;
2153 /***********************************************************************
2154 * FindWindowExA (USER32.@)
2156 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
2158 LPWSTR titleW = NULL;
2159 HWND hwnd = 0;
2161 if (title)
2163 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
2164 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
2165 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
2168 if (!IS_INTRESOURCE(className))
2170 WCHAR classW[256];
2171 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, ARRAY_SIZE( classW )))
2172 hwnd = FindWindowExW( parent, child, classW, titleW );
2174 else
2176 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
2179 HeapFree( GetProcessHeap(), 0, titleW );
2180 return hwnd;
2184 /***********************************************************************
2185 * FindWindowW (USER32.@)
2187 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2189 return FindWindowExW( 0, 0, className, title );
2193 /**********************************************************************
2194 * GetDesktopWindow (USER32.@)
2196 HWND WINAPI GetDesktopWindow(void)
2198 struct user_thread_info *thread_info = get_user_thread_info();
2200 if (thread_info->top_window) return thread_info->top_window;
2202 SERVER_START_REQ( get_desktop_window )
2204 req->force = 0;
2205 if (!wine_server_call( req ))
2207 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2208 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2211 SERVER_END_REQ;
2213 if (!thread_info->top_window)
2215 STARTUPINFOW si;
2216 PROCESS_INFORMATION pi;
2217 WCHAR windir[MAX_PATH];
2218 WCHAR app[MAX_PATH + ARRAY_SIZE( L"\\explorer.exe" )];
2219 WCHAR cmdline[MAX_PATH + ARRAY_SIZE( L"\\explorer.exe /desktop" )];
2220 WCHAR desktop[MAX_PATH];
2221 void *redir;
2223 SERVER_START_REQ( set_user_object_info )
2225 req->handle = wine_server_obj_handle( GetThreadDesktop(GetCurrentThreadId()) );
2226 req->flags = SET_USER_OBJECT_GET_FULL_NAME;
2227 wine_server_set_reply( req, desktop, sizeof(desktop) - sizeof(WCHAR) );
2228 if (!wine_server_call( req ))
2230 size_t size = wine_server_reply_size( reply );
2231 desktop[size / sizeof(WCHAR)] = 0;
2232 TRACE( "starting explorer for desktop %s\n", debugstr_w(desktop) );
2234 else
2235 desktop[0] = 0;
2237 SERVER_END_REQ;
2239 memset( &si, 0, sizeof(si) );
2240 si.cb = sizeof(si);
2241 si.lpDesktop = *desktop ? desktop : NULL;
2242 si.dwFlags = STARTF_USESTDHANDLES;
2243 si.hStdInput = 0;
2244 si.hStdOutput = 0;
2245 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2247 GetSystemDirectoryW( windir, MAX_PATH );
2248 lstrcpyW( app, windir );
2249 lstrcatW( app, L"\\explorer.exe" );
2250 lstrcpyW( cmdline, app );
2251 lstrcatW( cmdline, L" /desktop" );
2253 Wow64DisableWow64FsRedirection( &redir );
2254 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2255 NULL, windir, &si, &pi ))
2257 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2258 WaitForInputIdle( pi.hProcess, 10000 );
2259 CloseHandle( pi.hThread );
2260 CloseHandle( pi.hProcess );
2262 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2263 Wow64RevertWow64FsRedirection( redir );
2265 SERVER_START_REQ( get_desktop_window )
2267 req->force = 1;
2268 if (!wine_server_call( req ))
2270 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2271 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2274 SERVER_END_REQ;
2277 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2278 ERR( "failed to create desktop window\n" );
2280 return thread_info->top_window;
2284 /*******************************************************************
2285 * EnableWindow (USER32.@)
2287 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2289 BOOL retvalue;
2291 if (is_broadcast(hwnd))
2293 SetLastError( ERROR_INVALID_PARAMETER );
2294 return FALSE;
2297 TRACE("( %p, %d )\n", hwnd, enable);
2299 if (enable)
2301 retvalue = (WIN_SetStyle( hwnd, 0, WS_DISABLED ) & WS_DISABLED) != 0;
2302 if (retvalue) SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2304 else
2306 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
2308 retvalue = (WIN_SetStyle( hwnd, WS_DISABLED, 0 ) & WS_DISABLED) != 0;
2309 if (!retvalue)
2311 if (hwnd == GetFocus())
2312 SetFocus( 0 ); /* A disabled window can't have the focus */
2314 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2317 return retvalue;
2321 /***********************************************************************
2322 * IsWindowEnabled (USER32.@)
2324 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2326 LONG ret;
2328 SetLastError(NO_ERROR);
2329 ret = GetWindowLongW( hWnd, GWL_STYLE );
2330 if (!ret && GetLastError() != NO_ERROR) return FALSE;
2331 return !(ret & WS_DISABLED);
2334 /***********************************************************************
2335 * IsWindowUnicode (USER32.@)
2337 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2339 WND * wndPtr;
2340 BOOL retvalue = FALSE;
2342 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2344 if (wndPtr == WND_DESKTOP) return TRUE;
2346 if (wndPtr != WND_OTHER_PROCESS)
2348 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2349 WIN_ReleasePtr( wndPtr );
2351 else
2353 SERVER_START_REQ( get_window_info )
2355 req->handle = wine_server_user_handle( hwnd );
2356 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2358 SERVER_END_REQ;
2360 return retvalue;
2364 /***********************************************************************
2365 * GetWindowDpiAwarenessContext (USER32.@)
2367 DPI_AWARENESS_CONTEXT WINAPI GetWindowDpiAwarenessContext( HWND hwnd )
2369 WND *win;
2370 DPI_AWARENESS_CONTEXT ret = 0;
2372 if (!(win = WIN_GetPtr( hwnd )))
2374 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2375 return 0;
2377 if (win == WND_DESKTOP) return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
2378 if (win != WND_OTHER_PROCESS)
2380 ret = ULongToHandle( win->dpi_awareness | 0x10 );
2381 WIN_ReleasePtr( win );
2383 else
2385 SERVER_START_REQ( get_window_info )
2387 req->handle = wine_server_user_handle( hwnd );
2388 if (!wine_server_call_err( req )) ret = ULongToHandle( reply->awareness | 0x10 );
2390 SERVER_END_REQ;
2392 return ret;
2396 /***********************************************************************
2397 * GetDpiForWindow (USER32.@)
2399 UINT WINAPI GetDpiForWindow( HWND hwnd )
2401 WND *win;
2402 UINT ret = 0;
2404 if (!(win = WIN_GetPtr( hwnd )))
2406 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2407 return 0;
2409 if (win == WND_DESKTOP)
2411 POINT pt = { 0, 0 };
2412 return get_monitor_dpi( MonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY ));
2414 if (win != WND_OTHER_PROCESS)
2416 ret = win->dpi;
2417 if (!ret) ret = get_win_monitor_dpi( hwnd );
2418 WIN_ReleasePtr( win );
2420 else
2422 SERVER_START_REQ( get_window_info )
2424 req->handle = wine_server_user_handle( hwnd );
2425 if (!wine_server_call_err( req )) ret = reply->dpi;
2427 SERVER_END_REQ;
2429 return ret;
2433 /**********************************************************************
2434 * WIN_GetWindowLong
2436 * Helper function for GetWindowLong().
2438 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2440 LONG_PTR retvalue = 0;
2441 WND *wndPtr;
2443 if (offset == GWLP_HWNDPARENT)
2445 HWND parent = GetAncestor( hwnd, GA_PARENT );
2446 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2447 return (ULONG_PTR)parent;
2450 if (!(wndPtr = WIN_GetPtr( hwnd )))
2452 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2453 return 0;
2456 if (wndPtr == WND_DESKTOP)
2458 switch (offset)
2460 case GWL_STYLE:
2461 retvalue = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* message parent is not visible */
2462 if (WIN_GetFullHandle( hwnd ) == GetDesktopWindow())
2463 retvalue |= WS_VISIBLE;
2464 return retvalue;
2465 case GWL_EXSTYLE:
2466 case GWLP_USERDATA:
2467 case GWLP_ID:
2468 case GWLP_HINSTANCE:
2469 return 0;
2470 case GWLP_WNDPROC:
2471 SetLastError( ERROR_ACCESS_DENIED );
2472 return 0;
2474 SetLastError( ERROR_INVALID_INDEX );
2475 return 0;
2478 if (wndPtr == WND_OTHER_PROCESS)
2480 if (offset == GWLP_WNDPROC)
2482 SetLastError( ERROR_ACCESS_DENIED );
2483 return 0;
2485 SERVER_START_REQ( set_window_info )
2487 req->handle = wine_server_user_handle( hwnd );
2488 req->flags = 0; /* don't set anything, just retrieve */
2489 req->extra_offset = (offset >= 0) ? offset : -1;
2490 req->extra_size = (offset >= 0) ? size : 0;
2491 if (!wine_server_call_err( req ))
2493 switch(offset)
2495 case GWL_STYLE: retvalue = reply->old_style; break;
2496 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2497 case GWLP_ID: retvalue = reply->old_id; break;
2498 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2499 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2500 default:
2501 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2502 else SetLastError( ERROR_INVALID_INDEX );
2503 break;
2507 SERVER_END_REQ;
2508 return retvalue;
2511 /* now we have a valid wndPtr */
2513 if (offset >= 0)
2515 if (offset > (int)(wndPtr->cbWndExtra - size))
2517 WARN("Invalid offset %d\n", offset );
2518 WIN_ReleasePtr( wndPtr );
2519 SetLastError( ERROR_INVALID_INDEX );
2520 return 0;
2522 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2524 /* Special case for dialog window procedure */
2525 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2526 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2527 WIN_ReleasePtr( wndPtr );
2528 return retvalue;
2531 switch(offset)
2533 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2534 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2535 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2536 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2537 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2538 case GWLP_WNDPROC:
2539 /* This looks like a hack only for the edit control (see tests). This makes these controls
2540 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2541 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2543 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2544 retvalue = (ULONG_PTR)wndPtr->winproc;
2545 else
2546 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2547 break;
2548 default:
2549 WARN("Unknown offset %d\n", offset );
2550 SetLastError( ERROR_INVALID_INDEX );
2551 break;
2553 WIN_ReleasePtr(wndPtr);
2554 return retvalue;
2558 /**********************************************************************
2559 * WIN_SetWindowLong
2561 * Helper function for SetWindowLong().
2563 * 0 is the failure code. However, in the case of failure SetLastError
2564 * must be set to distinguish between a 0 return value and a failure.
2566 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2568 STYLESTRUCT style;
2569 BOOL ok, made_visible = FALSE;
2570 LONG_PTR retval = 0;
2571 WND *wndPtr;
2573 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2575 if (is_broadcast(hwnd))
2577 SetLastError( ERROR_INVALID_PARAMETER );
2578 return FALSE;
2581 if (!(wndPtr = WIN_GetPtr( hwnd )))
2583 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2584 return 0;
2586 if (wndPtr == WND_DESKTOP)
2588 /* can't change anything on the desktop window */
2589 SetLastError( ERROR_ACCESS_DENIED );
2590 return 0;
2592 if (wndPtr == WND_OTHER_PROCESS)
2594 if (offset == GWLP_WNDPROC)
2596 SetLastError( ERROR_ACCESS_DENIED );
2597 return 0;
2599 if (offset > 32767 || offset < -32767)
2601 SetLastError( ERROR_INVALID_INDEX );
2602 return 0;
2604 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2607 /* first some special cases */
2608 switch( offset )
2610 case GWL_STYLE:
2611 style.styleOld = wndPtr->dwStyle;
2612 style.styleNew = newval;
2613 WIN_ReleasePtr( wndPtr );
2614 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2615 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2616 newval = style.styleNew;
2617 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2618 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2619 /* WS_MINIMIZE can't be reset */
2620 if (wndPtr->dwStyle & WS_MINIMIZE) newval |= WS_MINIMIZE;
2621 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2622 WS_EX_WINDOWEDGE too */
2623 break;
2624 case GWL_EXSTYLE:
2625 style.styleOld = wndPtr->dwExStyle;
2626 style.styleNew = newval;
2627 WIN_ReleasePtr( wndPtr );
2628 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2629 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2630 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2631 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2632 /* WS_EX_WINDOWEDGE depends on some other styles */
2633 if (newval & WS_EX_DLGMODALFRAME)
2634 newval |= WS_EX_WINDOWEDGE;
2635 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2636 newval |= WS_EX_WINDOWEDGE;
2637 else
2638 newval &= ~WS_EX_WINDOWEDGE;
2639 break;
2640 case GWLP_HWNDPARENT:
2641 if (wndPtr->parent == GetDesktopWindow())
2643 WIN_ReleasePtr( wndPtr );
2644 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2646 else
2648 WIN_ReleasePtr( wndPtr );
2649 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2651 case GWLP_WNDPROC:
2653 WNDPROC proc;
2654 UINT old_flags = wndPtr->flags;
2655 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2656 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2657 if (proc) wndPtr->winproc = proc;
2658 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2659 else wndPtr->flags &= ~WIN_ISUNICODE;
2660 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2662 WIN_ReleasePtr( wndPtr );
2663 return retval;
2665 /* update is_unicode flag on the server side */
2666 break;
2668 case GWLP_ID:
2669 case GWLP_HINSTANCE:
2670 case GWLP_USERDATA:
2671 break;
2672 case DWLP_DLGPROC:
2673 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2674 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2676 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2677 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2678 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2679 WIN_ReleasePtr( wndPtr );
2680 return retval;
2682 /* fall through */
2683 default:
2684 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2686 WARN("Invalid offset %d\n", offset );
2687 WIN_ReleasePtr( wndPtr );
2688 SetLastError( ERROR_INVALID_INDEX );
2689 return 0;
2691 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2693 /* already set to the same value */
2694 WIN_ReleasePtr( wndPtr );
2695 return newval;
2697 break;
2700 SERVER_START_REQ( set_window_info )
2702 req->handle = wine_server_user_handle( hwnd );
2703 req->extra_offset = -1;
2704 switch(offset)
2706 case GWL_STYLE:
2707 req->flags = SET_WIN_STYLE;
2708 req->style = newval;
2709 break;
2710 case GWL_EXSTYLE:
2711 req->flags = SET_WIN_EXSTYLE;
2712 req->ex_style = newval;
2713 break;
2714 case GWLP_ID:
2715 req->flags = SET_WIN_ID;
2716 req->id = newval;
2717 break;
2718 case GWLP_HINSTANCE:
2719 req->flags = SET_WIN_INSTANCE;
2720 req->instance = wine_server_client_ptr( (void *)newval );
2721 break;
2722 case GWLP_WNDPROC:
2723 req->flags = SET_WIN_UNICODE;
2724 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2725 break;
2726 case GWLP_USERDATA:
2727 req->flags = SET_WIN_USERDATA;
2728 req->user_data = newval;
2729 break;
2730 default:
2731 req->flags = SET_WIN_EXTRA;
2732 req->extra_offset = offset;
2733 req->extra_size = size;
2734 set_win_data( &req->extra_value, newval, size );
2736 if ((ok = !wine_server_call_err( req )))
2738 switch(offset)
2740 case GWL_STYLE:
2741 wndPtr->dwStyle = newval;
2742 retval = reply->old_style;
2743 break;
2744 case GWL_EXSTYLE:
2745 wndPtr->dwExStyle = newval;
2746 retval = reply->old_ex_style;
2747 break;
2748 case GWLP_ID:
2749 wndPtr->wIDmenu = newval;
2750 retval = reply->old_id;
2751 break;
2752 case GWLP_HINSTANCE:
2753 wndPtr->hInstance = (HINSTANCE)newval;
2754 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2755 break;
2756 case GWLP_WNDPROC:
2757 break;
2758 case GWLP_USERDATA:
2759 wndPtr->userdata = newval;
2760 retval = reply->old_user_data;
2761 break;
2762 default:
2763 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2764 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2765 break;
2769 SERVER_END_REQ;
2771 if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2772 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2774 made_visible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
2775 invalidate_dce( wndPtr, NULL );
2777 WIN_ReleasePtr( wndPtr );
2779 if (!ok) return 0;
2781 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2783 style.styleOld = retval;
2784 style.styleNew = newval;
2785 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2786 if (made_visible) update_window_state( hwnd );
2787 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2790 return retval;
2794 /**********************************************************************
2795 * GetWindowWord (USER32.@)
2797 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2799 switch(offset)
2801 case GWLP_ID:
2802 case GWLP_HINSTANCE:
2803 case GWLP_HWNDPARENT:
2804 break;
2805 default:
2806 if (offset < 0)
2808 WARN("Invalid offset %d\n", offset );
2809 SetLastError( ERROR_INVALID_INDEX );
2810 return 0;
2812 break;
2814 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2818 /**********************************************************************
2819 * GetWindowLongA (USER32.@)
2821 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2823 switch (offset)
2825 #ifdef _WIN64
2826 case GWLP_WNDPROC:
2827 case GWLP_HINSTANCE:
2828 case GWLP_HWNDPARENT:
2829 WARN( "Invalid offset %d\n", offset );
2830 SetLastError( ERROR_INVALID_INDEX );
2831 return 0;
2832 #endif
2833 default:
2834 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2839 /**********************************************************************
2840 * GetWindowLongW (USER32.@)
2842 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2844 switch (offset)
2846 #ifdef _WIN64
2847 case GWLP_WNDPROC:
2848 case GWLP_HINSTANCE:
2849 case GWLP_HWNDPARENT:
2850 WARN( "Invalid offset %d\n", offset );
2851 SetLastError( ERROR_INVALID_INDEX );
2852 return 0;
2853 #endif
2854 default:
2855 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2860 /**********************************************************************
2861 * SetWindowWord (USER32.@)
2863 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2865 switch(offset)
2867 case GWLP_ID:
2868 case GWLP_HINSTANCE:
2869 case GWLP_HWNDPARENT:
2870 break;
2871 default:
2872 if (offset < 0)
2874 WARN("Invalid offset %d\n", offset );
2875 SetLastError( ERROR_INVALID_INDEX );
2876 return 0;
2878 break;
2880 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2884 /**********************************************************************
2885 * SetWindowLongA (USER32.@)
2887 * See SetWindowLongW.
2889 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2891 switch (offset)
2893 #ifdef _WIN64
2894 case GWLP_WNDPROC:
2895 case GWLP_HINSTANCE:
2896 case GWLP_HWNDPARENT:
2897 WARN( "Invalid offset %d\n", offset );
2898 SetLastError( ERROR_INVALID_INDEX );
2899 return 0;
2900 #endif
2901 default:
2902 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2907 /**********************************************************************
2908 * SetWindowLongW (USER32.@) Set window attribute
2910 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2911 * value in a window's extra memory.
2913 * The _hwnd_ parameter specifies the handle to a window that
2914 * has extra memory. The _newval_ parameter contains the new
2915 * attribute or extra memory value. If positive, the _offset_
2916 * parameter is the byte-addressed location in the window's extra
2917 * memory to set. If negative, _offset_ specifies the window
2918 * attribute to set, and should be one of the following values:
2920 * GWL_EXSTYLE The window's extended window style
2922 * GWL_STYLE The window's window style.
2924 * GWLP_WNDPROC Pointer to the window's window procedure.
2926 * GWLP_HINSTANCE The window's application instance handle.
2928 * GWLP_ID The window's identifier.
2930 * GWLP_USERDATA The window's user-specified data.
2932 * If the window is a dialog box, the _offset_ parameter can be one of
2933 * the following values:
2935 * DWLP_DLGPROC The address of the window's dialog box procedure.
2937 * DWLP_MSGRESULT The return value of a message
2938 * that the dialog box procedure processed.
2940 * DWLP_USER Application specific information.
2942 * RETURNS
2944 * If successful, returns the previous value located at _offset_. Otherwise,
2945 * returns 0.
2947 * NOTES
2949 * Extra memory for a window class is specified by a nonzero cbWndExtra
2950 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2951 * time of class creation.
2953 * Using GWL_WNDPROC to set a new window procedure effectively creates
2954 * a window subclass. Use CallWindowProc() in the new windows procedure
2955 * to pass messages to the superclass's window procedure.
2957 * The user data is reserved for use by the application which created
2958 * the window.
2960 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2961 * instead, call the EnableWindow() function to change the window's
2962 * disabled state.
2964 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2965 * SetParent() instead.
2967 * Win95:
2968 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2969 * it sends WM_STYLECHANGING before changing the settings
2970 * and WM_STYLECHANGED afterwards.
2971 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2973 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongW(
2974 HWND hwnd, /* [in] window to alter */
2975 INT offset, /* [in] offset, in bytes, of location to alter */
2976 LONG newval /* [in] new value of location */
2979 switch (offset)
2981 #ifdef _WIN64
2982 case GWLP_WNDPROC:
2983 case GWLP_HINSTANCE:
2984 case GWLP_HWNDPARENT:
2985 WARN("Invalid offset %d\n", offset );
2986 SetLastError( ERROR_INVALID_INDEX );
2987 return 0;
2988 #endif
2989 default:
2990 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2995 /*******************************************************************
2996 * GetWindowTextA (USER32.@)
2998 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
3000 WCHAR *buffer;
3002 if (!lpString || nMaxCount <= 0) return 0;
3004 if (WIN_IsCurrentProcess( hwnd ))
3006 lpString[0] = 0;
3007 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
3010 /* when window belongs to other process, don't send a message */
3011 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
3012 get_server_window_text( hwnd, buffer, nMaxCount );
3013 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
3014 lpString[nMaxCount-1] = 0;
3015 HeapFree( GetProcessHeap(), 0, buffer );
3016 return strlen(lpString);
3020 /*******************************************************************
3021 * InternalGetWindowText (USER32.@)
3023 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
3025 WND *win;
3027 if (nMaxCount <= 0) return 0;
3028 if (!(win = WIN_GetPtr( hwnd ))) return 0;
3029 if (win == WND_DESKTOP) lpString[0] = 0;
3030 else if (win != WND_OTHER_PROCESS)
3032 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
3033 else lpString[0] = 0;
3034 WIN_ReleasePtr( win );
3036 else
3038 get_server_window_text( hwnd, lpString, nMaxCount );
3040 return lstrlenW(lpString);
3044 /*******************************************************************
3045 * GetWindowTextW (USER32.@)
3047 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
3049 if (!lpString || nMaxCount <= 0) return 0;
3051 if (WIN_IsCurrentProcess( hwnd ))
3053 lpString[0] = 0;
3054 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
3057 /* when window belongs to other process, don't send a message */
3058 get_server_window_text( hwnd, lpString, nMaxCount );
3059 return lstrlenW(lpString);
3063 /*******************************************************************
3064 * SetWindowTextA (USER32.@)
3065 * SetWindowText (USER32.@)
3067 BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextA( HWND hwnd, LPCSTR lpString )
3069 if (is_broadcast(hwnd))
3071 SetLastError( ERROR_INVALID_PARAMETER );
3072 return FALSE;
3074 if (!WIN_IsCurrentProcess( hwnd ))
3075 WARN( "setting text %s of other process window %p should not use SendMessage\n",
3076 debugstr_a(lpString), hwnd );
3077 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
3081 /*******************************************************************
3082 * SetWindowTextW (USER32.@)
3084 BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextW( HWND hwnd, LPCWSTR lpString )
3086 if (is_broadcast(hwnd))
3088 SetLastError( ERROR_INVALID_PARAMETER );
3089 return FALSE;
3091 if (!WIN_IsCurrentProcess( hwnd ))
3092 WARN( "setting text %s of other process window %p should not use SendMessage\n",
3093 debugstr_w(lpString), hwnd );
3094 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
3098 /*******************************************************************
3099 * GetWindowTextLengthA (USER32.@)
3101 INT WINAPI GetWindowTextLengthA( HWND hwnd )
3103 CPINFO info;
3105 if (WIN_IsCurrentProcess( hwnd )) return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
3107 /* when window belongs to other process, don't send a message */
3108 GetCPInfo( CP_ACP, &info );
3109 return get_server_window_text( hwnd, NULL, 0 ) * info.MaxCharSize;
3112 /*******************************************************************
3113 * GetWindowTextLengthW (USER32.@)
3115 INT WINAPI GetWindowTextLengthW( HWND hwnd )
3117 if (WIN_IsCurrentProcess( hwnd )) return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
3119 /* when window belongs to other process, don't send a message */
3120 return get_server_window_text( hwnd, NULL, 0 );
3124 /*******************************************************************
3125 * IsWindow (USER32.@)
3127 BOOL WINAPI IsWindow( HWND hwnd )
3129 WND *ptr;
3130 BOOL ret;
3132 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
3133 if (ptr == WND_DESKTOP) return TRUE;
3135 if (ptr != WND_OTHER_PROCESS)
3137 WIN_ReleasePtr( ptr );
3138 return TRUE;
3141 /* check other processes */
3142 SERVER_START_REQ( get_window_info )
3144 req->handle = wine_server_user_handle( hwnd );
3145 ret = !wine_server_call_err( req );
3147 SERVER_END_REQ;
3148 return ret;
3152 /***********************************************************************
3153 * GetWindowThreadProcessId (USER32.@)
3155 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
3157 WND *ptr;
3158 DWORD tid = 0;
3160 if (!(ptr = WIN_GetPtr( hwnd )))
3162 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
3163 return 0;
3166 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
3168 /* got a valid window */
3169 tid = ptr->tid;
3170 if (process) *process = GetCurrentProcessId();
3171 WIN_ReleasePtr( ptr );
3172 return tid;
3175 /* check other processes */
3176 SERVER_START_REQ( get_window_info )
3178 req->handle = wine_server_user_handle( hwnd );
3179 if (!wine_server_call_err( req ))
3181 tid = (DWORD)reply->tid;
3182 if (process) *process = (DWORD)reply->pid;
3185 SERVER_END_REQ;
3186 return tid;
3190 /*****************************************************************
3191 * GetParent (USER32.@)
3193 HWND WINAPI GetParent( HWND hwnd )
3195 WND *wndPtr;
3196 HWND retvalue = 0;
3198 if (!(wndPtr = WIN_GetPtr( hwnd )))
3200 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3201 return 0;
3203 if (wndPtr == WND_DESKTOP) return 0;
3204 if (wndPtr == WND_OTHER_PROCESS)
3206 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3207 if (style & (WS_POPUP | WS_CHILD))
3209 SERVER_START_REQ( get_window_tree )
3211 req->handle = wine_server_user_handle( hwnd );
3212 if (!wine_server_call_err( req ))
3214 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
3215 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
3218 SERVER_END_REQ;
3221 else
3223 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
3224 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
3225 WIN_ReleasePtr( wndPtr );
3227 return retvalue;
3231 /*****************************************************************
3232 * GetAncestor (USER32.@)
3234 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
3236 WND *win;
3237 HWND *list, ret = 0;
3239 switch(type)
3241 case GA_PARENT:
3242 if (!(win = WIN_GetPtr( hwnd )))
3244 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3245 return 0;
3247 if (win == WND_DESKTOP) return 0;
3248 if (win != WND_OTHER_PROCESS)
3250 ret = win->parent;
3251 WIN_ReleasePtr( win );
3253 else /* need to query the server */
3255 SERVER_START_REQ( get_window_tree )
3257 req->handle = wine_server_user_handle( hwnd );
3258 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
3260 SERVER_END_REQ;
3262 break;
3264 case GA_ROOT:
3265 if (!(list = list_window_parents( hwnd ))) return 0;
3267 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
3268 else
3270 int count = 2;
3271 while (list[count]) count++;
3272 ret = list[count - 2]; /* get the one before the desktop */
3274 HeapFree( GetProcessHeap(), 0, list );
3275 break;
3277 case GA_ROOTOWNER:
3278 if (is_desktop_window( hwnd )) return 0;
3279 ret = WIN_GetFullHandle( hwnd );
3280 for (;;)
3282 HWND parent = GetParent( ret );
3283 if (!parent) break;
3284 ret = parent;
3286 break;
3288 return ret;
3292 /*****************************************************************
3293 * SetParent (USER32.@)
3295 HWND WINAPI SetParent( HWND hwnd, HWND parent )
3297 WINDOWPOS winpos;
3298 HWND full_handle;
3299 HWND old_parent = 0;
3300 BOOL was_visible;
3301 WND *wndPtr;
3302 BOOL ret;
3303 DPI_AWARENESS_CONTEXT context;
3304 RECT window_rect, old_screen_rect, new_screen_rect;
3306 TRACE("(%p %p)\n", hwnd, parent);
3308 if (is_broadcast(hwnd) || is_broadcast(parent))
3310 SetLastError(ERROR_INVALID_PARAMETER);
3311 return 0;
3314 if (!parent) parent = GetDesktopWindow();
3315 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
3316 else parent = WIN_GetFullHandle( parent );
3318 if (!IsWindow( parent ))
3320 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3321 return 0;
3324 /* Some applications try to set a child as a parent */
3325 if (IsChild(hwnd, parent))
3327 SetLastError( ERROR_INVALID_PARAMETER );
3328 return 0;
3331 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
3332 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
3334 if (full_handle == parent)
3336 SetLastError( ERROR_INVALID_PARAMETER );
3337 return 0;
3340 /* Windows hides the window first, then shows it again
3341 * including the WM_SHOWWINDOW messages and all */
3342 was_visible = ShowWindow( hwnd, SW_HIDE );
3344 wndPtr = WIN_GetPtr( hwnd );
3345 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
3347 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
3348 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, NULL );
3349 SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3350 WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_screen_rect, NULL );
3351 SetThreadDpiAwarenessContext( context );
3353 SERVER_START_REQ( set_parent )
3355 req->handle = wine_server_user_handle( hwnd );
3356 req->parent = wine_server_user_handle( parent );
3357 if ((ret = !wine_server_call( req )))
3359 old_parent = wine_server_ptr_handle( reply->old_parent );
3360 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3361 wndPtr->dpi = reply->dpi;
3362 wndPtr->dpi_awareness = reply->awareness;
3366 SERVER_END_REQ;
3367 WIN_ReleasePtr( wndPtr );
3368 if (!ret) return 0;
3370 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3371 WIN_GetRectangles( hwnd, COORDS_SCREEN, &new_screen_rect, NULL );
3372 SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
3374 USER_Driver->pSetParent( full_handle, parent, old_parent );
3376 winpos.hwnd = hwnd;
3377 winpos.hwndInsertAfter = HWND_TOP;
3378 winpos.x = window_rect.left;
3379 winpos.y = window_rect.top;
3380 winpos.cx = 0;
3381 winpos.cy = 0;
3382 winpos.flags = SWP_NOSIZE;
3384 USER_SetWindowPos( &winpos, new_screen_rect.left - old_screen_rect.left,
3385 new_screen_rect.top - old_screen_rect.top );
3387 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3389 SetThreadDpiAwarenessContext( context );
3390 return old_parent;
3394 /*******************************************************************
3395 * IsChild (USER32.@)
3397 BOOL WINAPI IsChild( HWND parent, HWND child )
3399 HWND *list;
3400 int i;
3401 BOOL ret = FALSE;
3403 if (!(GetWindowLongW( child, GWL_STYLE ) & WS_CHILD)) return FALSE;
3404 if (!(list = list_window_parents( child ))) return FALSE;
3405 parent = WIN_GetFullHandle( parent );
3406 for (i = 0; list[i]; i++)
3408 if (list[i] == parent)
3410 ret = list[i] && list[i+1];
3411 break;
3413 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_CHILD)) break;
3415 HeapFree( GetProcessHeap(), 0, list );
3416 return ret;
3420 /***********************************************************************
3421 * IsWindowVisible (USER32.@)
3423 BOOL WINAPI IsWindowVisible( HWND hwnd )
3425 HWND *list;
3426 BOOL retval = TRUE;
3427 int i;
3429 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3430 if (!(list = list_window_parents( hwnd ))) return TRUE;
3431 if (list[0])
3433 for (i = 0; list[i+1]; i++)
3434 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3435 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3437 HeapFree( GetProcessHeap(), 0, list );
3438 return retval;
3442 /***********************************************************************
3443 * WIN_IsWindowDrawable
3445 * hwnd is drawable when it is visible, all parents are not
3446 * minimized, and it is itself not minimized unless we are
3447 * trying to draw its default class icon.
3449 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3451 HWND *list;
3452 BOOL retval = TRUE;
3453 int i;
3454 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3456 if (!(style & WS_VISIBLE)) return FALSE;
3457 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3459 if (!(list = list_window_parents( hwnd ))) return TRUE;
3460 if (list[0])
3462 for (i = 0; list[i+1]; i++)
3463 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3464 break;
3465 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3467 HeapFree( GetProcessHeap(), 0, list );
3468 return retval;
3472 /*******************************************************************
3473 * GetTopWindow (USER32.@)
3475 HWND WINAPI GetTopWindow( HWND hwnd )
3477 if (!hwnd) hwnd = GetDesktopWindow();
3478 return GetWindow( hwnd, GW_CHILD );
3482 /*******************************************************************
3483 * GetWindow (USER32.@)
3485 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3487 HWND retval = 0;
3489 if (rel == GW_OWNER) /* this one may be available locally */
3491 WND *wndPtr = WIN_GetPtr( hwnd );
3492 if (!wndPtr)
3494 SetLastError( ERROR_INVALID_HANDLE );
3495 return 0;
3497 if (wndPtr == WND_DESKTOP) return 0;
3498 if (wndPtr != WND_OTHER_PROCESS)
3500 retval = wndPtr->owner;
3501 WIN_ReleasePtr( wndPtr );
3502 return retval;
3504 /* else fall through to server call */
3507 SERVER_START_REQ( get_window_tree )
3509 req->handle = wine_server_user_handle( hwnd );
3510 if (!wine_server_call_err( req ))
3512 switch(rel)
3514 case GW_HWNDFIRST:
3515 retval = wine_server_ptr_handle( reply->first_sibling );
3516 break;
3517 case GW_HWNDLAST:
3518 retval = wine_server_ptr_handle( reply->last_sibling );
3519 break;
3520 case GW_HWNDNEXT:
3521 retval = wine_server_ptr_handle( reply->next_sibling );
3522 break;
3523 case GW_HWNDPREV:
3524 retval = wine_server_ptr_handle( reply->prev_sibling );
3525 break;
3526 case GW_OWNER:
3527 retval = wine_server_ptr_handle( reply->owner );
3528 break;
3529 case GW_CHILD:
3530 retval = wine_server_ptr_handle( reply->first_child );
3531 break;
3535 SERVER_END_REQ;
3536 return retval;
3540 /*******************************************************************
3541 * ShowOwnedPopups (USER32.@)
3543 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3545 int count = 0;
3546 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3548 if (!win_array) return TRUE;
3550 while (win_array[count]) count++;
3551 while (--count >= 0)
3553 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3554 if (fShow)
3556 if (win_get_flags( win_array[count] ) & WIN_NEEDS_SHOW_OWNEDPOPUP)
3557 /* In Windows, ShowOwnedPopups(TRUE) generates
3558 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3559 * regardless of the state of the owner
3561 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3563 else
3565 if (GetWindowLongW( win_array[count], GWL_STYLE ) & WS_VISIBLE)
3566 /* In Windows, ShowOwnedPopups(FALSE) generates
3567 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3568 * regardless of the state of the owner
3570 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3573 HeapFree( GetProcessHeap(), 0, win_array );
3574 return TRUE;
3578 /*******************************************************************
3579 * GetLastActivePopup (USER32.@)
3581 HWND WINAPI GetLastActivePopup( HWND hwnd )
3583 HWND retval = hwnd;
3585 SERVER_START_REQ( get_window_info )
3587 req->handle = wine_server_user_handle( hwnd );
3588 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3590 SERVER_END_REQ;
3591 return retval;
3595 /*******************************************************************
3596 * WIN_ListChildren
3598 * Build an array of the children of a given window. The array must be
3599 * freed with HeapFree. Returns NULL when no windows are found.
3601 HWND *WIN_ListChildren( HWND hwnd )
3603 if (!hwnd)
3605 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3606 return NULL;
3608 return list_window_children( 0, hwnd, NULL, 0 );
3612 /*******************************************************************
3613 * EnumWindows (USER32.@)
3615 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3617 HWND *list;
3618 BOOL ret = TRUE;
3619 int i;
3621 USER_CheckNotLock();
3623 /* We have to build a list of all windows first, to avoid */
3624 /* unpleasant side-effects, for instance if the callback */
3625 /* function changes the Z-order of the windows. */
3627 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3629 /* Now call the callback function for every window */
3631 for (i = 0; list[i]; i++)
3633 /* Make sure that the window still exists */
3634 if (!IsWindow( list[i] )) continue;
3635 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3637 HeapFree( GetProcessHeap(), 0, list );
3638 return ret;
3642 /**********************************************************************
3643 * EnumThreadWindows (USER32.@)
3645 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3647 HWND *list;
3648 int i;
3649 BOOL ret = TRUE;
3651 USER_CheckNotLock();
3653 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3655 /* Now call the callback function for every window */
3657 for (i = 0; list[i]; i++)
3658 if (!(ret = func( list[i], lParam ))) break;
3659 HeapFree( GetProcessHeap(), 0, list );
3660 return ret;
3664 /***********************************************************************
3665 * EnumDesktopWindows (USER32.@)
3667 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3669 HWND *list;
3670 int i;
3672 USER_CheckNotLock();
3674 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3676 for (i = 0; list[i]; i++)
3677 if (!func( list[i], lparam )) break;
3678 HeapFree( GetProcessHeap(), 0, list );
3679 return TRUE;
3683 #ifdef __i386__
3684 /* Some apps pass a non-stdcall proc to EnumChildWindows,
3685 * so we need a small assembly wrapper to call the proc.
3687 extern LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam );
3688 __ASM_GLOBAL_FUNC( enum_callback_wrapper,
3689 "pushl %ebp\n\t"
3690 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
3691 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
3692 "movl %esp,%ebp\n\t"
3693 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
3694 "pushl 16(%ebp)\n\t"
3695 "pushl 12(%ebp)\n\t"
3696 "call *8(%ebp)\n\t"
3697 "leave\n\t"
3698 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
3699 __ASM_CFI(".cfi_same_value %ebp\n\t")
3700 "ret" )
3701 #else
3702 static inline LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam )
3704 return proc( hwnd, lparam );
3706 #endif /* __i386__ */
3708 /**********************************************************************
3709 * WIN_EnumChildWindows
3711 * Helper function for EnumChildWindows().
3713 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3715 HWND *childList;
3716 BOOL ret = FALSE;
3718 for ( ; *list; list++)
3720 /* Make sure that the window still exists */
3721 if (!IsWindow( *list )) continue;
3722 /* Build children list first */
3723 childList = WIN_ListChildren( *list );
3725 ret = enum_callback_wrapper( func, *list, lParam );
3727 if (childList)
3729 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3730 HeapFree( GetProcessHeap(), 0, childList );
3732 if (!ret) return FALSE;
3734 return TRUE;
3738 /**********************************************************************
3739 * EnumChildWindows (USER32.@)
3741 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3743 HWND *list;
3744 BOOL ret;
3746 USER_CheckNotLock();
3748 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3749 ret = WIN_EnumChildWindows( list, func, lParam );
3750 HeapFree( GetProcessHeap(), 0, list );
3751 return ret;
3755 /*******************************************************************
3756 * AnyPopup (USER32.@)
3758 BOOL WINAPI AnyPopup(void)
3760 int i;
3761 BOOL retvalue;
3762 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3764 if (!list) return FALSE;
3765 for (i = 0; list[i]; i++)
3767 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3769 retvalue = (list[i] != 0);
3770 HeapFree( GetProcessHeap(), 0, list );
3771 return retvalue;
3775 /*******************************************************************
3776 * FlashWindow (USER32.@)
3778 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3780 FLASHWINFO finfo;
3782 finfo.cbSize = sizeof(FLASHWINFO);
3783 finfo.dwFlags = bInvert ? FLASHW_ALL : FLASHW_STOP;
3784 finfo.uCount = 1;
3785 finfo.dwTimeout = 0;
3786 finfo.hwnd = hWnd;
3787 return FlashWindowEx( &finfo );
3790 /*******************************************************************
3791 * FlashWindowEx (USER32.@)
3793 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfinfo )
3795 WND *wndPtr;
3797 TRACE( "%p\n", pfinfo );
3799 if (!pfinfo)
3801 SetLastError( ERROR_NOACCESS );
3802 return FALSE;
3805 if (!pfinfo->hwnd || pfinfo->cbSize != sizeof(FLASHWINFO) || !IsWindow( pfinfo->hwnd ))
3807 SetLastError( ERROR_INVALID_PARAMETER );
3808 return FALSE;
3810 FIXME( "%p - semi-stub\n", pfinfo );
3812 if (IsIconic( pfinfo->hwnd ))
3814 RedrawWindow( pfinfo->hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3816 wndPtr = WIN_GetPtr( pfinfo->hwnd );
3817 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3818 if (pfinfo->dwFlags && !(wndPtr->flags & WIN_NCACTIVATED))
3820 wndPtr->flags |= WIN_NCACTIVATED;
3822 else
3824 wndPtr->flags &= ~WIN_NCACTIVATED;
3826 WIN_ReleasePtr( wndPtr );
3827 USER_Driver->pFlashWindowEx( pfinfo );
3828 return TRUE;
3830 else
3832 WPARAM wparam;
3833 HWND hwnd = pfinfo->hwnd;
3835 wndPtr = WIN_GetPtr( hwnd );
3836 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3837 hwnd = wndPtr->obj.handle; /* make it a full handle */
3839 if (pfinfo->dwFlags) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3840 else wparam = (hwnd == GetForegroundWindow());
3842 WIN_ReleasePtr( wndPtr );
3843 SendMessageW( hwnd, WM_NCACTIVATE, wparam, 0 );
3844 USER_Driver->pFlashWindowEx( pfinfo );
3845 return wparam;
3849 /*******************************************************************
3850 * GetWindowContextHelpId (USER32.@)
3852 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3854 DWORD retval;
3855 WND *wnd = WIN_GetPtr( hwnd );
3856 if (!wnd || wnd == WND_DESKTOP) return 0;
3857 if (wnd == WND_OTHER_PROCESS)
3859 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3860 return 0;
3862 retval = wnd->helpContext;
3863 WIN_ReleasePtr( wnd );
3864 return retval;
3868 /*******************************************************************
3869 * SetWindowContextHelpId (USER32.@)
3871 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3873 WND *wnd = WIN_GetPtr( hwnd );
3874 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3875 if (wnd == WND_OTHER_PROCESS)
3877 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3878 return FALSE;
3880 wnd->helpContext = id;
3881 WIN_ReleasePtr( wnd );
3882 return TRUE;
3886 /*******************************************************************
3887 * DragDetect (USER32.@)
3889 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3891 MSG msg;
3892 RECT rect;
3893 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3894 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3896 SetRect(&rect, pt.x - wDragWidth, pt.y - wDragHeight, pt.x + wDragWidth, pt.y + wDragHeight);
3898 SetCapture(hWnd);
3900 while(1)
3902 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3904 if( msg.message == WM_LBUTTONUP )
3906 ReleaseCapture();
3907 return FALSE;
3909 if( msg.message == WM_MOUSEMOVE )
3911 POINT tmp;
3912 tmp.x = (short)LOWORD(msg.lParam);
3913 tmp.y = (short)HIWORD(msg.lParam);
3914 if( !PtInRect( &rect, tmp ))
3916 ReleaseCapture();
3917 return TRUE;
3921 WaitMessage();
3923 return FALSE;
3926 /******************************************************************************
3927 * GetWindowModuleFileNameA (USER32.@)
3929 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3931 WND *win;
3932 HINSTANCE hinst;
3934 TRACE( "%p, %p, %u\n", hwnd, module, size );
3936 win = WIN_GetPtr( hwnd );
3937 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3939 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3940 return 0;
3942 hinst = win->hInstance;
3943 WIN_ReleasePtr( win );
3945 return GetModuleFileNameA( hinst, module, size );
3948 /******************************************************************************
3949 * GetWindowModuleFileNameW (USER32.@)
3951 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3953 WND *win;
3954 HINSTANCE hinst;
3956 TRACE( "%p, %p, %u\n", hwnd, module, size );
3958 win = WIN_GetPtr( hwnd );
3959 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3961 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3962 return 0;
3964 hinst = win->hInstance;
3965 WIN_ReleasePtr( win );
3967 return GetModuleFileNameW( hinst, module, size );
3970 /******************************************************************************
3971 * GetWindowInfo (USER32.@)
3973 * Note: tests show that Windows doesn't check cbSize of the structure.
3975 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3977 RECT rcWindow, rcClient;
3979 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &rcWindow, &rcClient )) return FALSE;
3980 if (!pwi) return FALSE;
3982 pwi->rcWindow = rcWindow;
3983 pwi->rcClient = rcClient;
3984 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3985 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3986 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3988 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3989 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3991 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3992 pwi->wCreatorVersion = 0x0400;
3994 return TRUE;
3997 /******************************************************************************
3998 * SwitchDesktop (USER32.@)
4000 * NOTES: Sets the current input or interactive desktop.
4002 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
4004 FIXME("(hwnd %p) stub!\n", hDesktop);
4005 return TRUE;
4009 /***********************************************************************
4010 * __wine_set_pixel_format
4012 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
4014 WND *win = WIN_GetPtr( hwnd );
4016 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
4018 WARN( "setting format %d on win %p not supported\n", format, hwnd );
4019 return FALSE;
4021 win->pixel_format = format;
4022 WIN_ReleasePtr( win );
4024 update_window_state( hwnd );
4025 return TRUE;
4029 /*****************************************************************************
4030 * SetLayeredWindowAttributes (USER32.@)
4032 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
4034 BOOL ret;
4036 TRACE("(%p,%08x,%d,%x)\n", hwnd, key, alpha, flags);
4038 SERVER_START_REQ( set_window_layered_info )
4040 req->handle = wine_server_user_handle( hwnd );
4041 req->color_key = key;
4042 req->alpha = alpha;
4043 req->flags = flags;
4044 ret = !wine_server_call_err( req );
4046 SERVER_END_REQ;
4048 if (ret)
4050 USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
4051 update_window_state( hwnd );
4054 return ret;
4058 /*****************************************************************************
4059 * GetLayeredWindowAttributes (USER32.@)
4061 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
4063 BOOL ret;
4065 SERVER_START_REQ( get_window_layered_info )
4067 req->handle = wine_server_user_handle( hwnd );
4068 if ((ret = !wine_server_call_err( req )))
4070 if (key) *key = reply->color_key;
4071 if (alpha) *alpha = reply->alpha;
4072 if (flags) *flags = reply->flags;
4075 SERVER_END_REQ;
4077 return ret;
4081 /*****************************************************************************
4082 * UpdateLayeredWindowIndirect (USER32.@)
4084 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
4086 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
4087 RECT window_rect, client_rect;
4088 SIZE offset;
4090 if (!info ||
4091 info->cbSize != sizeof(*info) ||
4092 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
4093 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
4094 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
4096 SetLastError( ERROR_INVALID_PARAMETER );
4097 return FALSE;
4100 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
4102 if (info->pptDst)
4104 offset.cx = info->pptDst->x - window_rect.left;
4105 offset.cy = info->pptDst->y - window_rect.top;
4106 OffsetRect( &client_rect, offset.cx, offset.cy );
4107 OffsetRect( &window_rect, offset.cx, offset.cy );
4108 flags &= ~SWP_NOMOVE;
4110 if (info->psize)
4112 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
4113 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
4114 if (info->psize->cx <= 0 || info->psize->cy <= 0)
4116 SetLastError( ERROR_INVALID_PARAMETER );
4117 return FALSE;
4119 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
4121 SetLastError( ERROR_INCORRECT_SIZE );
4122 return FALSE;
4124 client_rect.right += offset.cx;
4125 client_rect.bottom += offset.cy;
4126 window_rect.right += offset.cx;
4127 window_rect.bottom += offset.cy;
4128 flags &= ~SWP_NOSIZE;
4131 TRACE( "window %p win %s client %s\n", hwnd,
4132 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
4134 if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
4136 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
4137 return TRUE;
4141 /*****************************************************************************
4142 * UpdateLayeredWindow (USER32.@)
4144 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
4145 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
4146 DWORD flags)
4148 UPDATELAYEREDWINDOWINFO info;
4150 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
4152 SetLastError( ERROR_INVALID_PARAMETER );
4153 return FALSE;
4155 info.cbSize = sizeof(info);
4156 info.hdcDst = hdcDst;
4157 info.pptDst = pptDst;
4158 info.psize = psize;
4159 info.hdcSrc = hdcSrc;
4160 info.pptSrc = pptSrc;
4161 info.crKey = crKey;
4162 info.pblend = pblend;
4163 info.dwFlags = flags;
4164 info.prcDirty = NULL;
4165 return UpdateLayeredWindowIndirect( hwnd, &info );
4169 /******************************************************************************
4170 * GetProcessDefaultLayout [USER32.@]
4172 * Gets the default layout for parentless windows.
4174 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
4176 if (!layout)
4178 SetLastError( ERROR_NOACCESS );
4179 return FALSE;
4181 if (process_layout == ~0u)
4183 WCHAR *str, buffer[MAX_PATH];
4184 DWORD i, len, version_layout = 0;
4185 DWORD user_lang = GetUserDefaultLangID();
4186 DWORD *languages;
4187 void *data = NULL;
4189 GetModuleFileNameW( 0, buffer, MAX_PATH );
4190 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
4191 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
4192 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
4193 if (!VerQueryValueW( data, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done;
4195 len /= sizeof(DWORD);
4196 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
4197 if (i == len) /* try neutral language */
4198 for (i = 0; i < len; i++)
4199 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
4200 if (i == len) i = 0; /* default to the first one */
4202 swprintf( buffer, ARRAY_SIZE(buffer), L"\\StringFileInfo\\%04x%04x\\FileDescription",
4203 LOWORD(languages[i]), HIWORD(languages[i]) );
4204 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
4205 TRACE( "found description %s\n", debugstr_w( str ));
4206 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
4208 done:
4209 HeapFree( GetProcessHeap(), 0, data );
4210 process_layout = version_layout;
4212 *layout = process_layout;
4213 return TRUE;
4217 /******************************************************************************
4218 * SetProcessDefaultLayout [USER32.@]
4220 * Sets the default layout for parentless windows.
4222 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
4224 process_layout = layout;
4225 return TRUE;
4229 /* 64bit versions */
4231 #ifdef GetWindowLongPtrW
4232 #undef GetWindowLongPtrW
4233 #endif
4235 #ifdef GetWindowLongPtrA
4236 #undef GetWindowLongPtrA
4237 #endif
4239 #ifdef SetWindowLongPtrW
4240 #undef SetWindowLongPtrW
4241 #endif
4243 #ifdef SetWindowLongPtrA
4244 #undef SetWindowLongPtrA
4245 #endif
4247 /*****************************************************************************
4248 * GetWindowLongPtrW (USER32.@)
4250 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
4252 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
4255 /*****************************************************************************
4256 * GetWindowLongPtrA (USER32.@)
4258 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
4260 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
4263 /*****************************************************************************
4264 * SetWindowLongPtrW (USER32.@)
4266 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
4268 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
4271 /*****************************************************************************
4272 * SetWindowLongPtrA (USER32.@)
4274 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
4276 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
4279 /*****************************************************************************
4280 * RegisterTouchWindow (USER32.@)
4282 BOOL WINAPI RegisterTouchWindow(HWND hwnd, ULONG flags)
4284 FIXME("(%p %08x): stub\n", hwnd, flags);
4285 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4286 return FALSE;
4289 /*****************************************************************************
4290 * UnregisterTouchWindow (USER32.@)
4292 BOOL WINAPI UnregisterTouchWindow(HWND hwnd)
4294 FIXME("(%p): stub\n", hwnd);
4295 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4296 return FALSE;
4299 /*****************************************************************************
4300 * CloseTouchInputHandle (USER32.@)
4302 BOOL WINAPI CloseTouchInputHandle(HTOUCHINPUT handle)
4304 FIXME("(%p): stub\n", handle);
4305 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4306 return FALSE;
4309 /*****************************************************************************
4310 * GetTouchInputInfo (USER32.@)
4312 BOOL WINAPI GetTouchInputInfo(HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size)
4314 FIXME("(%p %u %p %u): stub\n", handle, count, ptr, size);
4315 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4316 return FALSE;
4319 /*****************************************************************************
4320 * GetGestureInfo (USER32.@)
4322 BOOL WINAPI GetGestureInfo(HGESTUREINFO handle, PGESTUREINFO ptr)
4324 FIXME("(%p %p): stub\n", handle, ptr);
4325 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4326 return FALSE;
4329 /*****************************************************************************
4330 * GetWindowDisplayAffinity (USER32.@)
4332 BOOL WINAPI GetWindowDisplayAffinity(HWND hwnd, DWORD *affinity)
4334 FIXME("(%p, %p): stub\n", hwnd, affinity);
4336 if (!hwnd || !affinity)
4338 SetLastError(hwnd ? ERROR_NOACCESS : ERROR_INVALID_WINDOW_HANDLE);
4339 return FALSE;
4342 *affinity = WDA_NONE;
4343 return TRUE;
4346 /*****************************************************************************
4347 * SetWindowDisplayAffinity (USER32.@)
4349 BOOL WINAPI SetWindowDisplayAffinity(HWND hwnd, DWORD affinity)
4351 FIXME("(%p, %u): stub\n", hwnd, affinity);
4353 if (!hwnd)
4355 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
4356 return FALSE;
4359 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4360 return FALSE;
4363 /**********************************************************************
4364 * SetWindowCompositionAttribute (USER32.@)
4366 BOOL WINAPI SetWindowCompositionAttribute(HWND hwnd, void *data)
4368 FIXME("(%p, %p): stub\n", hwnd, data);
4369 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4370 return FALSE;
4373 /***********************************************************************
4374 * InternalGetWindowIcon (USER32.@)
4376 HICON WINAPI InternalGetWindowIcon( HWND hwnd, UINT type )
4378 WND *win = WIN_GetPtr( hwnd );
4379 HICON ret;
4381 TRACE( "hwnd %p, type %#x\n", hwnd, type );
4383 if (!win)
4385 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
4386 return 0;
4388 if (win == WND_OTHER_PROCESS || win == WND_DESKTOP)
4390 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
4391 return 0;
4394 switch (type)
4396 case ICON_BIG:
4397 ret = win->hIcon;
4398 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON );
4399 break;
4401 case ICON_SMALL:
4402 case ICON_SMALL2:
4403 ret = win->hIconSmall ? win->hIconSmall : win->hIconSmall2;
4404 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICONSM );
4405 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON );
4406 break;
4408 default:
4409 SetLastError( ERROR_INVALID_PARAMETER );
4410 WIN_ReleasePtr( win );
4411 return 0;
4414 if (!ret) ret = LoadIconW( 0, (const WCHAR *)IDI_APPLICATION );
4416 WIN_ReleasePtr( win );
4417 return CopyIcon( ret );