kernel32: Update version to Win 10.
[wine.git] / dlls / user32 / win.c
blob680defc20719677dd48ffaf1bef5d8d1917a2f92
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>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winver.h"
30 #include "wine/server.h"
31 #include "wine/asm.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "controls.h"
35 #include "winerror.h"
36 #include "wine/gdi_driver.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(win);
41 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
42 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
44 static DWORD process_layout = ~0u;
46 static struct list window_surfaces = LIST_INIT( window_surfaces );
48 static CRITICAL_SECTION surfaces_section;
49 static CRITICAL_SECTION_DEBUG critsect_debug =
51 0, 0, &surfaces_section,
52 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
53 0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
55 static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };
57 /**********************************************************************/
59 /* helper for Get/SetWindowLong */
60 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
62 if (size == sizeof(WORD))
64 WORD ret;
65 memcpy( &ret, ptr, sizeof(ret) );
66 return ret;
68 else if (size == sizeof(DWORD))
70 DWORD ret;
71 memcpy( &ret, ptr, sizeof(ret) );
72 return ret;
74 else
76 LONG_PTR ret;
77 memcpy( &ret, ptr, sizeof(ret) );
78 return ret;
82 /* helper for Get/SetWindowLong */
83 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
85 if (size == sizeof(WORD))
87 WORD newval = val;
88 memcpy( ptr, &newval, sizeof(newval) );
90 else if (size == sizeof(DWORD))
92 DWORD newval = val;
93 memcpy( ptr, &newval, sizeof(newval) );
95 else
97 memcpy( ptr, &val, sizeof(val) );
102 static void *user_handles[NB_USER_HANDLES];
104 /***********************************************************************
105 * alloc_user_handle
107 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
109 HANDLE handle = 0;
111 SERVER_START_REQ( alloc_user_handle )
113 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
115 SERVER_END_REQ;
117 if (handle)
119 UINT index = USER_HANDLE_TO_INDEX( handle );
121 assert( index < NB_USER_HANDLES );
122 ptr->handle = handle;
123 ptr->type = type;
124 InterlockedExchangePointer( &user_handles[index], ptr );
126 return handle;
130 /***********************************************************************
131 * get_user_handle_ptr
133 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
135 struct user_object *ptr;
136 WORD index = USER_HANDLE_TO_INDEX( handle );
138 if (index >= NB_USER_HANDLES) return NULL;
140 USER_Lock();
141 if ((ptr = user_handles[index]))
143 if (ptr->type == type &&
144 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
145 !HIWORD(handle) || HIWORD(handle) == 0xffff))
146 return ptr;
147 ptr = NULL;
149 else ptr = OBJ_OTHER_PROCESS;
150 USER_Unlock();
151 return ptr;
155 /***********************************************************************
156 * release_user_handle_ptr
158 void release_user_handle_ptr( void *ptr )
160 assert( ptr && ptr != OBJ_OTHER_PROCESS );
161 USER_Unlock();
165 /***********************************************************************
166 * free_user_handle
168 void *free_user_handle( HANDLE handle, enum user_obj_type type )
170 struct user_object *ptr;
171 WORD index = USER_HANDLE_TO_INDEX( handle );
173 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
175 SERVER_START_REQ( free_user_handle )
177 req->handle = wine_server_user_handle( handle );
178 if (wine_server_call( req )) ptr = NULL;
179 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
181 SERVER_END_REQ;
182 USER_Unlock();
184 return ptr;
188 /***********************************************************************
189 * create_window_handle
191 * Create a window handle with the server.
193 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
194 HINSTANCE instance, BOOL unicode )
196 WORD index;
197 WND *win;
198 HWND handle = 0, full_parent = 0, full_owner = 0;
199 struct tagCLASS *class = NULL;
200 int extra_bytes = 0;
201 DPI_AWARENESS awareness = GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() );
202 UINT dpi = 0;
204 SERVER_START_REQ( create_window )
206 req->parent = wine_server_user_handle( parent );
207 req->owner = wine_server_user_handle( owner );
208 req->instance = wine_server_client_ptr( instance );
209 req->dpi = GetDpiForSystem();
210 req->awareness = awareness;
211 if (!(req->atom = get_int_atom_value( name )) && name)
212 wine_server_add_data( req, name, lstrlenW(name)*sizeof(WCHAR) );
213 if (!wine_server_call_err( req ))
215 handle = wine_server_ptr_handle( reply->handle );
216 full_parent = wine_server_ptr_handle( reply->parent );
217 full_owner = wine_server_ptr_handle( reply->owner );
218 extra_bytes = reply->extra;
219 dpi = reply->dpi;
220 awareness = reply->awareness;
221 class = wine_server_get_ptr( reply->class_ptr );
224 SERVER_END_REQ;
226 if (!handle)
228 WARN( "error %d creating window\n", GetLastError() );
229 return NULL;
232 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
233 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
235 SERVER_START_REQ( destroy_window )
237 req->handle = wine_server_user_handle( handle );
238 wine_server_call( req );
240 SERVER_END_REQ;
241 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
242 return NULL;
245 if (!parent) /* if parent is 0 we don't have a desktop window yet */
247 struct user_thread_info *thread_info = get_user_thread_info();
249 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
251 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
252 else assert( full_parent == thread_info->top_window );
253 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
254 ERR( "failed to create desktop window\n" );
256 else /* HWND_MESSAGE parent */
258 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
262 USER_Lock();
264 index = USER_HANDLE_TO_INDEX(handle);
265 assert( index < NB_USER_HANDLES );
266 win->obj.handle = handle;
267 win->obj.type = USER_WINDOW;
268 win->parent = full_parent;
269 win->owner = full_owner;
270 win->class = class;
271 win->winproc = get_class_winproc( class );
272 win->cbWndExtra = extra_bytes;
273 win->dpi = dpi;
274 win->dpi_awareness = awareness;
275 InterlockedExchangePointer( &user_handles[index], win );
276 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
277 return win;
281 /***********************************************************************
282 * free_window_handle
284 * Free a window handle.
286 static void free_window_handle( HWND hwnd )
288 struct user_object *ptr;
289 WORD index = USER_HANDLE_TO_INDEX(hwnd);
291 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
293 SERVER_START_REQ( destroy_window )
295 req->handle = wine_server_user_handle( hwnd );
296 wine_server_call( req );
297 InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
299 SERVER_END_REQ;
300 USER_Unlock();
301 HeapFree( GetProcessHeap(), 0, ptr );
306 /*******************************************************************
307 * list_window_children
309 * Build an array of the children of a given window. The array must be
310 * freed with HeapFree. Returns NULL when no windows are found.
312 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
314 HWND *list;
315 int i, size = 128;
316 ATOM atom = get_int_atom_value( class );
318 /* empty class is not the same as NULL class */
319 if (!atom && class && !class[0]) return NULL;
321 for (;;)
323 int count = 0;
325 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
327 SERVER_START_REQ( get_window_children )
329 req->desktop = wine_server_obj_handle( desktop );
330 req->parent = wine_server_user_handle( hwnd );
331 req->tid = tid;
332 req->atom = atom;
333 if (!atom && class) wine_server_add_data( req, class, lstrlenW(class)*sizeof(WCHAR) );
334 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
335 if (!wine_server_call( req )) count = reply->count;
337 SERVER_END_REQ;
338 if (count && count < size)
340 /* start from the end since HWND is potentially larger than user_handle_t */
341 for (i = count - 1; i >= 0; i--)
342 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
343 list[count] = 0;
344 return list;
346 HeapFree( GetProcessHeap(), 0, list );
347 if (!count) break;
348 size = count + 1; /* restart with a large enough buffer */
350 return NULL;
354 /*******************************************************************
355 * list_window_parents
357 * Build an array of all parents of a given window, starting with
358 * the immediate parent. The array must be freed with HeapFree.
360 static HWND *list_window_parents( HWND hwnd )
362 WND *win;
363 HWND current, *list;
364 int i, pos = 0, size = 16, count;
366 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
368 current = hwnd;
369 for (;;)
371 if (!(win = WIN_GetPtr( current ))) goto empty;
372 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
373 if (win == WND_DESKTOP)
375 if (!pos) goto empty;
376 list[pos] = 0;
377 return list;
379 list[pos] = current = win->parent;
380 WIN_ReleasePtr( win );
381 if (!current) return list;
382 if (++pos == size - 1)
384 /* need to grow the list */
385 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
386 if (!new_list) goto empty;
387 list = new_list;
388 size += 16;
392 /* at least one parent belongs to another process, have to query the server */
394 for (;;)
396 count = 0;
397 SERVER_START_REQ( get_window_parents )
399 req->handle = wine_server_user_handle( hwnd );
400 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
401 if (!wine_server_call( req )) count = reply->count;
403 SERVER_END_REQ;
404 if (!count) goto empty;
405 if (size > count)
407 /* start from the end since HWND is potentially larger than user_handle_t */
408 for (i = count - 1; i >= 0; i--)
409 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
410 list[count] = 0;
411 return list;
413 HeapFree( GetProcessHeap(), 0, list );
414 size = count + 1;
415 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
418 empty:
419 HeapFree( GetProcessHeap(), 0, list );
420 return NULL;
424 /*******************************************************************
425 * send_parent_notify
427 static void send_parent_notify( HWND hwnd, UINT msg )
429 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
430 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
432 HWND parent = GetParent(hwnd);
433 if (parent && parent != GetDesktopWindow())
434 SendMessageW( parent, WM_PARENTNOTIFY,
435 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
440 /*******************************************************************
441 * update_window_state
443 * Trigger an update of the window's driver state and surface.
445 void update_window_state( HWND hwnd )
447 DPI_AWARENESS_CONTEXT context;
448 RECT window_rect, client_rect, valid_rects[2];
450 if (!WIN_IsCurrentThread( hwnd ))
452 PostMessageW( hwnd, WM_WINE_UPDATEWINDOWSTATE, 0, 0 );
453 return;
456 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
457 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
458 valid_rects[0] = valid_rects[1] = client_rect;
459 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
460 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW,
461 &window_rect, &client_rect, valid_rects );
462 SetThreadDpiAwarenessContext( context );
466 /*******************************************************************
467 * get_server_window_text
469 * Retrieve the window text from the server.
471 static data_size_t get_server_window_text( HWND hwnd, WCHAR *text, data_size_t count )
473 data_size_t len = 0, needed = 0;
475 SERVER_START_REQ( get_window_text )
477 req->handle = wine_server_user_handle( hwnd );
478 if (count) wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
479 if (!wine_server_call_err( req ))
481 needed = reply->length;
482 len = wine_server_reply_size(reply);
485 SERVER_END_REQ;
486 if (text) text[len / sizeof(WCHAR)] = 0;
487 return needed;
491 /*******************************************************************
492 * get_hwnd_message_parent
494 * Return the parent for HWND_MESSAGE windows.
496 HWND get_hwnd_message_parent(void)
498 struct user_thread_info *thread_info = get_user_thread_info();
500 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
501 return thread_info->msg_window;
505 /*******************************************************************
506 * is_desktop_window
508 * Check if window is the desktop or the HWND_MESSAGE top parent.
510 BOOL is_desktop_window( HWND hwnd )
512 struct user_thread_info *thread_info = get_user_thread_info();
514 if (!hwnd) return FALSE;
515 if (hwnd == thread_info->top_window) return TRUE;
516 if (hwnd == thread_info->msg_window) return TRUE;
518 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
520 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
521 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
523 return FALSE;
527 /*******************************************************************
528 * Dummy window surface for windows that shouldn't get painted.
531 static void CDECL dummy_surface_lock( struct window_surface *window_surface )
533 /* nothing to do */
536 static void CDECL dummy_surface_unlock( struct window_surface *window_surface )
538 /* nothing to do */
541 static void *CDECL dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
543 static DWORD dummy_data;
545 info->bmiHeader.biSize = sizeof( info->bmiHeader );
546 info->bmiHeader.biWidth = dummy_surface.rect.right;
547 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
548 info->bmiHeader.biPlanes = 1;
549 info->bmiHeader.biBitCount = 32;
550 info->bmiHeader.biCompression = BI_RGB;
551 info->bmiHeader.biSizeImage = 0;
552 info->bmiHeader.biXPelsPerMeter = 0;
553 info->bmiHeader.biYPelsPerMeter = 0;
554 info->bmiHeader.biClrUsed = 0;
555 info->bmiHeader.biClrImportant = 0;
556 return &dummy_data;
559 static RECT *CDECL dummy_surface_get_bounds( struct window_surface *window_surface )
561 static RECT dummy_bounds;
562 return &dummy_bounds;
565 static void CDECL dummy_surface_set_region( struct window_surface *window_surface, HRGN region )
567 /* nothing to do */
570 static void CDECL dummy_surface_flush( struct window_surface *window_surface )
572 /* nothing to do */
575 static void CDECL dummy_surface_destroy( struct window_surface *window_surface )
577 /* nothing to do */
580 static const struct window_surface_funcs dummy_surface_funcs =
582 dummy_surface_lock,
583 dummy_surface_unlock,
584 dummy_surface_get_bitmap_info,
585 dummy_surface_get_bounds,
586 dummy_surface_set_region,
587 dummy_surface_flush,
588 dummy_surface_destroy
591 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
594 /*******************************************************************
595 * register_window_surface
597 * Register a window surface in the global list, possibly replacing another one.
599 void register_window_surface( struct window_surface *old, struct window_surface *new )
601 if (old == new) return;
602 EnterCriticalSection( &surfaces_section );
603 if (old && old != &dummy_surface) list_remove( &old->entry );
604 if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
605 LeaveCriticalSection( &surfaces_section );
609 /*******************************************************************
610 * flush_window_surfaces
612 * Flush pending output from all window surfaces.
614 void flush_window_surfaces( BOOL idle )
616 static DWORD last_idle;
617 DWORD now;
618 struct window_surface *surface;
620 EnterCriticalSection( &surfaces_section );
621 now = GetTickCount();
622 if (idle) last_idle = now;
623 /* if not idle, we only flush if there's evidence that the app never goes idle */
624 else if ((int)(now - last_idle) < 50) goto done;
626 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
627 surface->funcs->flush( surface );
628 done:
629 LeaveCriticalSection( &surfaces_section );
633 /***********************************************************************
634 * WIN_GetPtr
636 * Return a pointer to the WND structure if local to the process,
637 * or WND_OTHER_PROCESS if handle may be valid in other process.
638 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
640 WND *WIN_GetPtr( HWND hwnd )
642 WND *ptr;
644 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
646 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
648 return ptr;
652 /***********************************************************************
653 * WIN_IsCurrentProcess
655 * Check whether a given window belongs to the current process (and return the full handle).
657 HWND WIN_IsCurrentProcess( HWND hwnd )
659 WND *ptr;
660 HWND ret;
662 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
663 ret = ptr->obj.handle;
664 WIN_ReleasePtr( ptr );
665 return ret;
669 /***********************************************************************
670 * WIN_IsCurrentThread
672 * Check whether a given window belongs to the current thread (and return the full handle).
674 HWND WIN_IsCurrentThread( HWND hwnd )
676 WND *ptr;
677 HWND ret = 0;
679 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
680 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
681 WIN_ReleasePtr( ptr );
682 return ret;
686 /***********************************************************************
687 * win_set_flags
689 * Set the flags of a window and return the previous value.
691 UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask )
693 UINT ret;
694 WND *ptr = WIN_GetPtr( hwnd );
696 if (!ptr || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
697 ret = ptr->flags;
698 ptr->flags = (ret & ~clear_mask) | set_mask;
699 WIN_ReleasePtr( ptr );
700 return ret;
704 /***********************************************************************
705 * WIN_GetFullHandle
707 * Convert a possibly truncated window handle to a full 32-bit handle.
709 HWND WIN_GetFullHandle( HWND hwnd )
711 WND *ptr;
713 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
714 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
715 /* do sign extension for -2 and -3 */
716 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
718 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
720 if (ptr == WND_DESKTOP)
722 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
723 else return get_hwnd_message_parent();
726 if (ptr != WND_OTHER_PROCESS)
728 hwnd = ptr->obj.handle;
729 WIN_ReleasePtr( ptr );
731 else /* may belong to another process */
733 SERVER_START_REQ( get_window_info )
735 req->handle = wine_server_user_handle( hwnd );
736 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
738 SERVER_END_REQ;
740 return hwnd;
744 /***********************************************************************
745 * WIN_SetOwner
747 * Change the owner of a window.
749 static HWND WIN_SetOwner( HWND hwnd, HWND owner )
751 WND *win = WIN_GetPtr( hwnd );
752 HWND ret = 0;
754 if (!win || win == WND_DESKTOP) return 0;
755 if (win == WND_OTHER_PROCESS)
757 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
758 return 0;
760 SERVER_START_REQ( set_window_owner )
762 req->handle = wine_server_user_handle( hwnd );
763 req->owner = wine_server_user_handle( owner );
764 if (!wine_server_call( req ))
766 win->owner = wine_server_ptr_handle( reply->full_owner );
767 ret = wine_server_ptr_handle( reply->prev_owner );
770 SERVER_END_REQ;
771 WIN_ReleasePtr( win );
772 return ret;
776 /***********************************************************************
777 * WIN_SetStyle
779 * Change the style of a window.
781 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
783 BOOL ok, made_visible = FALSE;
784 STYLESTRUCT style;
785 WND *win = WIN_GetPtr( hwnd );
787 if (!win || win == WND_DESKTOP) return 0;
788 if (win == WND_OTHER_PROCESS)
790 if (IsWindow(hwnd))
791 return SendMessageW(hwnd, WM_WINE_SETSTYLE, set_bits, clear_bits);
792 return 0;
794 style.styleOld = win->dwStyle;
795 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
796 if (style.styleNew == style.styleOld)
798 WIN_ReleasePtr( win );
799 return style.styleNew;
801 SERVER_START_REQ( set_window_info )
803 req->handle = wine_server_user_handle( hwnd );
804 req->flags = SET_WIN_STYLE;
805 req->style = style.styleNew;
806 req->extra_offset = -1;
807 if ((ok = !wine_server_call( req )))
809 style.styleOld = reply->old_style;
810 win->dwStyle = style.styleNew;
813 SERVER_END_REQ;
815 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
817 made_visible = (style.styleNew & WS_VISIBLE) != 0;
818 invalidate_dce( win, NULL );
820 WIN_ReleasePtr( win );
822 if (!ok) return 0;
824 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
825 if (made_visible) update_window_state( hwnd );
827 return style.styleOld;
831 /***********************************************************************
832 * WIN_GetRectangles
834 * Get the window and client rectangles.
836 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
838 WND *win = WIN_GetPtr( hwnd );
839 BOOL ret = TRUE;
841 if (!win)
843 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
844 return FALSE;
846 if (win == WND_DESKTOP)
848 RECT rect;
849 rect.left = rect.top = 0;
850 if (hwnd == get_hwnd_message_parent())
852 rect.right = 100;
853 rect.bottom = 100;
854 rect = rect_win_to_thread_dpi( hwnd, rect );
856 else
858 rect.right = GetSystemMetrics(SM_CXSCREEN);
859 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
861 if (rectWindow) *rectWindow = rect;
862 if (rectClient) *rectClient = rect;
863 return TRUE;
865 if (win != WND_OTHER_PROCESS)
867 RECT window_rect = win->window_rect, client_rect = win->client_rect;
869 switch (relative)
871 case COORDS_CLIENT:
872 OffsetRect( &window_rect, -win->client_rect.left, -win->client_rect.top );
873 OffsetRect( &client_rect, -win->client_rect.left, -win->client_rect.top );
874 if (win->dwExStyle & WS_EX_LAYOUTRTL)
875 mirror_rect( &win->client_rect, &window_rect );
876 break;
877 case COORDS_WINDOW:
878 OffsetRect( &window_rect, -win->window_rect.left, -win->window_rect.top );
879 OffsetRect( &client_rect, -win->window_rect.left, -win->window_rect.top );
880 if (win->dwExStyle & WS_EX_LAYOUTRTL)
881 mirror_rect( &win->window_rect, &client_rect );
882 break;
883 case COORDS_PARENT:
884 if (win->parent)
886 WND *parent = WIN_GetPtr( win->parent );
887 if (parent == WND_DESKTOP) break;
888 if (!parent || parent == WND_OTHER_PROCESS)
890 WIN_ReleasePtr( win );
891 goto other_process;
893 if (parent->flags & WIN_CHILDREN_MOVED)
895 WIN_ReleasePtr( parent );
896 WIN_ReleasePtr( win );
897 goto other_process;
899 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
901 mirror_rect( &parent->client_rect, &window_rect );
902 mirror_rect( &parent->client_rect, &client_rect );
904 WIN_ReleasePtr( parent );
906 break;
907 case COORDS_SCREEN:
908 while (win->parent)
910 WND *parent = WIN_GetPtr( win->parent );
911 if (parent == WND_DESKTOP) break;
912 if (!parent || parent == WND_OTHER_PROCESS)
914 WIN_ReleasePtr( win );
915 goto other_process;
917 WIN_ReleasePtr( win );
918 if (parent->flags & WIN_CHILDREN_MOVED)
920 WIN_ReleasePtr( parent );
921 goto other_process;
923 win = parent;
924 if (win->parent)
926 OffsetRect( &window_rect, win->client_rect.left, win->client_rect.top );
927 OffsetRect( &client_rect, win->client_rect.left, win->client_rect.top );
930 break;
932 if (rectWindow) *rectWindow = rect_win_to_thread_dpi( hwnd, window_rect );
933 if (rectClient) *rectClient = rect_win_to_thread_dpi( hwnd, client_rect );
934 WIN_ReleasePtr( win );
935 return TRUE;
938 other_process:
939 SERVER_START_REQ( get_window_rectangles )
941 req->handle = wine_server_user_handle( hwnd );
942 req->relative = relative;
943 req->dpi = get_thread_dpi();
944 if ((ret = !wine_server_call_err( req )))
946 if (rectWindow)
948 rectWindow->left = reply->window.left;
949 rectWindow->top = reply->window.top;
950 rectWindow->right = reply->window.right;
951 rectWindow->bottom = reply->window.bottom;
953 if (rectClient)
955 rectClient->left = reply->client.left;
956 rectClient->top = reply->client.top;
957 rectClient->right = reply->client.right;
958 rectClient->bottom = reply->client.bottom;
962 SERVER_END_REQ;
963 return ret;
967 /***********************************************************************
968 * WIN_DestroyWindow
970 * Destroy storage associated to a window. "Internals" p.358
972 LRESULT WIN_DestroyWindow( HWND hwnd )
974 WND *wndPtr;
975 HWND *list;
976 HMENU menu = 0, sys_menu;
977 struct window_surface *surface;
979 TRACE("%p\n", hwnd );
981 /* destroy default IME window */
982 if (win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)
984 TRACE("unregister IME window for %p\n", hwnd);
985 imm_unregister_window( hwnd );
988 /* free child windows */
989 if ((list = WIN_ListChildren( hwnd )))
991 int i;
992 for (i = 0; list[i]; i++)
994 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
995 else SendNotifyMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
997 HeapFree( GetProcessHeap(), 0, list );
1000 /* Unlink now so we won't bother with the children later on */
1001 SERVER_START_REQ( set_parent )
1003 req->handle = wine_server_user_handle( hwnd );
1004 req->parent = 0;
1005 wine_server_call( req );
1007 SERVER_END_REQ;
1010 * Send the WM_NCDESTROY to the window being destroyed.
1012 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
1014 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
1016 /* free resources associated with the window */
1018 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1019 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1020 menu = (HMENU)wndPtr->wIDmenu;
1021 sys_menu = wndPtr->hSysMenu;
1022 free_dce( wndPtr->dce, hwnd );
1023 wndPtr->dce = NULL;
1024 HeapFree( GetProcessHeap(), 0, wndPtr->text );
1025 wndPtr->text = NULL;
1026 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
1027 wndPtr->pScroll = NULL;
1028 DestroyIcon( wndPtr->hIconSmall2 );
1029 surface = wndPtr->surface;
1030 wndPtr->surface = NULL;
1031 WIN_ReleasePtr( wndPtr );
1033 if (menu) DestroyMenu( menu );
1034 if (sys_menu) DestroyMenu( sys_menu );
1035 if (surface)
1037 register_window_surface( surface, NULL );
1038 window_surface_release( surface );
1041 USER_Driver->pDestroyWindow( hwnd );
1043 free_window_handle( hwnd );
1044 return 0;
1048 /***********************************************************************
1049 * next_thread_window
1051 static WND *next_thread_window( HWND *hwnd )
1053 struct user_object *ptr;
1054 WND *win;
1055 WORD index = *hwnd ? USER_HANDLE_TO_INDEX( *hwnd ) + 1 : 0;
1057 USER_Lock();
1058 while (index < NB_USER_HANDLES)
1060 if (!(ptr = user_handles[index++])) continue;
1061 if (ptr->type != USER_WINDOW) continue;
1062 win = (WND *)ptr;
1063 if (win->tid != GetCurrentThreadId()) continue;
1064 *hwnd = ptr->handle;
1065 return win;
1067 USER_Unlock();
1068 return NULL;
1072 /***********************************************************************
1073 * destroy_thread_windows
1075 * Destroy all window owned by the current thread.
1077 void destroy_thread_windows(void)
1079 WND *wndPtr;
1080 HWND hwnd = 0, *list;
1081 HMENU menu, sys_menu;
1082 struct window_surface *surface;
1083 int i;
1085 while ((wndPtr = next_thread_window( &hwnd )))
1087 /* destroy the client-side storage */
1089 list = WIN_ListChildren( hwnd );
1090 menu = ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) ? (HMENU)wndPtr->wIDmenu : 0;
1091 sys_menu = wndPtr->hSysMenu;
1092 free_dce( wndPtr->dce, hwnd );
1093 surface = wndPtr->surface;
1094 InterlockedCompareExchangePointer( &user_handles[USER_HANDLE_TO_INDEX(hwnd)], NULL, wndPtr );
1095 WIN_ReleasePtr( wndPtr );
1096 HeapFree( GetProcessHeap(), 0, wndPtr );
1097 if (menu) DestroyMenu( menu );
1098 if (sys_menu) DestroyMenu( sys_menu );
1099 if (surface)
1101 register_window_surface( surface, NULL );
1102 window_surface_release( surface );
1105 /* free child windows */
1107 if (!list) continue;
1108 for (i = 0; list[i]; i++)
1109 if (!WIN_IsCurrentThread( list[i] ))
1110 SendNotifyMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1111 HeapFree( GetProcessHeap(), 0, list );
1116 /***********************************************************************
1117 * WIN_FixCoordinates
1119 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1120 * returns default show mode in sw.
1122 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1124 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1125 POINT pos[2];
1127 if (cs->dwExStyle & WS_EX_MDICHILD)
1129 UINT id = 0;
1131 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1132 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1134 TRACE("MDI child id %04x\n", id);
1137 if (cs->style & (WS_CHILD | WS_POPUP))
1139 if (cs->dwExStyle & WS_EX_MDICHILD)
1141 if (IS_DEFAULT(cs->x))
1143 cs->x = pos[0].x;
1144 cs->y = pos[0].y;
1146 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1147 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1149 else
1151 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1152 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1155 else /* overlapped window */
1157 HMONITOR monitor;
1158 MONITORINFO mon_info;
1159 STARTUPINFOW info;
1161 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1163 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1164 mon_info.cbSize = sizeof(mon_info);
1165 GetMonitorInfoW( monitor, &mon_info );
1166 GetStartupInfoW( &info );
1168 if (IS_DEFAULT(cs->x))
1170 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1171 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1172 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1175 if (IS_DEFAULT(cs->cx))
1177 if (info.dwFlags & STARTF_USESIZE)
1179 cs->cx = info.dwXSize;
1180 cs->cy = info.dwYSize;
1182 else
1184 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1185 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1188 /* neither x nor cx are default. Check the y values .
1189 * In the trace we see Outlook and Outlook Express using
1190 * cy set to CW_USEDEFAULT when opening the address book.
1192 else if (IS_DEFAULT(cs->cy))
1194 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1195 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1198 #undef IS_DEFAULT
1201 /***********************************************************************
1202 * dump_window_styles
1204 static void dump_window_styles( DWORD style, DWORD exstyle )
1206 TRACE( "style:" );
1207 if(style & WS_POPUP) TRACE(" WS_POPUP");
1208 if(style & WS_CHILD) TRACE(" WS_CHILD");
1209 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1210 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1211 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1212 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1213 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1214 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1215 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1216 else
1218 if(style & WS_BORDER) TRACE(" WS_BORDER");
1219 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1221 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1222 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1223 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1224 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1225 if (style & WS_CHILD)
1227 if(style & WS_GROUP) TRACE(" WS_GROUP");
1228 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1230 else
1232 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1233 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1236 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1237 #define DUMPED_STYLES \
1238 ((DWORD)(WS_POPUP | \
1239 WS_CHILD | \
1240 WS_MINIMIZE | \
1241 WS_VISIBLE | \
1242 WS_DISABLED | \
1243 WS_CLIPSIBLINGS | \
1244 WS_CLIPCHILDREN | \
1245 WS_MAXIMIZE | \
1246 WS_BORDER | \
1247 WS_DLGFRAME | \
1248 WS_VSCROLL | \
1249 WS_HSCROLL | \
1250 WS_SYSMENU | \
1251 WS_THICKFRAME | \
1252 WS_GROUP | \
1253 WS_TABSTOP | \
1254 WS_MINIMIZEBOX | \
1255 WS_MAXIMIZEBOX))
1257 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1258 TRACE("\n");
1259 #undef DUMPED_STYLES
1261 TRACE( "exstyle:" );
1262 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1263 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1264 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1265 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1266 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1267 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1268 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1269 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1270 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1271 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1272 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1273 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1274 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1275 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1276 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1277 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1278 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1279 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1280 if(exstyle & WS_EX_NOINHERITLAYOUT) TRACE(" WS_EX_NOINHERITLAYOUT");
1281 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1282 if(exstyle & WS_EX_COMPOSITED) TRACE(" WS_EX_COMPOSITED");
1283 if(exstyle & WS_EX_NOACTIVATE) TRACE(" WS_EX_NOACTIVATE");
1285 #define DUMPED_EX_STYLES \
1286 ((DWORD)(WS_EX_DLGMODALFRAME | \
1287 WS_EX_DRAGDETECT | \
1288 WS_EX_NOPARENTNOTIFY | \
1289 WS_EX_TOPMOST | \
1290 WS_EX_ACCEPTFILES | \
1291 WS_EX_TRANSPARENT | \
1292 WS_EX_MDICHILD | \
1293 WS_EX_TOOLWINDOW | \
1294 WS_EX_WINDOWEDGE | \
1295 WS_EX_CLIENTEDGE | \
1296 WS_EX_CONTEXTHELP | \
1297 WS_EX_RIGHT | \
1298 WS_EX_RTLREADING | \
1299 WS_EX_LEFTSCROLLBAR | \
1300 WS_EX_CONTROLPARENT | \
1301 WS_EX_STATICEDGE | \
1302 WS_EX_APPWINDOW | \
1303 WS_EX_LAYERED | \
1304 WS_EX_NOINHERITLAYOUT | \
1305 WS_EX_LAYOUTRTL | \
1306 WS_EX_COMPOSITED |\
1307 WS_EX_NOACTIVATE))
1309 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1310 TRACE("\n");
1311 #undef DUMPED_EX_STYLES
1314 /***********************************************************************
1315 * map_dpi_create_struct
1317 static void map_dpi_create_struct( CREATESTRUCTW *cs, UINT dpi_from, UINT dpi_to )
1319 if (!dpi_from && !dpi_to) return;
1320 if (!dpi_from || !dpi_to)
1322 POINT pt = { cs->x, cs->y };
1323 UINT mon_dpi = get_monitor_dpi( MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ));
1324 if (!dpi_from) dpi_from = mon_dpi;
1325 else dpi_to = mon_dpi;
1327 if (dpi_from == dpi_to) return;
1328 cs->x = MulDiv( cs->x, dpi_to, dpi_from );
1329 cs->y = MulDiv( cs->y, dpi_to, dpi_from );
1330 cs->cx = MulDiv( cs->cx, dpi_to, dpi_from );
1331 cs->cy = MulDiv( cs->cy, dpi_to, dpi_from );
1334 /***********************************************************************
1335 * WIN_CreateWindowEx
1337 * Implementation of CreateWindowEx().
1339 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1341 INT cx, cy, style, sw = SW_SHOW;
1342 LRESULT result;
1343 RECT rect;
1344 WND *wndPtr;
1345 HWND hwnd, parent, owner, top_child = 0;
1346 const WCHAR *p = className;
1347 UINT win_dpi, thread_dpi = get_thread_dpi();
1348 DPI_AWARENESS_CONTEXT context;
1349 MDICREATESTRUCTW mdi_cs;
1350 CBT_CREATEWNDW cbtc;
1351 CREATESTRUCTW cbcs;
1353 className = CLASS_GetVersionedName(className, NULL, NULL, TRUE);
1355 TRACE("%s %s%s%s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1356 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1357 debugstr_w(p), p != className ? "->" : "", p != className ? debugstr_w(className) : "",
1358 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1359 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1360 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1362 /* Fix the styles for MDI children */
1363 if (cs->dwExStyle & WS_EX_MDICHILD)
1365 if (!(win_get_flags( cs->hwndParent ) & WIN_ISMDICLIENT))
1367 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1368 return 0;
1371 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1372 * MDICREATESTRUCT members have the originally passed values.
1374 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1375 * have the same layout.
1377 mdi_cs.szClass = cs->lpszClass;
1378 mdi_cs.szTitle = cs->lpszName;
1379 mdi_cs.hOwner = cs->hInstance;
1380 mdi_cs.x = cs->x;
1381 mdi_cs.y = cs->y;
1382 mdi_cs.cx = cs->cx;
1383 mdi_cs.cy = cs->cy;
1384 mdi_cs.style = cs->style;
1385 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1387 cs->lpCreateParams = &mdi_cs;
1389 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1391 if (cs->style & WS_POPUP)
1393 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1394 return 0;
1396 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1398 else
1400 cs->style &= ~WS_POPUP;
1401 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1402 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1405 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1407 if (top_child)
1409 /* Restore current maximized child */
1410 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1412 TRACE("Restoring current maximized child %p\n", top_child);
1413 if (cs->style & WS_MAXIMIZE)
1415 /* if the new window is maximized don't bother repainting */
1416 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1417 ShowWindow( top_child, SW_SHOWNORMAL );
1418 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1420 else ShowWindow( top_child, SW_SHOWNORMAL );
1425 /* Find the parent window */
1427 parent = cs->hwndParent;
1428 owner = 0;
1430 if (cs->hwndParent == HWND_MESSAGE)
1432 cs->hwndParent = parent = get_hwnd_message_parent();
1434 else if (cs->hwndParent)
1436 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1438 parent = GetDesktopWindow();
1439 owner = cs->hwndParent;
1441 else
1443 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1444 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1445 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1448 else
1450 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1452 WARN("No parent for child window\n" );
1453 SetLastError(ERROR_TLW_WITH_WSCHILD);
1454 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1457 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1458 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1459 (IS_INTRESOURCE(className) || wcsicmp( className, L"Message" )))
1461 DWORD layout;
1462 GetProcessDefaultLayout( &layout );
1463 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1464 parent = GetDesktopWindow();
1468 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1470 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1471 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1472 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1473 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1474 else
1475 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1477 /* Create the window structure */
1479 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1481 WNDCLASSW wc;
1482 /* if it's a comctl32 class, GetClassInfo will load it, then we can retry */
1483 if (GetLastError() != ERROR_INVALID_HANDLE ||
1484 !GetClassInfoW( 0, className, &wc ) ||
1485 !(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1486 return 0;
1488 hwnd = wndPtr->obj.handle;
1490 /* Fill the window structure */
1492 wndPtr->tid = GetCurrentThreadId();
1493 wndPtr->hInstance = cs->hInstance;
1494 wndPtr->text = NULL;
1495 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1496 wndPtr->dwExStyle = cs->dwExStyle;
1497 wndPtr->wIDmenu = 0;
1498 wndPtr->helpContext = 0;
1499 wndPtr->pScroll = NULL;
1500 wndPtr->userdata = 0;
1501 wndPtr->hIcon = 0;
1502 wndPtr->hIconSmall = 0;
1503 wndPtr->hIconSmall2 = 0;
1504 wndPtr->hSysMenu = 0;
1506 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1507 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1508 SetRect( &wndPtr->normal_rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1510 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1513 * Correct the window styles.
1515 * It affects only the style loaded into the WIN structure.
1518 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1520 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1521 if (!(wndPtr->dwStyle & WS_POPUP))
1522 wndPtr->dwStyle |= WS_CAPTION;
1525 /* WS_EX_WINDOWEDGE depends on some other styles */
1526 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1527 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1528 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1530 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1531 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1532 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1534 else
1535 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1537 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1538 wndPtr->flags |= WIN_NEED_SIZE;
1540 SERVER_START_REQ( set_window_info )
1542 req->handle = wine_server_user_handle( hwnd );
1543 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1544 req->style = wndPtr->dwStyle;
1545 req->ex_style = wndPtr->dwExStyle;
1546 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1547 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1548 req->extra_offset = -1;
1549 wine_server_call( req );
1551 SERVER_END_REQ;
1553 /* Set the window menu */
1555 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1557 if (cs->hMenu)
1559 if (!MENU_SetMenu(hwnd, cs->hMenu))
1561 WIN_ReleasePtr( wndPtr );
1562 free_window_handle( hwnd );
1563 return 0;
1566 else
1568 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1569 if (menuName)
1571 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1572 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1576 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1578 style = wndPtr->dwStyle;
1579 win_dpi = wndPtr->dpi;
1580 WIN_ReleasePtr( wndPtr );
1582 if (parent) map_dpi_create_struct( cs, thread_dpi, win_dpi );
1584 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1586 /* call the WH_CBT hook */
1588 /* the window style passed to the hook must be the real window style,
1589 * rather than just the window style that the caller to CreateWindowEx
1590 * passed in, so we have to copy the original CREATESTRUCT and get the
1591 * the real style. */
1592 cbcs = *cs;
1593 cbcs.style = style;
1594 cbtc.lpcs = &cbcs;
1595 cbtc.hwndInsertAfter = HWND_TOP;
1596 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1598 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1600 cx = cs->cx;
1601 cy = cs->cy;
1602 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1604 MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd );
1605 cx = max( min( cx, info.ptMaxTrackSize.x ), info.ptMinTrackSize.x );
1606 cy = max( min( cy, info.ptMaxTrackSize.y ), info.ptMinTrackSize.y );
1609 if (cx < 0) cx = 0;
1610 if (cy < 0) cy = 0;
1611 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1612 /* check for wraparound */
1613 if (cs->x > 0x7fffffff - cx) rect.right = 0x7fffffff;
1614 if (cs->y > 0x7fffffff - cy) rect.bottom = 0x7fffffff;
1615 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1617 /* send WM_NCCREATE */
1619 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd, cs->x, cs->y, cs->cx, cs->cy, wine_dbgstr_rect(&rect) );
1620 if (unicode)
1621 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1622 else
1623 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1624 if (!result)
1626 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1627 goto failed;
1630 /* create default IME window */
1632 if (imm_register_window && !is_desktop_window( hwnd ) &&
1633 parent != get_hwnd_message_parent() && imm_register_window( hwnd ))
1635 TRACE("register IME window for %p\n", hwnd);
1636 win_set_flags( hwnd, WIN_HAS_IME_WIN, 0 );
1639 /* send WM_NCCALCSIZE */
1641 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1643 /* yes, even if the CBT hook was called with HWND_TOP */
1644 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1645 RECT client_rect = rect;
1647 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1648 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1649 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1650 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1651 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1653 else goto failed;
1655 /* send WM_CREATE */
1657 if (unicode)
1658 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1659 else
1660 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1661 if (result == -1) goto failed;
1663 /* call the driver */
1665 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1667 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1669 /* send the size messages */
1671 if (!(win_get_flags( hwnd ) & WIN_NEED_SIZE))
1673 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1674 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1675 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1676 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1679 /* Show the window, maximizing or minimizing if needed */
1681 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1682 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1684 RECT newPos;
1685 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1687 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1688 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1689 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1690 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1691 newPos.bottom - newPos.top, swFlag );
1694 /* Notify the parent window only */
1696 send_parent_notify( hwnd, WM_CREATE );
1697 if (!IsWindow( hwnd ))
1699 SetThreadDpiAwarenessContext( context );
1700 return 0;
1703 if (parent == GetDesktopWindow())
1704 PostMessageW( parent, WM_PARENTNOTIFY, WM_CREATE, (LPARAM)hwnd );
1706 if (cs->style & WS_VISIBLE)
1708 if (cs->style & WS_MAXIMIZE)
1709 sw = SW_SHOW;
1710 else if (cs->style & WS_MINIMIZE)
1711 sw = SW_SHOWMINIMIZED;
1713 ShowWindow( hwnd, sw );
1714 if (cs->dwExStyle & WS_EX_MDICHILD)
1716 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1717 /* ShowWindow won't activate child windows */
1718 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1722 /* Call WH_SHELL hook */
1724 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1725 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1727 TRACE("created window %p\n", hwnd);
1728 SetThreadDpiAwarenessContext( context );
1729 return hwnd;
1731 failed:
1732 WIN_DestroyWindow( hwnd );
1733 SetThreadDpiAwarenessContext( context );
1734 return 0;
1738 /***********************************************************************
1739 * CreateWindowExA (USER32.@)
1741 HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExA( DWORD exStyle, LPCSTR className,
1742 LPCSTR windowName, DWORD style, INT x,
1743 INT y, INT width, INT height,
1744 HWND parent, HMENU menu,
1745 HINSTANCE instance, LPVOID data )
1747 CREATESTRUCTA cs;
1749 cs.lpCreateParams = data;
1750 cs.hInstance = instance;
1751 cs.hMenu = menu;
1752 cs.hwndParent = parent;
1753 cs.x = x;
1754 cs.y = y;
1755 cs.cx = width;
1756 cs.cy = height;
1757 cs.style = style;
1758 cs.lpszName = windowName;
1759 cs.lpszClass = className;
1760 cs.dwExStyle = exStyle;
1762 if (!IS_INTRESOURCE(className))
1764 WCHAR bufferW[256];
1765 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, ARRAY_SIZE( bufferW )))
1766 return 0;
1767 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1769 /* Note: we rely on the fact that CREATESTRUCTA and */
1770 /* CREATESTRUCTW have the same layout. */
1771 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1775 /***********************************************************************
1776 * CreateWindowExW (USER32.@)
1778 HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
1779 LPCWSTR windowName, DWORD style, INT x,
1780 INT y, INT width, INT height,
1781 HWND parent, HMENU menu,
1782 HINSTANCE instance, LPVOID data )
1784 CREATESTRUCTW cs;
1786 cs.lpCreateParams = data;
1787 cs.hInstance = instance;
1788 cs.hMenu = menu;
1789 cs.hwndParent = parent;
1790 cs.x = x;
1791 cs.y = y;
1792 cs.cx = width;
1793 cs.cy = height;
1794 cs.style = style;
1795 cs.lpszName = windowName;
1796 cs.lpszClass = className;
1797 cs.dwExStyle = exStyle;
1799 return wow_handlers.create_window( &cs, className, instance, TRUE );
1803 /***********************************************************************
1804 * WIN_SendDestroyMsg
1806 static void WIN_SendDestroyMsg( HWND hwnd )
1808 GUITHREADINFO info;
1810 info.cbSize = sizeof(info);
1811 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1813 if (hwnd == info.hwndCaret) DestroyCaret();
1814 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1817 if (hwnd == GetClipboardOwner()) CLIPBOARD_ReleaseOwner( hwnd );
1820 * Send the WM_DESTROY to the window.
1822 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1825 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1826 * make sure that the window still exists when we come back.
1828 if (IsWindow(hwnd))
1830 HWND* pWndArray;
1831 int i;
1833 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1835 for (i = 0; pWndArray[i]; i++)
1837 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1839 HeapFree( GetProcessHeap(), 0, pWndArray );
1841 else
1842 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1846 /***********************************************************************
1847 * DestroyWindow (USER32.@)
1849 BOOL WINAPI DestroyWindow( HWND hwnd )
1851 BOOL is_child;
1853 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1855 SetLastError( ERROR_ACCESS_DENIED );
1856 return FALSE;
1859 TRACE("(%p)\n", hwnd);
1861 /* Call hooks */
1863 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1865 if (MENU_IsMenuActive() == hwnd)
1866 EndMenu();
1868 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1870 if (is_child)
1872 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1873 send_parent_notify( hwnd, WM_DESTROY );
1875 else if (!GetWindow( hwnd, GW_OWNER ))
1877 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1878 /* FIXME: clean up palette - see "Internals" p.352 */
1881 if (!IsWindow(hwnd)) return TRUE;
1883 /* Hide the window */
1884 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1886 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1887 if (is_child)
1888 ShowWindow( hwnd, SW_HIDE );
1889 else
1890 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1891 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1894 if (!IsWindow(hwnd)) return TRUE;
1896 /* Recursively destroy owned windows */
1898 if (!is_child)
1900 for (;;)
1902 int i;
1903 BOOL got_one = FALSE;
1904 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1905 if (list)
1907 for (i = 0; list[i]; i++)
1909 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1910 if (WIN_IsCurrentThread( list[i] ))
1912 DestroyWindow( list[i] );
1913 got_one = TRUE;
1914 continue;
1916 WIN_SetOwner( list[i], 0 );
1918 HeapFree( GetProcessHeap(), 0, list );
1920 if (!got_one) break;
1924 /* Send destroy messages */
1926 WIN_SendDestroyMsg( hwnd );
1927 if (!IsWindow( hwnd )) return TRUE;
1929 /* Destroy the window storage */
1931 WIN_DestroyWindow( hwnd );
1932 return TRUE;
1936 /***********************************************************************
1937 * CloseWindow (USER32.@)
1939 BOOL WINAPI CloseWindow( HWND hwnd )
1941 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1942 ShowWindow( hwnd, SW_MINIMIZE );
1943 return TRUE;
1947 /***********************************************************************
1948 * OpenIcon (USER32.@)
1950 BOOL WINAPI OpenIcon( HWND hwnd )
1952 if (!IsIconic( hwnd )) return FALSE;
1953 ShowWindow( hwnd, SW_SHOWNORMAL );
1954 return TRUE;
1958 /***********************************************************************
1959 * FindWindowExW (USER32.@)
1961 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1963 HWND *list;
1964 HWND retvalue = 0;
1965 int i = 0, len = 0;
1966 WCHAR *buffer = NULL;
1968 if (!parent && child) parent = GetDesktopWindow();
1969 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1971 if (title)
1973 len = lstrlenW(title) + 1; /* one extra char to check for chars beyond the end */
1974 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1977 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1979 if (child)
1981 child = WIN_GetFullHandle( child );
1982 while (list[i] && list[i] != child) i++;
1983 if (!list[i]) goto done;
1984 i++; /* start from next window */
1987 if (title)
1989 while (list[i])
1991 if (InternalGetWindowText( list[i], buffer, len + 1 ))
1993 if (!wcsicmp( buffer, title )) break;
1995 else
1997 if (!title[0]) break;
1999 i++;
2002 retvalue = list[i];
2004 done:
2005 HeapFree( GetProcessHeap(), 0, list );
2006 HeapFree( GetProcessHeap(), 0, buffer );
2007 return retvalue;
2012 /***********************************************************************
2013 * FindWindowA (USER32.@)
2015 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
2017 HWND ret = FindWindowExA( 0, 0, className, title );
2018 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
2019 return ret;
2023 /***********************************************************************
2024 * FindWindowExA (USER32.@)
2026 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
2028 LPWSTR titleW = NULL;
2029 HWND hwnd = 0;
2031 if (title)
2033 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
2034 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
2035 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
2038 if (!IS_INTRESOURCE(className))
2040 WCHAR classW[256];
2041 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, ARRAY_SIZE( classW )))
2042 hwnd = FindWindowExW( parent, child, classW, titleW );
2044 else
2046 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
2049 HeapFree( GetProcessHeap(), 0, titleW );
2050 return hwnd;
2054 /***********************************************************************
2055 * FindWindowW (USER32.@)
2057 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2059 return FindWindowExW( 0, 0, className, title );
2063 /**********************************************************************
2064 * GetDesktopWindow (USER32.@)
2066 HWND WINAPI GetDesktopWindow(void)
2068 struct user_thread_info *thread_info = get_user_thread_info();
2070 if (thread_info->top_window) return thread_info->top_window;
2072 SERVER_START_REQ( get_desktop_window )
2074 req->force = 0;
2075 if (!wine_server_call( req ))
2077 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2078 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2081 SERVER_END_REQ;
2083 if (!thread_info->top_window)
2085 STARTUPINFOW si;
2086 PROCESS_INFORMATION pi;
2087 WCHAR windir[MAX_PATH];
2088 WCHAR app[MAX_PATH + ARRAY_SIZE( L"\\explorer.exe" )];
2089 WCHAR cmdline[MAX_PATH + ARRAY_SIZE( L"\\explorer.exe /desktop" )];
2090 WCHAR desktop[MAX_PATH];
2091 void *redir;
2093 SERVER_START_REQ( set_user_object_info )
2095 req->handle = wine_server_obj_handle( GetThreadDesktop(GetCurrentThreadId()) );
2096 req->flags = SET_USER_OBJECT_GET_FULL_NAME;
2097 wine_server_set_reply( req, desktop, sizeof(desktop) - sizeof(WCHAR) );
2098 if (!wine_server_call( req ))
2100 size_t size = wine_server_reply_size( reply );
2101 desktop[size / sizeof(WCHAR)] = 0;
2102 TRACE( "starting explorer for desktop %s\n", debugstr_w(desktop) );
2104 else
2105 desktop[0] = 0;
2107 SERVER_END_REQ;
2109 memset( &si, 0, sizeof(si) );
2110 si.cb = sizeof(si);
2111 si.lpDesktop = *desktop ? desktop : NULL;
2112 si.dwFlags = STARTF_USESTDHANDLES;
2113 si.hStdInput = 0;
2114 si.hStdOutput = 0;
2115 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2117 GetSystemDirectoryW( windir, MAX_PATH );
2118 lstrcpyW( app, windir );
2119 lstrcatW( app, L"\\explorer.exe" );
2120 lstrcpyW( cmdline, app );
2121 lstrcatW( cmdline, L" /desktop" );
2123 Wow64DisableWow64FsRedirection( &redir );
2124 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2125 NULL, windir, &si, &pi ))
2127 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2128 WaitForInputIdle( pi.hProcess, 10000 );
2129 CloseHandle( pi.hThread );
2130 CloseHandle( pi.hProcess );
2132 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2133 Wow64RevertWow64FsRedirection( redir );
2135 SERVER_START_REQ( get_desktop_window )
2137 req->force = 1;
2138 if (!wine_server_call( req ))
2140 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2141 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2144 SERVER_END_REQ;
2147 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2148 ERR( "failed to create desktop window\n" );
2150 return thread_info->top_window;
2154 /*******************************************************************
2155 * EnableWindow (USER32.@)
2157 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2159 BOOL retvalue;
2161 if (is_broadcast(hwnd))
2163 SetLastError( ERROR_INVALID_PARAMETER );
2164 return FALSE;
2167 TRACE("( %p, %d )\n", hwnd, enable);
2169 if (enable)
2171 retvalue = (WIN_SetStyle( hwnd, 0, WS_DISABLED ) & WS_DISABLED) != 0;
2172 if (retvalue) SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2174 else
2176 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
2178 retvalue = (WIN_SetStyle( hwnd, WS_DISABLED, 0 ) & WS_DISABLED) != 0;
2179 if (!retvalue)
2181 if (hwnd == GetFocus())
2182 SetFocus( 0 ); /* A disabled window can't have the focus */
2184 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2187 return retvalue;
2191 /***********************************************************************
2192 * IsWindowEnabled (USER32.@)
2194 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2196 LONG ret;
2198 SetLastError(NO_ERROR);
2199 ret = GetWindowLongW( hWnd, GWL_STYLE );
2200 if (!ret && GetLastError() != NO_ERROR) return FALSE;
2201 return !(ret & WS_DISABLED);
2204 /***********************************************************************
2205 * IsWindowUnicode (USER32.@)
2207 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2209 WND * wndPtr;
2210 BOOL retvalue = FALSE;
2212 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2214 if (wndPtr == WND_DESKTOP) return TRUE;
2216 if (wndPtr != WND_OTHER_PROCESS)
2218 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2219 WIN_ReleasePtr( wndPtr );
2221 else
2223 SERVER_START_REQ( get_window_info )
2225 req->handle = wine_server_user_handle( hwnd );
2226 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2228 SERVER_END_REQ;
2230 return retvalue;
2234 /***********************************************************************
2235 * GetWindowDpiAwarenessContext (USER32.@)
2237 DPI_AWARENESS_CONTEXT WINAPI GetWindowDpiAwarenessContext( HWND hwnd )
2239 WND *win;
2240 DPI_AWARENESS_CONTEXT ret = 0;
2242 if (!(win = WIN_GetPtr( hwnd )))
2244 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2245 return 0;
2247 if (win == WND_DESKTOP) return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
2248 if (win != WND_OTHER_PROCESS)
2250 ret = ULongToHandle( win->dpi_awareness | 0x10 );
2251 WIN_ReleasePtr( win );
2253 else
2255 SERVER_START_REQ( get_window_info )
2257 req->handle = wine_server_user_handle( hwnd );
2258 if (!wine_server_call_err( req )) ret = ULongToHandle( reply->awareness | 0x10 );
2260 SERVER_END_REQ;
2262 return ret;
2266 /***********************************************************************
2267 * GetDpiForWindow (USER32.@)
2269 UINT WINAPI GetDpiForWindow( HWND hwnd )
2271 WND *win;
2272 UINT ret = 0;
2274 if (!(win = WIN_GetPtr( hwnd )))
2276 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2277 return 0;
2279 if (win == WND_DESKTOP)
2281 POINT pt = { 0, 0 };
2282 return get_monitor_dpi( MonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY ));
2284 if (win != WND_OTHER_PROCESS)
2286 ret = win->dpi;
2287 if (!ret) ret = get_win_monitor_dpi( hwnd );
2288 WIN_ReleasePtr( win );
2290 else
2292 SERVER_START_REQ( get_window_info )
2294 req->handle = wine_server_user_handle( hwnd );
2295 if (!wine_server_call_err( req )) ret = reply->dpi;
2297 SERVER_END_REQ;
2299 return ret;
2303 /**********************************************************************
2304 * WIN_GetWindowLong
2306 * Helper function for GetWindowLong().
2308 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2310 LONG_PTR retvalue = 0;
2311 WND *wndPtr;
2313 if (offset == GWLP_HWNDPARENT)
2315 HWND parent = GetAncestor( hwnd, GA_PARENT );
2316 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2317 return (ULONG_PTR)parent;
2320 if (!(wndPtr = WIN_GetPtr( hwnd )))
2322 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2323 return 0;
2326 if (wndPtr == WND_DESKTOP)
2328 switch (offset)
2330 case GWL_STYLE:
2331 retvalue = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* message parent is not visible */
2332 if (WIN_GetFullHandle( hwnd ) == GetDesktopWindow())
2333 retvalue |= WS_VISIBLE;
2334 return retvalue;
2335 case GWL_EXSTYLE:
2336 case GWLP_USERDATA:
2337 case GWLP_ID:
2338 case GWLP_HINSTANCE:
2339 return 0;
2340 case GWLP_WNDPROC:
2341 SetLastError( ERROR_ACCESS_DENIED );
2342 return 0;
2344 SetLastError( ERROR_INVALID_INDEX );
2345 return 0;
2348 if (wndPtr == WND_OTHER_PROCESS)
2350 if (offset == GWLP_WNDPROC)
2352 SetLastError( ERROR_ACCESS_DENIED );
2353 return 0;
2355 SERVER_START_REQ( set_window_info )
2357 req->handle = wine_server_user_handle( hwnd );
2358 req->flags = 0; /* don't set anything, just retrieve */
2359 req->extra_offset = (offset >= 0) ? offset : -1;
2360 req->extra_size = (offset >= 0) ? size : 0;
2361 if (!wine_server_call_err( req ))
2363 switch(offset)
2365 case GWL_STYLE: retvalue = reply->old_style; break;
2366 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2367 case GWLP_ID: retvalue = reply->old_id; break;
2368 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2369 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2370 default:
2371 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2372 else SetLastError( ERROR_INVALID_INDEX );
2373 break;
2377 SERVER_END_REQ;
2378 return retvalue;
2381 /* now we have a valid wndPtr */
2383 if (offset >= 0)
2385 if (offset > (int)(wndPtr->cbWndExtra - size))
2387 WARN("Invalid offset %d\n", offset );
2388 WIN_ReleasePtr( wndPtr );
2389 SetLastError( ERROR_INVALID_INDEX );
2390 return 0;
2392 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2394 /* Special case for dialog window procedure */
2395 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2396 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2397 WIN_ReleasePtr( wndPtr );
2398 return retvalue;
2401 switch(offset)
2403 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2404 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2405 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2406 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2407 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2408 case GWLP_WNDPROC:
2409 /* This looks like a hack only for the edit control (see tests). This makes these controls
2410 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2411 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2413 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2414 retvalue = (ULONG_PTR)wndPtr->winproc;
2415 else
2416 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2417 break;
2418 default:
2419 WARN("Unknown offset %d\n", offset );
2420 SetLastError( ERROR_INVALID_INDEX );
2421 break;
2423 WIN_ReleasePtr(wndPtr);
2424 return retvalue;
2428 /**********************************************************************
2429 * WIN_SetWindowLong
2431 * Helper function for SetWindowLong().
2433 * 0 is the failure code. However, in the case of failure SetLastError
2434 * must be set to distinguish between a 0 return value and a failure.
2436 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2438 STYLESTRUCT style;
2439 BOOL ok, made_visible = FALSE;
2440 LONG_PTR retval = 0;
2441 WND *wndPtr;
2443 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2445 if (is_broadcast(hwnd))
2447 SetLastError( ERROR_INVALID_PARAMETER );
2448 return FALSE;
2451 if (!(wndPtr = WIN_GetPtr( hwnd )))
2453 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2454 return 0;
2456 if (wndPtr == WND_DESKTOP)
2458 /* can't change anything on the desktop window */
2459 SetLastError( ERROR_ACCESS_DENIED );
2460 return 0;
2462 if (wndPtr == WND_OTHER_PROCESS)
2464 if (offset == GWLP_WNDPROC)
2466 SetLastError( ERROR_ACCESS_DENIED );
2467 return 0;
2469 if (offset > 32767 || offset < -32767)
2471 SetLastError( ERROR_INVALID_INDEX );
2472 return 0;
2474 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2477 /* first some special cases */
2478 switch( offset )
2480 case GWL_STYLE:
2481 style.styleOld = wndPtr->dwStyle;
2482 style.styleNew = newval;
2483 WIN_ReleasePtr( wndPtr );
2484 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2485 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2486 newval = style.styleNew;
2487 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2488 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2489 /* WS_MINIMIZE can't be reset */
2490 if (wndPtr->dwStyle & WS_MINIMIZE) newval |= WS_MINIMIZE;
2491 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2492 WS_EX_WINDOWEDGE too */
2493 break;
2494 case GWL_EXSTYLE:
2495 style.styleOld = wndPtr->dwExStyle;
2496 style.styleNew = newval;
2497 WIN_ReleasePtr( wndPtr );
2498 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2499 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2500 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2501 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2502 /* WS_EX_WINDOWEDGE depends on some other styles */
2503 if (newval & WS_EX_DLGMODALFRAME)
2504 newval |= WS_EX_WINDOWEDGE;
2505 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2506 newval |= WS_EX_WINDOWEDGE;
2507 else
2508 newval &= ~WS_EX_WINDOWEDGE;
2509 break;
2510 case GWLP_HWNDPARENT:
2511 if (wndPtr->parent == GetDesktopWindow())
2513 WIN_ReleasePtr( wndPtr );
2514 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2516 else
2518 WIN_ReleasePtr( wndPtr );
2519 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2521 case GWLP_WNDPROC:
2523 WNDPROC proc;
2524 UINT old_flags = wndPtr->flags;
2525 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2526 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2527 if (proc) wndPtr->winproc = proc;
2528 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2529 else wndPtr->flags &= ~WIN_ISUNICODE;
2530 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2532 WIN_ReleasePtr( wndPtr );
2533 return retval;
2535 /* update is_unicode flag on the server side */
2536 break;
2538 case GWLP_ID:
2539 case GWLP_HINSTANCE:
2540 case GWLP_USERDATA:
2541 break;
2542 case DWLP_DLGPROC:
2543 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2544 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2546 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2547 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2548 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2549 WIN_ReleasePtr( wndPtr );
2550 return retval;
2552 /* fall through */
2553 default:
2554 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2556 WARN("Invalid offset %d\n", offset );
2557 WIN_ReleasePtr( wndPtr );
2558 SetLastError( ERROR_INVALID_INDEX );
2559 return 0;
2561 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2563 /* already set to the same value */
2564 WIN_ReleasePtr( wndPtr );
2565 return newval;
2567 break;
2570 SERVER_START_REQ( set_window_info )
2572 req->handle = wine_server_user_handle( hwnd );
2573 req->extra_offset = -1;
2574 switch(offset)
2576 case GWL_STYLE:
2577 req->flags = SET_WIN_STYLE;
2578 req->style = newval;
2579 break;
2580 case GWL_EXSTYLE:
2581 req->flags = SET_WIN_EXSTYLE;
2582 req->ex_style = newval;
2583 break;
2584 case GWLP_ID:
2585 req->flags = SET_WIN_ID;
2586 req->id = newval;
2587 break;
2588 case GWLP_HINSTANCE:
2589 req->flags = SET_WIN_INSTANCE;
2590 req->instance = wine_server_client_ptr( (void *)newval );
2591 break;
2592 case GWLP_WNDPROC:
2593 req->flags = SET_WIN_UNICODE;
2594 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2595 break;
2596 case GWLP_USERDATA:
2597 req->flags = SET_WIN_USERDATA;
2598 req->user_data = newval;
2599 break;
2600 default:
2601 req->flags = SET_WIN_EXTRA;
2602 req->extra_offset = offset;
2603 req->extra_size = size;
2604 set_win_data( &req->extra_value, newval, size );
2606 if ((ok = !wine_server_call_err( req )))
2608 switch(offset)
2610 case GWL_STYLE:
2611 wndPtr->dwStyle = newval;
2612 retval = reply->old_style;
2613 break;
2614 case GWL_EXSTYLE:
2615 wndPtr->dwExStyle = newval;
2616 retval = reply->old_ex_style;
2617 break;
2618 case GWLP_ID:
2619 wndPtr->wIDmenu = newval;
2620 retval = reply->old_id;
2621 break;
2622 case GWLP_HINSTANCE:
2623 wndPtr->hInstance = (HINSTANCE)newval;
2624 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2625 break;
2626 case GWLP_WNDPROC:
2627 break;
2628 case GWLP_USERDATA:
2629 wndPtr->userdata = newval;
2630 retval = reply->old_user_data;
2631 break;
2632 default:
2633 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2634 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2635 break;
2639 SERVER_END_REQ;
2641 if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2642 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2644 made_visible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
2645 invalidate_dce( wndPtr, NULL );
2647 WIN_ReleasePtr( wndPtr );
2649 if (!ok) return 0;
2651 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2653 style.styleOld = retval;
2654 style.styleNew = newval;
2655 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2656 if (made_visible) update_window_state( hwnd );
2657 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2660 return retval;
2664 /**********************************************************************
2665 * GetWindowWord (USER32.@)
2667 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2669 switch(offset)
2671 case GWLP_ID:
2672 case GWLP_HINSTANCE:
2673 case GWLP_HWNDPARENT:
2674 break;
2675 default:
2676 if (offset < 0)
2678 WARN("Invalid offset %d\n", offset );
2679 SetLastError( ERROR_INVALID_INDEX );
2680 return 0;
2682 break;
2684 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2688 /**********************************************************************
2689 * GetWindowLongA (USER32.@)
2691 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2693 switch (offset)
2695 #ifdef _WIN64
2696 case GWLP_WNDPROC:
2697 case GWLP_HINSTANCE:
2698 case GWLP_HWNDPARENT:
2699 WARN( "Invalid offset %d\n", offset );
2700 SetLastError( ERROR_INVALID_INDEX );
2701 return 0;
2702 #endif
2703 default:
2704 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2709 /**********************************************************************
2710 * GetWindowLongW (USER32.@)
2712 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2714 switch (offset)
2716 #ifdef _WIN64
2717 case GWLP_WNDPROC:
2718 case GWLP_HINSTANCE:
2719 case GWLP_HWNDPARENT:
2720 WARN( "Invalid offset %d\n", offset );
2721 SetLastError( ERROR_INVALID_INDEX );
2722 return 0;
2723 #endif
2724 default:
2725 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2730 /**********************************************************************
2731 * SetWindowWord (USER32.@)
2733 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2735 switch(offset)
2737 case GWLP_ID:
2738 case GWLP_HINSTANCE:
2739 case GWLP_HWNDPARENT:
2740 break;
2741 default:
2742 if (offset < 0)
2744 WARN("Invalid offset %d\n", offset );
2745 SetLastError( ERROR_INVALID_INDEX );
2746 return 0;
2748 break;
2750 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2754 /**********************************************************************
2755 * SetWindowLongA (USER32.@)
2757 * See SetWindowLongW.
2759 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2761 switch (offset)
2763 #ifdef _WIN64
2764 case GWLP_WNDPROC:
2765 case GWLP_HINSTANCE:
2766 case GWLP_HWNDPARENT:
2767 WARN( "Invalid offset %d\n", offset );
2768 SetLastError( ERROR_INVALID_INDEX );
2769 return 0;
2770 #endif
2771 default:
2772 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2777 /**********************************************************************
2778 * SetWindowLongW (USER32.@) Set window attribute
2780 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2781 * value in a window's extra memory.
2783 * The _hwnd_ parameter specifies the handle to a window that
2784 * has extra memory. The _newval_ parameter contains the new
2785 * attribute or extra memory value. If positive, the _offset_
2786 * parameter is the byte-addressed location in the window's extra
2787 * memory to set. If negative, _offset_ specifies the window
2788 * attribute to set, and should be one of the following values:
2790 * GWL_EXSTYLE The window's extended window style
2792 * GWL_STYLE The window's window style.
2794 * GWLP_WNDPROC Pointer to the window's window procedure.
2796 * GWLP_HINSTANCE The window's application instance handle.
2798 * GWLP_ID The window's identifier.
2800 * GWLP_USERDATA The window's user-specified data.
2802 * If the window is a dialog box, the _offset_ parameter can be one of
2803 * the following values:
2805 * DWLP_DLGPROC The address of the window's dialog box procedure.
2807 * DWLP_MSGRESULT The return value of a message
2808 * that the dialog box procedure processed.
2810 * DWLP_USER Application specific information.
2812 * RETURNS
2814 * If successful, returns the previous value located at _offset_. Otherwise,
2815 * returns 0.
2817 * NOTES
2819 * Extra memory for a window class is specified by a nonzero cbWndExtra
2820 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2821 * time of class creation.
2823 * Using GWL_WNDPROC to set a new window procedure effectively creates
2824 * a window subclass. Use CallWindowProc() in the new windows procedure
2825 * to pass messages to the superclass's window procedure.
2827 * The user data is reserved for use by the application which created
2828 * the window.
2830 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2831 * instead, call the EnableWindow() function to change the window's
2832 * disabled state.
2834 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2835 * SetParent() instead.
2837 * Win95:
2838 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2839 * it sends WM_STYLECHANGING before changing the settings
2840 * and WM_STYLECHANGED afterwards.
2841 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2843 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongW(
2844 HWND hwnd, /* [in] window to alter */
2845 INT offset, /* [in] offset, in bytes, of location to alter */
2846 LONG newval /* [in] new value of location */
2849 switch (offset)
2851 #ifdef _WIN64
2852 case GWLP_WNDPROC:
2853 case GWLP_HINSTANCE:
2854 case GWLP_HWNDPARENT:
2855 WARN("Invalid offset %d\n", offset );
2856 SetLastError( ERROR_INVALID_INDEX );
2857 return 0;
2858 #endif
2859 default:
2860 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2865 /*******************************************************************
2866 * GetWindowTextA (USER32.@)
2868 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2870 WCHAR *buffer;
2872 if (!lpString || nMaxCount <= 0) return 0;
2874 if (WIN_IsCurrentProcess( hwnd ))
2876 lpString[0] = 0;
2877 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2880 /* when window belongs to other process, don't send a message */
2881 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2882 get_server_window_text( hwnd, buffer, nMaxCount );
2883 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2884 lpString[nMaxCount-1] = 0;
2885 HeapFree( GetProcessHeap(), 0, buffer );
2886 return strlen(lpString);
2890 /*******************************************************************
2891 * InternalGetWindowText (USER32.@)
2893 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2895 WND *win;
2897 if (nMaxCount <= 0) return 0;
2898 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2899 if (win == WND_DESKTOP) lpString[0] = 0;
2900 else if (win != WND_OTHER_PROCESS)
2902 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2903 else lpString[0] = 0;
2904 WIN_ReleasePtr( win );
2906 else
2908 get_server_window_text( hwnd, lpString, nMaxCount );
2910 return lstrlenW(lpString);
2914 /*******************************************************************
2915 * GetWindowTextW (USER32.@)
2917 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2919 if (!lpString || nMaxCount <= 0) return 0;
2921 if (WIN_IsCurrentProcess( hwnd ))
2923 lpString[0] = 0;
2924 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2927 /* when window belongs to other process, don't send a message */
2928 get_server_window_text( hwnd, lpString, nMaxCount );
2929 return lstrlenW(lpString);
2933 /*******************************************************************
2934 * SetWindowTextA (USER32.@)
2935 * SetWindowText (USER32.@)
2937 BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextA( HWND hwnd, LPCSTR lpString )
2939 if (is_broadcast(hwnd))
2941 SetLastError( ERROR_INVALID_PARAMETER );
2942 return FALSE;
2944 if (!WIN_IsCurrentProcess( hwnd ))
2945 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2946 debugstr_a(lpString), hwnd );
2947 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2951 /*******************************************************************
2952 * SetWindowTextW (USER32.@)
2954 BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2956 if (is_broadcast(hwnd))
2958 SetLastError( ERROR_INVALID_PARAMETER );
2959 return FALSE;
2961 if (!WIN_IsCurrentProcess( hwnd ))
2962 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2963 debugstr_w(lpString), hwnd );
2964 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2968 /*******************************************************************
2969 * GetWindowTextLengthA (USER32.@)
2971 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2973 CPINFO info;
2975 if (WIN_IsCurrentProcess( hwnd )) return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2977 /* when window belongs to other process, don't send a message */
2978 GetCPInfo( CP_ACP, &info );
2979 return get_server_window_text( hwnd, NULL, 0 ) * info.MaxCharSize;
2982 /*******************************************************************
2983 * GetWindowTextLengthW (USER32.@)
2985 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2987 if (WIN_IsCurrentProcess( hwnd )) return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2989 /* when window belongs to other process, don't send a message */
2990 return get_server_window_text( hwnd, NULL, 0 );
2994 /*******************************************************************
2995 * IsWindow (USER32.@)
2997 BOOL WINAPI IsWindow( HWND hwnd )
2999 WND *ptr;
3000 BOOL ret;
3002 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
3003 if (ptr == WND_DESKTOP) return TRUE;
3005 if (ptr != WND_OTHER_PROCESS)
3007 WIN_ReleasePtr( ptr );
3008 return TRUE;
3011 /* check other processes */
3012 SERVER_START_REQ( get_window_info )
3014 req->handle = wine_server_user_handle( hwnd );
3015 ret = !wine_server_call_err( req );
3017 SERVER_END_REQ;
3018 return ret;
3022 /***********************************************************************
3023 * GetWindowThreadProcessId (USER32.@)
3025 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
3027 WND *ptr;
3028 DWORD tid = 0;
3030 if (!(ptr = WIN_GetPtr( hwnd )))
3032 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
3033 return 0;
3036 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
3038 /* got a valid window */
3039 tid = ptr->tid;
3040 if (process) *process = GetCurrentProcessId();
3041 WIN_ReleasePtr( ptr );
3042 return tid;
3045 /* check other processes */
3046 SERVER_START_REQ( get_window_info )
3048 req->handle = wine_server_user_handle( hwnd );
3049 if (!wine_server_call_err( req ))
3051 tid = (DWORD)reply->tid;
3052 if (process) *process = (DWORD)reply->pid;
3055 SERVER_END_REQ;
3056 return tid;
3060 /*****************************************************************
3061 * GetParent (USER32.@)
3063 HWND WINAPI GetParent( HWND hwnd )
3065 WND *wndPtr;
3066 HWND retvalue = 0;
3068 if (!(wndPtr = WIN_GetPtr( hwnd )))
3070 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3071 return 0;
3073 if (wndPtr == WND_DESKTOP) return 0;
3074 if (wndPtr == WND_OTHER_PROCESS)
3076 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3077 if (style & (WS_POPUP | WS_CHILD))
3079 SERVER_START_REQ( get_window_tree )
3081 req->handle = wine_server_user_handle( hwnd );
3082 if (!wine_server_call_err( req ))
3084 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
3085 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
3088 SERVER_END_REQ;
3091 else
3093 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
3094 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
3095 WIN_ReleasePtr( wndPtr );
3097 return retvalue;
3101 /*****************************************************************
3102 * GetAncestor (USER32.@)
3104 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
3106 WND *win;
3107 HWND *list, ret = 0;
3109 switch(type)
3111 case GA_PARENT:
3112 if (!(win = WIN_GetPtr( hwnd )))
3114 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3115 return 0;
3117 if (win == WND_DESKTOP) return 0;
3118 if (win != WND_OTHER_PROCESS)
3120 ret = win->parent;
3121 WIN_ReleasePtr( win );
3123 else /* need to query the server */
3125 SERVER_START_REQ( get_window_tree )
3127 req->handle = wine_server_user_handle( hwnd );
3128 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
3130 SERVER_END_REQ;
3132 break;
3134 case GA_ROOT:
3135 if (!(list = list_window_parents( hwnd ))) return 0;
3137 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
3138 else
3140 int count = 2;
3141 while (list[count]) count++;
3142 ret = list[count - 2]; /* get the one before the desktop */
3144 HeapFree( GetProcessHeap(), 0, list );
3145 break;
3147 case GA_ROOTOWNER:
3148 if (is_desktop_window( hwnd )) return 0;
3149 ret = WIN_GetFullHandle( hwnd );
3150 for (;;)
3152 HWND parent = GetParent( ret );
3153 if (!parent) break;
3154 ret = parent;
3156 break;
3158 return ret;
3162 /*****************************************************************
3163 * SetParent (USER32.@)
3165 HWND WINAPI SetParent( HWND hwnd, HWND parent )
3167 WINDOWPOS winpos;
3168 HWND full_handle;
3169 HWND old_parent = 0;
3170 BOOL was_visible;
3171 WND *wndPtr;
3172 BOOL ret;
3173 DPI_AWARENESS_CONTEXT context;
3174 RECT window_rect, old_screen_rect, new_screen_rect;
3176 TRACE("(%p %p)\n", hwnd, parent);
3178 if (is_broadcast(hwnd) || is_broadcast(parent))
3180 SetLastError(ERROR_INVALID_PARAMETER);
3181 return 0;
3184 if (!parent) parent = GetDesktopWindow();
3185 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
3186 else parent = WIN_GetFullHandle( parent );
3188 if (!IsWindow( parent ))
3190 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3191 return 0;
3194 /* Some applications try to set a child as a parent */
3195 if (IsChild(hwnd, parent))
3197 SetLastError( ERROR_INVALID_PARAMETER );
3198 return 0;
3201 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
3202 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
3204 if (full_handle == parent)
3206 SetLastError( ERROR_INVALID_PARAMETER );
3207 return 0;
3210 /* Windows hides the window first, then shows it again
3211 * including the WM_SHOWWINDOW messages and all */
3212 was_visible = ShowWindow( hwnd, SW_HIDE );
3214 wndPtr = WIN_GetPtr( hwnd );
3215 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
3217 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
3218 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, NULL );
3219 SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3220 WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_screen_rect, NULL );
3221 SetThreadDpiAwarenessContext( context );
3223 SERVER_START_REQ( set_parent )
3225 req->handle = wine_server_user_handle( hwnd );
3226 req->parent = wine_server_user_handle( parent );
3227 if ((ret = !wine_server_call( req )))
3229 old_parent = wine_server_ptr_handle( reply->old_parent );
3230 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3231 wndPtr->dpi = reply->dpi;
3232 wndPtr->dpi_awareness = reply->awareness;
3236 SERVER_END_REQ;
3237 WIN_ReleasePtr( wndPtr );
3238 if (!ret) return 0;
3240 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3241 WIN_GetRectangles( hwnd, COORDS_SCREEN, &new_screen_rect, NULL );
3242 SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
3244 USER_Driver->pSetParent( full_handle, parent, old_parent );
3246 winpos.hwnd = hwnd;
3247 winpos.hwndInsertAfter = HWND_TOP;
3248 winpos.x = window_rect.left;
3249 winpos.y = window_rect.top;
3250 winpos.cx = 0;
3251 winpos.cy = 0;
3252 winpos.flags = SWP_NOSIZE;
3254 USER_SetWindowPos( &winpos, new_screen_rect.left - old_screen_rect.left,
3255 new_screen_rect.top - old_screen_rect.top );
3257 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3259 SetThreadDpiAwarenessContext( context );
3260 return old_parent;
3264 /*******************************************************************
3265 * IsChild (USER32.@)
3267 BOOL WINAPI IsChild( HWND parent, HWND child )
3269 HWND *list;
3270 int i;
3271 BOOL ret = FALSE;
3273 if (!(GetWindowLongW( child, GWL_STYLE ) & WS_CHILD)) return FALSE;
3274 if (!(list = list_window_parents( child ))) return FALSE;
3275 parent = WIN_GetFullHandle( parent );
3276 for (i = 0; list[i]; i++)
3278 if (list[i] == parent)
3280 ret = list[i] && list[i+1];
3281 break;
3283 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_CHILD)) break;
3285 HeapFree( GetProcessHeap(), 0, list );
3286 return ret;
3290 /***********************************************************************
3291 * IsWindowVisible (USER32.@)
3293 BOOL WINAPI IsWindowVisible( HWND hwnd )
3295 HWND *list;
3296 BOOL retval = TRUE;
3297 int i;
3299 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3300 if (!(list = list_window_parents( hwnd ))) return TRUE;
3301 if (list[0])
3303 for (i = 0; list[i+1]; i++)
3304 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3305 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3307 HeapFree( GetProcessHeap(), 0, list );
3308 return retval;
3312 /***********************************************************************
3313 * WIN_IsWindowDrawable
3315 * hwnd is drawable when it is visible, all parents are not
3316 * minimized, and it is itself not minimized unless we are
3317 * trying to draw its default class icon.
3319 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3321 HWND *list;
3322 BOOL retval = TRUE;
3323 int i;
3324 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3326 if (!(style & WS_VISIBLE)) return FALSE;
3327 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3329 if (!(list = list_window_parents( hwnd ))) return TRUE;
3330 if (list[0])
3332 for (i = 0; list[i+1]; i++)
3333 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3334 break;
3335 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3337 HeapFree( GetProcessHeap(), 0, list );
3338 return retval;
3342 /*******************************************************************
3343 * GetTopWindow (USER32.@)
3345 HWND WINAPI GetTopWindow( HWND hwnd )
3347 if (!hwnd) hwnd = GetDesktopWindow();
3348 return GetWindow( hwnd, GW_CHILD );
3352 /*******************************************************************
3353 * GetWindow (USER32.@)
3355 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3357 HWND retval = 0;
3359 if (rel == GW_OWNER) /* this one may be available locally */
3361 WND *wndPtr = WIN_GetPtr( hwnd );
3362 if (!wndPtr)
3364 SetLastError( ERROR_INVALID_HANDLE );
3365 return 0;
3367 if (wndPtr == WND_DESKTOP) return 0;
3368 if (wndPtr != WND_OTHER_PROCESS)
3370 retval = wndPtr->owner;
3371 WIN_ReleasePtr( wndPtr );
3372 return retval;
3374 /* else fall through to server call */
3377 SERVER_START_REQ( get_window_tree )
3379 req->handle = wine_server_user_handle( hwnd );
3380 if (!wine_server_call_err( req ))
3382 switch(rel)
3384 case GW_HWNDFIRST:
3385 retval = wine_server_ptr_handle( reply->first_sibling );
3386 break;
3387 case GW_HWNDLAST:
3388 retval = wine_server_ptr_handle( reply->last_sibling );
3389 break;
3390 case GW_HWNDNEXT:
3391 retval = wine_server_ptr_handle( reply->next_sibling );
3392 break;
3393 case GW_HWNDPREV:
3394 retval = wine_server_ptr_handle( reply->prev_sibling );
3395 break;
3396 case GW_OWNER:
3397 retval = wine_server_ptr_handle( reply->owner );
3398 break;
3399 case GW_CHILD:
3400 retval = wine_server_ptr_handle( reply->first_child );
3401 break;
3405 SERVER_END_REQ;
3406 return retval;
3410 /*******************************************************************
3411 * ShowOwnedPopups (USER32.@)
3413 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3415 int count = 0;
3416 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3418 if (!win_array) return TRUE;
3420 while (win_array[count]) count++;
3421 while (--count >= 0)
3423 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3424 if (fShow)
3426 if (win_get_flags( win_array[count] ) & WIN_NEEDS_SHOW_OWNEDPOPUP)
3427 /* In Windows, ShowOwnedPopups(TRUE) generates
3428 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3429 * regardless of the state of the owner
3431 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3433 else
3435 if (GetWindowLongW( win_array[count], GWL_STYLE ) & WS_VISIBLE)
3436 /* In Windows, ShowOwnedPopups(FALSE) generates
3437 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3438 * regardless of the state of the owner
3440 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3443 HeapFree( GetProcessHeap(), 0, win_array );
3444 return TRUE;
3448 /*******************************************************************
3449 * GetLastActivePopup (USER32.@)
3451 HWND WINAPI GetLastActivePopup( HWND hwnd )
3453 HWND retval = hwnd;
3455 SERVER_START_REQ( get_window_info )
3457 req->handle = wine_server_user_handle( hwnd );
3458 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3460 SERVER_END_REQ;
3461 return retval;
3465 /*******************************************************************
3466 * WIN_ListChildren
3468 * Build an array of the children of a given window. The array must be
3469 * freed with HeapFree. Returns NULL when no windows are found.
3471 HWND *WIN_ListChildren( HWND hwnd )
3473 if (!hwnd)
3475 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3476 return NULL;
3478 return list_window_children( 0, hwnd, NULL, 0 );
3482 /*******************************************************************
3483 * EnumWindows (USER32.@)
3485 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3487 HWND *list;
3488 BOOL ret = TRUE;
3489 int i;
3491 USER_CheckNotLock();
3493 /* We have to build a list of all windows first, to avoid */
3494 /* unpleasant side-effects, for instance if the callback */
3495 /* function changes the Z-order of the windows. */
3497 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3499 /* Now call the callback function for every window */
3501 for (i = 0; list[i]; i++)
3503 /* Make sure that the window still exists */
3504 if (!IsWindow( list[i] )) continue;
3505 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3507 HeapFree( GetProcessHeap(), 0, list );
3508 return ret;
3512 /**********************************************************************
3513 * EnumThreadWindows (USER32.@)
3515 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3517 HWND *list;
3518 int i;
3519 BOOL ret = TRUE;
3521 USER_CheckNotLock();
3523 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3525 /* Now call the callback function for every window */
3527 for (i = 0; list[i]; i++)
3528 if (!(ret = func( list[i], lParam ))) break;
3529 HeapFree( GetProcessHeap(), 0, list );
3530 return ret;
3534 /***********************************************************************
3535 * EnumDesktopWindows (USER32.@)
3537 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3539 HWND *list;
3540 int i;
3542 USER_CheckNotLock();
3544 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3546 for (i = 0; list[i]; i++)
3547 if (!func( list[i], lparam )) break;
3548 HeapFree( GetProcessHeap(), 0, list );
3549 return TRUE;
3553 #ifdef __i386__
3554 /* Some apps pass a non-stdcall proc to EnumChildWindows,
3555 * so we need a small assembly wrapper to call the proc.
3557 extern LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam );
3558 __ASM_GLOBAL_FUNC( enum_callback_wrapper,
3559 "pushl %ebp\n\t"
3560 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
3561 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
3562 "movl %esp,%ebp\n\t"
3563 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
3564 "pushl 16(%ebp)\n\t"
3565 "pushl 12(%ebp)\n\t"
3566 "call *8(%ebp)\n\t"
3567 "leave\n\t"
3568 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
3569 __ASM_CFI(".cfi_same_value %ebp\n\t")
3570 "ret" )
3571 #else
3572 static inline LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam )
3574 return proc( hwnd, lparam );
3576 #endif /* __i386__ */
3578 /**********************************************************************
3579 * WIN_EnumChildWindows
3581 * Helper function for EnumChildWindows().
3583 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3585 HWND *childList;
3586 BOOL ret = FALSE;
3588 for ( ; *list; list++)
3590 /* Make sure that the window still exists */
3591 if (!IsWindow( *list )) continue;
3592 /* Build children list first */
3593 childList = WIN_ListChildren( *list );
3595 ret = enum_callback_wrapper( func, *list, lParam );
3597 if (childList)
3599 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3600 HeapFree( GetProcessHeap(), 0, childList );
3602 if (!ret) return FALSE;
3604 return TRUE;
3608 /**********************************************************************
3609 * EnumChildWindows (USER32.@)
3611 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3613 HWND *list;
3614 BOOL ret;
3616 USER_CheckNotLock();
3618 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3619 ret = WIN_EnumChildWindows( list, func, lParam );
3620 HeapFree( GetProcessHeap(), 0, list );
3621 return ret;
3625 /*******************************************************************
3626 * AnyPopup (USER32.@)
3628 BOOL WINAPI AnyPopup(void)
3630 int i;
3631 BOOL retvalue;
3632 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3634 if (!list) return FALSE;
3635 for (i = 0; list[i]; i++)
3637 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3639 retvalue = (list[i] != 0);
3640 HeapFree( GetProcessHeap(), 0, list );
3641 return retvalue;
3645 /*******************************************************************
3646 * FlashWindow (USER32.@)
3648 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3650 FLASHWINFO finfo;
3652 finfo.cbSize = sizeof(FLASHWINFO);
3653 finfo.dwFlags = bInvert ? FLASHW_ALL : FLASHW_STOP;
3654 finfo.uCount = 1;
3655 finfo.dwTimeout = 0;
3656 finfo.hwnd = hWnd;
3657 return FlashWindowEx( &finfo );
3660 /*******************************************************************
3661 * FlashWindowEx (USER32.@)
3663 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfinfo )
3665 WND *wndPtr;
3667 TRACE( "%p\n", pfinfo );
3669 if (!pfinfo)
3671 SetLastError( ERROR_NOACCESS );
3672 return FALSE;
3675 if (!pfinfo->hwnd || pfinfo->cbSize != sizeof(FLASHWINFO) || !IsWindow( pfinfo->hwnd ))
3677 SetLastError( ERROR_INVALID_PARAMETER );
3678 return FALSE;
3680 FIXME( "%p - semi-stub\n", pfinfo );
3682 if (IsIconic( pfinfo->hwnd ))
3684 RedrawWindow( pfinfo->hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3686 wndPtr = WIN_GetPtr( pfinfo->hwnd );
3687 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3688 if (pfinfo->dwFlags && !(wndPtr->flags & WIN_NCACTIVATED))
3690 wndPtr->flags |= WIN_NCACTIVATED;
3692 else
3694 wndPtr->flags &= ~WIN_NCACTIVATED;
3696 WIN_ReleasePtr( wndPtr );
3697 USER_Driver->pFlashWindowEx( pfinfo );
3698 return TRUE;
3700 else
3702 WPARAM wparam;
3703 HWND hwnd = pfinfo->hwnd;
3705 wndPtr = WIN_GetPtr( hwnd );
3706 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3707 hwnd = wndPtr->obj.handle; /* make it a full handle */
3709 if (pfinfo->dwFlags) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3710 else wparam = (hwnd == GetForegroundWindow());
3712 WIN_ReleasePtr( wndPtr );
3713 SendMessageW( hwnd, WM_NCACTIVATE, wparam, 0 );
3714 USER_Driver->pFlashWindowEx( pfinfo );
3715 return wparam;
3719 /*******************************************************************
3720 * GetWindowContextHelpId (USER32.@)
3722 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3724 DWORD retval;
3725 WND *wnd = WIN_GetPtr( hwnd );
3726 if (!wnd || wnd == WND_DESKTOP) return 0;
3727 if (wnd == WND_OTHER_PROCESS)
3729 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3730 return 0;
3732 retval = wnd->helpContext;
3733 WIN_ReleasePtr( wnd );
3734 return retval;
3738 /*******************************************************************
3739 * SetWindowContextHelpId (USER32.@)
3741 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3743 WND *wnd = WIN_GetPtr( hwnd );
3744 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3745 if (wnd == WND_OTHER_PROCESS)
3747 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3748 return FALSE;
3750 wnd->helpContext = id;
3751 WIN_ReleasePtr( wnd );
3752 return TRUE;
3756 /*******************************************************************
3757 * DragDetect (USER32.@)
3759 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3761 MSG msg;
3762 RECT rect;
3763 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3764 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3766 SetRect(&rect, pt.x - wDragWidth, pt.y - wDragHeight, pt.x + wDragWidth, pt.y + wDragHeight);
3768 SetCapture(hWnd);
3770 while(1)
3772 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3774 if( msg.message == WM_LBUTTONUP )
3776 ReleaseCapture();
3777 return FALSE;
3779 if( msg.message == WM_MOUSEMOVE )
3781 POINT tmp;
3782 tmp.x = (short)LOWORD(msg.lParam);
3783 tmp.y = (short)HIWORD(msg.lParam);
3784 if( !PtInRect( &rect, tmp ))
3786 ReleaseCapture();
3787 return TRUE;
3791 WaitMessage();
3793 return FALSE;
3796 /******************************************************************************
3797 * GetWindowModuleFileNameA (USER32.@)
3799 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3801 WND *win;
3802 HINSTANCE hinst;
3804 TRACE( "%p, %p, %u\n", hwnd, module, size );
3806 win = WIN_GetPtr( hwnd );
3807 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3809 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3810 return 0;
3812 hinst = win->hInstance;
3813 WIN_ReleasePtr( win );
3815 return GetModuleFileNameA( hinst, module, size );
3818 /******************************************************************************
3819 * GetWindowModuleFileNameW (USER32.@)
3821 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3823 WND *win;
3824 HINSTANCE hinst;
3826 TRACE( "%p, %p, %u\n", hwnd, module, size );
3828 win = WIN_GetPtr( hwnd );
3829 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3831 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3832 return 0;
3834 hinst = win->hInstance;
3835 WIN_ReleasePtr( win );
3837 return GetModuleFileNameW( hinst, module, size );
3840 /******************************************************************************
3841 * GetWindowInfo (USER32.@)
3843 * Note: tests show that Windows doesn't check cbSize of the structure.
3845 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3847 RECT rcWindow, rcClient;
3849 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &rcWindow, &rcClient )) return FALSE;
3850 if (!pwi) return FALSE;
3852 pwi->rcWindow = rcWindow;
3853 pwi->rcClient = rcClient;
3854 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3855 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3856 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3858 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3859 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3861 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3862 pwi->wCreatorVersion = 0x0400;
3864 return TRUE;
3867 /******************************************************************************
3868 * SwitchDesktop (USER32.@)
3870 * NOTES: Sets the current input or interactive desktop.
3872 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3874 FIXME("(hwnd %p) stub!\n", hDesktop);
3875 return TRUE;
3879 /***********************************************************************
3880 * __wine_set_pixel_format
3882 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3884 WND *win = WIN_GetPtr( hwnd );
3886 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3888 WARN( "setting format %d on win %p not supported\n", format, hwnd );
3889 return FALSE;
3891 win->pixel_format = format;
3892 WIN_ReleasePtr( win );
3894 update_window_state( hwnd );
3895 return TRUE;
3899 /*****************************************************************************
3900 * SetLayeredWindowAttributes (USER32.@)
3902 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3904 BOOL ret;
3906 TRACE("(%p,%08x,%d,%x)\n", hwnd, key, alpha, flags);
3908 SERVER_START_REQ( set_window_layered_info )
3910 req->handle = wine_server_user_handle( hwnd );
3911 req->color_key = key;
3912 req->alpha = alpha;
3913 req->flags = flags;
3914 ret = !wine_server_call_err( req );
3916 SERVER_END_REQ;
3918 if (ret)
3920 USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3921 update_window_state( hwnd );
3924 return ret;
3928 /*****************************************************************************
3929 * GetLayeredWindowAttributes (USER32.@)
3931 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3933 BOOL ret;
3935 SERVER_START_REQ( get_window_layered_info )
3937 req->handle = wine_server_user_handle( hwnd );
3938 if ((ret = !wine_server_call_err( req )))
3940 if (key) *key = reply->color_key;
3941 if (alpha) *alpha = reply->alpha;
3942 if (flags) *flags = reply->flags;
3945 SERVER_END_REQ;
3947 return ret;
3951 /*****************************************************************************
3952 * UpdateLayeredWindowIndirect (USER32.@)
3954 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3956 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3957 RECT window_rect, client_rect;
3958 SIZE offset;
3960 if (!info ||
3961 info->cbSize != sizeof(*info) ||
3962 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3963 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3964 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3966 SetLastError( ERROR_INVALID_PARAMETER );
3967 return FALSE;
3970 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3972 if (info->pptDst)
3974 offset.cx = info->pptDst->x - window_rect.left;
3975 offset.cy = info->pptDst->y - window_rect.top;
3976 OffsetRect( &client_rect, offset.cx, offset.cy );
3977 OffsetRect( &window_rect, offset.cx, offset.cy );
3978 flags &= ~SWP_NOMOVE;
3980 if (info->psize)
3982 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3983 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3984 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3986 SetLastError( ERROR_INVALID_PARAMETER );
3987 return FALSE;
3989 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3991 SetLastError( ERROR_INCORRECT_SIZE );
3992 return FALSE;
3994 client_rect.right += offset.cx;
3995 client_rect.bottom += offset.cy;
3996 window_rect.right += offset.cx;
3997 window_rect.bottom += offset.cy;
3998 flags &= ~SWP_NOSIZE;
4001 TRACE( "window %p win %s client %s\n", hwnd,
4002 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
4004 if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
4006 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
4007 return TRUE;
4011 /*****************************************************************************
4012 * UpdateLayeredWindow (USER32.@)
4014 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
4015 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
4016 DWORD flags)
4018 UPDATELAYEREDWINDOWINFO info;
4020 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
4022 SetLastError( ERROR_INVALID_PARAMETER );
4023 return FALSE;
4025 info.cbSize = sizeof(info);
4026 info.hdcDst = hdcDst;
4027 info.pptDst = pptDst;
4028 info.psize = psize;
4029 info.hdcSrc = hdcSrc;
4030 info.pptSrc = pptSrc;
4031 info.crKey = crKey;
4032 info.pblend = pblend;
4033 info.dwFlags = flags;
4034 info.prcDirty = NULL;
4035 return UpdateLayeredWindowIndirect( hwnd, &info );
4039 /******************************************************************************
4040 * GetProcessDefaultLayout [USER32.@]
4042 * Gets the default layout for parentless windows.
4044 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
4046 if (!layout)
4048 SetLastError( ERROR_NOACCESS );
4049 return FALSE;
4051 if (process_layout == ~0u)
4053 WCHAR *str, buffer[MAX_PATH];
4054 DWORD i, len, version_layout = 0;
4055 DWORD user_lang = GetUserDefaultLangID();
4056 DWORD *languages;
4057 void *data = NULL;
4059 GetModuleFileNameW( 0, buffer, MAX_PATH );
4060 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
4061 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
4062 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
4063 if (!VerQueryValueW( data, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done;
4065 len /= sizeof(DWORD);
4066 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
4067 if (i == len) /* try neutral language */
4068 for (i = 0; i < len; i++)
4069 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
4070 if (i == len) i = 0; /* default to the first one */
4072 swprintf( buffer, ARRAY_SIZE(buffer), L"\\StringFileInfo\\%04x%04x\\FileDescription",
4073 LOWORD(languages[i]), HIWORD(languages[i]) );
4074 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
4075 TRACE( "found description %s\n", debugstr_w( str ));
4076 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
4078 done:
4079 HeapFree( GetProcessHeap(), 0, data );
4080 process_layout = version_layout;
4082 *layout = process_layout;
4083 return TRUE;
4087 /******************************************************************************
4088 * SetProcessDefaultLayout [USER32.@]
4090 * Sets the default layout for parentless windows.
4092 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
4094 process_layout = layout;
4095 return TRUE;
4099 /* 64bit versions */
4101 #ifdef GetWindowLongPtrW
4102 #undef GetWindowLongPtrW
4103 #endif
4105 #ifdef GetWindowLongPtrA
4106 #undef GetWindowLongPtrA
4107 #endif
4109 #ifdef SetWindowLongPtrW
4110 #undef SetWindowLongPtrW
4111 #endif
4113 #ifdef SetWindowLongPtrA
4114 #undef SetWindowLongPtrA
4115 #endif
4117 /*****************************************************************************
4118 * GetWindowLongPtrW (USER32.@)
4120 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
4122 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
4125 /*****************************************************************************
4126 * GetWindowLongPtrA (USER32.@)
4128 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
4130 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
4133 /*****************************************************************************
4134 * SetWindowLongPtrW (USER32.@)
4136 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
4138 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
4141 /*****************************************************************************
4142 * SetWindowLongPtrA (USER32.@)
4144 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
4146 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
4149 /*****************************************************************************
4150 * RegisterTouchWindow (USER32.@)
4152 BOOL WINAPI RegisterTouchWindow(HWND hwnd, ULONG flags)
4154 FIXME("(%p %08x): stub\n", hwnd, flags);
4155 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4156 return FALSE;
4159 /*****************************************************************************
4160 * UnregisterTouchWindow (USER32.@)
4162 BOOL WINAPI UnregisterTouchWindow(HWND hwnd)
4164 FIXME("(%p): stub\n", hwnd);
4165 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4166 return FALSE;
4169 /*****************************************************************************
4170 * CloseTouchInputHandle (USER32.@)
4172 BOOL WINAPI CloseTouchInputHandle(HTOUCHINPUT handle)
4174 FIXME("(%p): stub\n", handle);
4175 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4176 return FALSE;
4179 /*****************************************************************************
4180 * GetTouchInputInfo (USER32.@)
4182 BOOL WINAPI GetTouchInputInfo(HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size)
4184 FIXME("(%p %u %p %u): stub\n", handle, count, ptr, size);
4185 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4186 return FALSE;
4189 /*****************************************************************************
4190 * GetGestureInfo (USER32.@)
4192 BOOL WINAPI GetGestureInfo(HGESTUREINFO handle, PGESTUREINFO ptr)
4194 FIXME("(%p %p): stub\n", handle, ptr);
4195 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4196 return FALSE;
4199 /*****************************************************************************
4200 * GetWindowDisplayAffinity (USER32.@)
4202 BOOL WINAPI GetWindowDisplayAffinity(HWND hwnd, DWORD *affinity)
4204 FIXME("(%p, %p): stub\n", hwnd, affinity);
4206 if (!hwnd || !affinity)
4208 SetLastError(hwnd ? ERROR_NOACCESS : ERROR_INVALID_WINDOW_HANDLE);
4209 return FALSE;
4212 *affinity = WDA_NONE;
4213 return TRUE;
4216 /*****************************************************************************
4217 * SetWindowDisplayAffinity (USER32.@)
4219 BOOL WINAPI SetWindowDisplayAffinity(HWND hwnd, DWORD affinity)
4221 FIXME("(%p, %u): stub\n", hwnd, affinity);
4223 if (!hwnd)
4225 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
4226 return FALSE;
4229 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4230 return FALSE;
4233 /**********************************************************************
4234 * SetWindowCompositionAttribute (USER32.@)
4236 BOOL WINAPI SetWindowCompositionAttribute(HWND hwnd, void *data)
4238 FIXME("(%p, %p): stub\n", hwnd, data);
4239 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4240 return FALSE;