windowscodecs: Add more tests for PNG metadata.
[wine/multimedia.git] / dlls / user32 / win.c
blob2a0848e1fb8d8506f7cffe7098ad8f1a902414b8
1 /*
2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winver.h"
31 #include "wine/server.h"
32 #include "wine/unicode.h"
33 #include "win.h"
34 #include "user_private.h"
35 #include "controls.h"
36 #include "winerror.h"
37 #include "wine/gdi_driver.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
42 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
43 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
45 static DWORD process_layout = ~0u;
47 static struct list window_surfaces = LIST_INIT( window_surfaces );
49 static CRITICAL_SECTION surfaces_section;
50 static CRITICAL_SECTION_DEBUG critsect_debug =
52 0, 0, &surfaces_section,
53 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
54 0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
56 static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };
58 /**********************************************************************/
60 /* helper for Get/SetWindowLong */
61 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
63 if (size == sizeof(WORD))
65 WORD ret;
66 memcpy( &ret, ptr, sizeof(ret) );
67 return ret;
69 else if (size == sizeof(DWORD))
71 DWORD ret;
72 memcpy( &ret, ptr, sizeof(ret) );
73 return ret;
75 else
77 LONG_PTR ret;
78 memcpy( &ret, ptr, sizeof(ret) );
79 return ret;
83 /* helper for Get/SetWindowLong */
84 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
86 if (size == sizeof(WORD))
88 WORD newval = val;
89 memcpy( ptr, &newval, sizeof(newval) );
91 else if (size == sizeof(DWORD))
93 DWORD newval = val;
94 memcpy( ptr, &newval, sizeof(newval) );
96 else
98 memcpy( ptr, &val, sizeof(val) );
103 static void *user_handles[NB_USER_HANDLES];
105 /***********************************************************************
106 * alloc_user_handle
108 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
110 HANDLE handle = 0;
112 SERVER_START_REQ( alloc_user_handle )
114 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
116 SERVER_END_REQ;
118 if (handle)
120 UINT index = USER_HANDLE_TO_INDEX( handle );
122 assert( index < NB_USER_HANDLES );
123 ptr->handle = handle;
124 ptr->type = type;
125 InterlockedExchangePointer( &user_handles[index], ptr );
127 return handle;
131 /***********************************************************************
132 * get_user_handle_ptr
134 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
136 struct user_object *ptr;
137 WORD index = USER_HANDLE_TO_INDEX( handle );
139 if (index >= NB_USER_HANDLES) return NULL;
141 USER_Lock();
142 if ((ptr = user_handles[index]))
144 if (ptr->type == type &&
145 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
146 !HIWORD(handle) || HIWORD(handle) == 0xffff))
147 return ptr;
148 ptr = NULL;
150 else ptr = OBJ_OTHER_PROCESS;
151 USER_Unlock();
152 return ptr;
156 /***********************************************************************
157 * release_user_handle_ptr
159 void release_user_handle_ptr( void *ptr )
161 assert( ptr && ptr != OBJ_OTHER_PROCESS );
162 USER_Unlock();
166 /***********************************************************************
167 * free_user_handle
169 void *free_user_handle( HANDLE handle, enum user_obj_type type )
171 struct user_object *ptr;
172 WORD index = USER_HANDLE_TO_INDEX( handle );
174 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
176 SERVER_START_REQ( free_user_handle )
178 req->handle = wine_server_user_handle( handle );
179 if (wine_server_call( req )) ptr = NULL;
180 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
182 SERVER_END_REQ;
183 release_user_handle_ptr( ptr );
185 return ptr;
189 /***********************************************************************
190 * create_window_handle
192 * Create a window handle with the server.
194 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
195 HINSTANCE instance, BOOL unicode )
197 WORD index;
198 WND *win;
199 HWND handle = 0, full_parent = 0, full_owner = 0;
200 struct tagCLASS *class = NULL;
201 int extra_bytes = 0;
203 SERVER_START_REQ( create_window )
205 req->parent = wine_server_user_handle( parent );
206 req->owner = wine_server_user_handle( owner );
207 req->instance = wine_server_client_ptr( instance );
208 if (!(req->atom = get_int_atom_value( name )) && name)
209 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
210 if (!wine_server_call_err( req ))
212 handle = wine_server_ptr_handle( reply->handle );
213 full_parent = wine_server_ptr_handle( reply->parent );
214 full_owner = wine_server_ptr_handle( reply->owner );
215 extra_bytes = reply->extra;
216 class = wine_server_get_ptr( reply->class_ptr );
219 SERVER_END_REQ;
221 if (!handle)
223 WARN( "error %d creating window\n", GetLastError() );
224 return NULL;
227 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
228 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
230 SERVER_START_REQ( destroy_window )
232 req->handle = wine_server_user_handle( handle );
233 wine_server_call( req );
235 SERVER_END_REQ;
236 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
237 return NULL;
240 if (!parent) /* if parent is 0 we don't have a desktop window yet */
242 struct user_thread_info *thread_info = get_user_thread_info();
244 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
246 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
247 else assert( full_parent == thread_info->top_window );
248 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
249 ERR( "failed to create desktop window\n" );
251 else /* HWND_MESSAGE parent */
253 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
257 USER_Lock();
259 index = USER_HANDLE_TO_INDEX(handle);
260 assert( index < NB_USER_HANDLES );
261 win->obj.handle = handle;
262 win->obj.type = USER_WINDOW;
263 win->parent = full_parent;
264 win->owner = full_owner;
265 win->class = class;
266 win->winproc = get_class_winproc( class );
267 win->cbWndExtra = extra_bytes;
268 InterlockedExchangePointer( &user_handles[index], win );
269 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
270 return win;
274 /***********************************************************************
275 * free_window_handle
277 * Free a window handle.
279 static void free_window_handle( HWND hwnd )
281 struct user_object *ptr;
282 WORD index = USER_HANDLE_TO_INDEX(hwnd);
284 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
286 SERVER_START_REQ( destroy_window )
288 req->handle = wine_server_user_handle( hwnd );
289 if (wine_server_call_err( req )) ptr = NULL;
290 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
292 SERVER_END_REQ;
293 release_user_handle_ptr( ptr );
294 HeapFree( GetProcessHeap(), 0, ptr );
299 /*******************************************************************
300 * list_window_children
302 * Build an array of the children of a given window. The array must be
303 * freed with HeapFree. Returns NULL when no windows are found.
305 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
307 HWND *list;
308 int i, size = 128;
309 ATOM atom = get_int_atom_value( class );
311 /* empty class is not the same as NULL class */
312 if (!atom && class && !class[0]) return NULL;
314 for (;;)
316 int count = 0;
318 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
320 SERVER_START_REQ( get_window_children )
322 req->desktop = wine_server_obj_handle( desktop );
323 req->parent = wine_server_user_handle( hwnd );
324 req->tid = tid;
325 req->atom = atom;
326 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
327 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
328 if (!wine_server_call( req )) count = reply->count;
330 SERVER_END_REQ;
331 if (count && count < size)
333 /* start from the end since HWND is potentially larger than user_handle_t */
334 for (i = count - 1; i >= 0; i--)
335 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
336 list[count] = 0;
337 return list;
339 HeapFree( GetProcessHeap(), 0, list );
340 if (!count) break;
341 size = count + 1; /* restart with a large enough buffer */
343 return NULL;
347 /*******************************************************************
348 * list_window_parents
350 * Build an array of all parents of a given window, starting with
351 * the immediate parent. The array must be freed with HeapFree.
353 static HWND *list_window_parents( HWND hwnd )
355 WND *win;
356 HWND current, *list;
357 int i, pos = 0, size = 16, count = 0;
359 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
361 current = hwnd;
362 for (;;)
364 if (!(win = WIN_GetPtr( current ))) goto empty;
365 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
366 if (win == WND_DESKTOP)
368 if (!pos) goto empty;
369 list[pos] = 0;
370 return list;
372 list[pos] = current = win->parent;
373 WIN_ReleasePtr( win );
374 if (!current) return list;
375 if (++pos == size - 1)
377 /* need to grow the list */
378 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
379 if (!new_list) goto empty;
380 list = new_list;
381 size += 16;
385 /* at least one parent belongs to another process, have to query the server */
387 for (;;)
389 count = 0;
390 SERVER_START_REQ( get_window_parents )
392 req->handle = wine_server_user_handle( hwnd );
393 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
394 if (!wine_server_call( req )) count = reply->count;
396 SERVER_END_REQ;
397 if (!count) goto empty;
398 if (size > count)
400 /* start from the end since HWND is potentially larger than user_handle_t */
401 for (i = count - 1; i >= 0; i--)
402 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
403 list[count] = 0;
404 return list;
406 HeapFree( GetProcessHeap(), 0, list );
407 size = count + 1;
408 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
411 empty:
412 HeapFree( GetProcessHeap(), 0, list );
413 return NULL;
417 /*******************************************************************
418 * send_parent_notify
420 static void send_parent_notify( HWND hwnd, UINT msg )
422 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
423 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
425 HWND parent = GetParent(hwnd);
426 if (parent && parent != GetDesktopWindow())
427 SendMessageW( parent, WM_PARENTNOTIFY,
428 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
433 /*******************************************************************
434 * get_server_window_text
436 * Retrieve the window text from the server.
438 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
440 size_t len = 0;
442 SERVER_START_REQ( get_window_text )
444 req->handle = wine_server_user_handle( hwnd );
445 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
446 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
448 SERVER_END_REQ;
449 text[len / sizeof(WCHAR)] = 0;
453 /*******************************************************************
454 * get_hwnd_message_parent
456 * Return the parent for HWND_MESSAGE windows.
458 HWND get_hwnd_message_parent(void)
460 struct user_thread_info *thread_info = get_user_thread_info();
462 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
463 return thread_info->msg_window;
467 /*******************************************************************
468 * is_desktop_window
470 * Check if window is the desktop or the HWND_MESSAGE top parent.
472 BOOL is_desktop_window( HWND hwnd )
474 struct user_thread_info *thread_info = get_user_thread_info();
476 if (!hwnd) return FALSE;
477 if (hwnd == thread_info->top_window) return TRUE;
478 if (hwnd == thread_info->msg_window) return TRUE;
480 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
482 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
483 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
485 return FALSE;
489 /*******************************************************************
490 * register_window_surface
492 * Register a window surface in the global list, possibly replacing another one.
494 void register_window_surface( struct window_surface *old, struct window_surface *new )
496 if (old == new) return;
497 EnterCriticalSection( &surfaces_section );
498 if (old) list_remove( &old->entry );
499 if (new) list_add_tail( &window_surfaces, &new->entry );
500 LeaveCriticalSection( &surfaces_section );
504 /*******************************************************************
505 * flush_window_surfaces
507 * Flush pending output from all window surfaces.
509 void flush_window_surfaces( BOOL idle )
511 static DWORD last_idle;
512 DWORD now;
513 struct window_surface *surface;
515 EnterCriticalSection( &surfaces_section );
516 now = GetTickCount();
517 if (idle) last_idle = now;
518 /* if not idle, we only flush if there's evidence that the app never goes idle */
519 else if ((int)(now - last_idle) < 1000) goto done;
521 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
522 surface->funcs->flush( surface );
523 done:
524 LeaveCriticalSection( &surfaces_section );
528 /***********************************************************************
529 * WIN_GetPtr
531 * Return a pointer to the WND structure if local to the process,
532 * or WND_OTHER_PROCESS if handle may be valid in other process.
533 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
535 WND *WIN_GetPtr( HWND hwnd )
537 WND *ptr;
539 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
541 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
543 return ptr;
547 /***********************************************************************
548 * WIN_IsCurrentProcess
550 * Check whether a given window belongs to the current process (and return the full handle).
552 HWND WIN_IsCurrentProcess( HWND hwnd )
554 WND *ptr;
555 HWND ret;
557 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
558 ret = ptr->obj.handle;
559 WIN_ReleasePtr( ptr );
560 return ret;
564 /***********************************************************************
565 * WIN_IsCurrentThread
567 * Check whether a given window belongs to the current thread (and return the full handle).
569 HWND WIN_IsCurrentThread( HWND hwnd )
571 WND *ptr;
572 HWND ret = 0;
574 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
575 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
576 WIN_ReleasePtr( ptr );
577 return ret;
581 /***********************************************************************
582 * WIN_GetFullHandle
584 * Convert a possibly truncated window handle to a full 32-bit handle.
586 HWND WIN_GetFullHandle( HWND hwnd )
588 WND *ptr;
590 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
591 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
592 /* do sign extension for -2 and -3 */
593 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
595 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
597 if (ptr == WND_DESKTOP)
599 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
600 else return get_hwnd_message_parent();
603 if (ptr != WND_OTHER_PROCESS)
605 hwnd = ptr->obj.handle;
606 WIN_ReleasePtr( ptr );
608 else /* may belong to another process */
610 SERVER_START_REQ( get_window_info )
612 req->handle = wine_server_user_handle( hwnd );
613 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
615 SERVER_END_REQ;
617 return hwnd;
621 /***********************************************************************
622 * WIN_SetOwner
624 * Change the owner of a window.
626 HWND WIN_SetOwner( HWND hwnd, HWND owner )
628 WND *win = WIN_GetPtr( hwnd );
629 HWND ret = 0;
631 if (!win || win == WND_DESKTOP) return 0;
632 if (win == WND_OTHER_PROCESS)
634 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
635 return 0;
637 SERVER_START_REQ( set_window_owner )
639 req->handle = wine_server_user_handle( hwnd );
640 req->owner = wine_server_user_handle( owner );
641 if (!wine_server_call( req ))
643 win->owner = wine_server_ptr_handle( reply->full_owner );
644 ret = wine_server_ptr_handle( reply->prev_owner );
647 SERVER_END_REQ;
648 WIN_ReleasePtr( win );
649 return ret;
653 /***********************************************************************
654 * WIN_SetStyle
656 * Change the style of a window.
658 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
660 BOOL ok, needs_show = FALSE;
661 STYLESTRUCT style;
662 WND *win = WIN_GetPtr( hwnd );
664 if (!win || win == WND_DESKTOP) return 0;
665 if (win == WND_OTHER_PROCESS)
667 if (IsWindow(hwnd))
668 ERR( "cannot set style %x/%x on other process window %p\n",
669 set_bits, clear_bits, hwnd );
670 return 0;
672 style.styleOld = win->dwStyle;
673 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
674 if (style.styleNew == style.styleOld)
676 WIN_ReleasePtr( win );
677 return style.styleNew;
679 SERVER_START_REQ( set_window_info )
681 req->handle = wine_server_user_handle( hwnd );
682 req->flags = SET_WIN_STYLE;
683 req->style = style.styleNew;
684 req->extra_offset = -1;
685 if ((ok = !wine_server_call( req )))
687 style.styleOld = reply->old_style;
688 win->dwStyle = style.styleNew;
691 SERVER_END_REQ;
693 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
695 /* Some apps try to make their window visible through WM_SETREDRAW.
696 * Only do that if the window was never explicitly hidden,
697 * because Steam messes with WM_SETREDRAW after hiding its windows. */
698 needs_show = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
699 invalidate_dce( win, NULL );
701 WIN_ReleasePtr( win );
703 if (!ok) return 0;
705 if (needs_show)
707 RECT window_rect, client_rect;
708 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
709 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
710 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
711 &window_rect, &client_rect, NULL );
714 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
715 return style.styleOld;
719 /***********************************************************************
720 * WIN_GetRectangles
722 * Get the window and client rectangles.
724 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
726 WND *win = WIN_GetPtr( hwnd );
727 BOOL ret = TRUE;
729 if (!win)
731 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
732 return FALSE;
734 if (win == WND_DESKTOP)
736 RECT rect;
737 rect.left = rect.top = 0;
738 if (hwnd == get_hwnd_message_parent())
740 rect.right = 100;
741 rect.bottom = 100;
743 else
745 rect.right = GetSystemMetrics(SM_CXSCREEN);
746 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
748 if (rectWindow) *rectWindow = rect;
749 if (rectClient) *rectClient = rect;
750 return TRUE;
752 if (win != WND_OTHER_PROCESS)
754 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
756 switch (relative)
758 case COORDS_CLIENT:
759 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
760 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
761 if (win->dwExStyle & WS_EX_LAYOUTRTL)
762 mirror_rect( &win->rectClient, &window_rect );
763 break;
764 case COORDS_WINDOW:
765 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
766 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
767 if (win->dwExStyle & WS_EX_LAYOUTRTL)
768 mirror_rect( &win->rectWindow, &client_rect );
769 break;
770 case COORDS_PARENT:
771 if (win->parent)
773 WND *parent = WIN_GetPtr( win->parent );
774 if (parent == WND_DESKTOP) break;
775 if (!parent || parent == WND_OTHER_PROCESS)
777 WIN_ReleasePtr( win );
778 goto other_process;
780 if (parent->flags & WIN_CHILDREN_MOVED)
782 WIN_ReleasePtr( parent );
783 WIN_ReleasePtr( win );
784 goto other_process;
786 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
788 mirror_rect( &parent->rectClient, &window_rect );
789 mirror_rect( &parent->rectClient, &client_rect );
791 WIN_ReleasePtr( parent );
793 break;
794 case COORDS_SCREEN:
795 while (win->parent)
797 WND *parent = WIN_GetPtr( win->parent );
798 if (parent == WND_DESKTOP) break;
799 if (!parent || parent == WND_OTHER_PROCESS)
801 WIN_ReleasePtr( win );
802 goto other_process;
804 WIN_ReleasePtr( win );
805 if (parent->flags & WIN_CHILDREN_MOVED)
807 WIN_ReleasePtr( parent );
808 goto other_process;
810 win = parent;
811 if (win->parent)
813 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
814 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
817 break;
819 if (rectWindow) *rectWindow = window_rect;
820 if (rectClient) *rectClient = client_rect;
821 WIN_ReleasePtr( win );
822 return TRUE;
825 other_process:
826 SERVER_START_REQ( get_window_rectangles )
828 req->handle = wine_server_user_handle( hwnd );
829 req->relative = relative;
830 if ((ret = !wine_server_call_err( req )))
832 if (rectWindow)
834 rectWindow->left = reply->window.left;
835 rectWindow->top = reply->window.top;
836 rectWindow->right = reply->window.right;
837 rectWindow->bottom = reply->window.bottom;
839 if (rectClient)
841 rectClient->left = reply->client.left;
842 rectClient->top = reply->client.top;
843 rectClient->right = reply->client.right;
844 rectClient->bottom = reply->client.bottom;
848 SERVER_END_REQ;
849 return ret;
853 /***********************************************************************
854 * WIN_DestroyWindow
856 * Destroy storage associated to a window. "Internals" p.358
858 LRESULT WIN_DestroyWindow( HWND hwnd )
860 WND *wndPtr;
861 HWND *list;
862 HMENU menu = 0, sys_menu;
863 HWND icon_title;
864 struct window_surface *surface;
866 TRACE("%p\n", hwnd );
868 /* free child windows */
869 if ((list = WIN_ListChildren( hwnd )))
871 int i;
872 for (i = 0; list[i]; i++)
874 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
875 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
877 HeapFree( GetProcessHeap(), 0, list );
880 /* Unlink now so we won't bother with the children later on */
881 SERVER_START_REQ( set_parent )
883 req->handle = wine_server_user_handle( hwnd );
884 req->parent = 0;
885 wine_server_call( req );
887 SERVER_END_REQ;
890 * Send the WM_NCDESTROY to the window being destroyed.
892 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
894 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
896 /* free resources associated with the window */
898 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
899 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
900 menu = (HMENU)wndPtr->wIDmenu;
901 sys_menu = wndPtr->hSysMenu;
902 free_dce( wndPtr->dce, hwnd );
903 wndPtr->dce = NULL;
904 icon_title = wndPtr->icon_title;
905 HeapFree( GetProcessHeap(), 0, wndPtr->text );
906 wndPtr->text = NULL;
907 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
908 wndPtr->pScroll = NULL;
909 surface = wndPtr->surface;
910 wndPtr->surface = NULL;
911 WIN_ReleasePtr( wndPtr );
913 if (icon_title) DestroyWindow( icon_title );
914 if (menu) DestroyMenu( menu );
915 if (sys_menu) DestroyMenu( sys_menu );
916 if (surface)
918 register_window_surface( surface, NULL );
919 window_surface_release( surface );
922 USER_Driver->pDestroyWindow( hwnd );
924 free_window_handle( hwnd );
925 return 0;
929 /***********************************************************************
930 * destroy_thread_window
932 * Destroy a window upon exit of its thread.
934 static void destroy_thread_window( HWND hwnd )
936 WND *wndPtr;
937 HWND *list;
938 HMENU menu = 0, sys_menu = 0;
939 struct window_surface *surface = NULL;
940 WORD index;
942 /* free child windows */
944 if ((list = WIN_ListChildren( hwnd )))
946 int i;
947 for (i = 0; list[i]; i++)
949 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
950 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
952 HeapFree( GetProcessHeap(), 0, list );
955 /* destroy the client-side storage */
957 index = USER_HANDLE_TO_INDEX(hwnd);
958 if (index >= NB_USER_HANDLES) return;
959 USER_Lock();
960 if ((wndPtr = user_handles[index]))
962 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
963 sys_menu = wndPtr->hSysMenu;
964 free_dce( wndPtr->dce, hwnd );
965 surface = wndPtr->surface;
966 wndPtr->surface = NULL;
967 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
969 USER_Unlock();
971 HeapFree( GetProcessHeap(), 0, wndPtr );
972 if (menu) DestroyMenu( menu );
973 if (sys_menu) DestroyMenu( sys_menu );
974 if (surface)
976 register_window_surface( surface, NULL );
977 window_surface_release( surface );
982 /***********************************************************************
983 * destroy_thread_child_windows
985 * Destroy child windows upon exit of its thread.
987 static void destroy_thread_child_windows( HWND hwnd )
989 HWND *list;
990 int i;
992 if (WIN_IsCurrentThread( hwnd ))
994 destroy_thread_window( hwnd );
996 else if ((list = WIN_ListChildren( hwnd )))
998 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
999 HeapFree( GetProcessHeap(), 0, list );
1004 /***********************************************************************
1005 * WIN_DestroyThreadWindows
1007 * Destroy all children of 'wnd' owned by the current thread.
1009 void WIN_DestroyThreadWindows( HWND hwnd )
1011 HWND *list;
1012 int i;
1014 if (!(list = WIN_ListChildren( hwnd ))) return;
1016 /* reset owners of top-level windows */
1017 for (i = 0; list[i]; i++)
1019 if (!WIN_IsCurrentThread( list[i] ))
1021 HWND owner = GetWindow( list[i], GW_OWNER );
1022 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1026 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1027 HeapFree( GetProcessHeap(), 0, list );
1031 /***********************************************************************
1032 * WIN_FixCoordinates
1034 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1035 * returns default show mode in sw.
1037 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1039 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1040 POINT pos[2];
1042 if (cs->dwExStyle & WS_EX_MDICHILD)
1044 UINT id = 0;
1046 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1047 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1049 TRACE("MDI child id %04x\n", id);
1052 if (cs->style & (WS_CHILD | WS_POPUP))
1054 if (cs->dwExStyle & WS_EX_MDICHILD)
1056 if (IS_DEFAULT(cs->x))
1058 cs->x = pos[0].x;
1059 cs->y = pos[0].y;
1061 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1062 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1064 else
1066 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1067 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1070 else /* overlapped window */
1072 HMONITOR monitor;
1073 MONITORINFO mon_info;
1074 STARTUPINFOW info;
1076 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1078 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1079 mon_info.cbSize = sizeof(mon_info);
1080 GetMonitorInfoW( monitor, &mon_info );
1081 GetStartupInfoW( &info );
1083 if (IS_DEFAULT(cs->x))
1085 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1086 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1087 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1090 if (IS_DEFAULT(cs->cx))
1092 if (info.dwFlags & STARTF_USESIZE)
1094 cs->cx = info.dwXSize;
1095 cs->cy = info.dwYSize;
1097 else
1099 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1100 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1103 /* neither x nor cx are default. Check the y values .
1104 * In the trace we see Outlook and Outlook Express using
1105 * cy set to CW_USEDEFAULT when opening the address book.
1107 else if (IS_DEFAULT(cs->cy))
1109 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1110 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1113 #undef IS_DEFAULT
1116 /***********************************************************************
1117 * dump_window_styles
1119 static void dump_window_styles( DWORD style, DWORD exstyle )
1121 TRACE( "style:" );
1122 if(style & WS_POPUP) TRACE(" WS_POPUP");
1123 if(style & WS_CHILD) TRACE(" WS_CHILD");
1124 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1125 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1126 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1127 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1128 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1129 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1130 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1131 else
1133 if(style & WS_BORDER) TRACE(" WS_BORDER");
1134 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1136 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1137 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1138 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1139 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1140 if (style & WS_CHILD)
1142 if(style & WS_GROUP) TRACE(" WS_GROUP");
1143 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1145 else
1147 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1148 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1151 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1152 #define DUMPED_STYLES \
1153 ((DWORD)(WS_POPUP | \
1154 WS_CHILD | \
1155 WS_MINIMIZE | \
1156 WS_VISIBLE | \
1157 WS_DISABLED | \
1158 WS_CLIPSIBLINGS | \
1159 WS_CLIPCHILDREN | \
1160 WS_MAXIMIZE | \
1161 WS_BORDER | \
1162 WS_DLGFRAME | \
1163 WS_VSCROLL | \
1164 WS_HSCROLL | \
1165 WS_SYSMENU | \
1166 WS_THICKFRAME | \
1167 WS_GROUP | \
1168 WS_TABSTOP | \
1169 WS_MINIMIZEBOX | \
1170 WS_MAXIMIZEBOX))
1172 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1173 TRACE("\n");
1174 #undef DUMPED_STYLES
1176 TRACE( "exstyle:" );
1177 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1178 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1179 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1180 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1181 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1182 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1183 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1184 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1185 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1186 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1187 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1188 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1189 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1190 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1191 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1192 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1193 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1194 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1195 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1197 #define DUMPED_EX_STYLES \
1198 ((DWORD)(WS_EX_DLGMODALFRAME | \
1199 WS_EX_DRAGDETECT | \
1200 WS_EX_NOPARENTNOTIFY | \
1201 WS_EX_TOPMOST | \
1202 WS_EX_ACCEPTFILES | \
1203 WS_EX_TRANSPARENT | \
1204 WS_EX_MDICHILD | \
1205 WS_EX_TOOLWINDOW | \
1206 WS_EX_WINDOWEDGE | \
1207 WS_EX_CLIENTEDGE | \
1208 WS_EX_CONTEXTHELP | \
1209 WS_EX_RIGHT | \
1210 WS_EX_RTLREADING | \
1211 WS_EX_LEFTSCROLLBAR | \
1212 WS_EX_CONTROLPARENT | \
1213 WS_EX_STATICEDGE | \
1214 WS_EX_APPWINDOW | \
1215 WS_EX_LAYERED | \
1216 WS_EX_LAYOUTRTL))
1218 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1219 TRACE("\n");
1220 #undef DUMPED_EX_STYLES
1224 /***********************************************************************
1225 * WIN_CreateWindowEx
1227 * Implementation of CreateWindowEx().
1229 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1231 INT cx, cy, style, sw = SW_SHOW;
1232 LRESULT result;
1233 RECT rect;
1234 WND *wndPtr;
1235 HWND hwnd, parent, owner, top_child = 0;
1236 MDICREATESTRUCTW mdi_cs;
1237 CBT_CREATEWNDW cbtc;
1238 CREATESTRUCTW cbcs;
1240 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1241 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1242 debugstr_w(className),
1243 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1244 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1245 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1247 /* Fix the styles for MDI children */
1248 if (cs->dwExStyle & WS_EX_MDICHILD)
1250 UINT flags = 0;
1252 wndPtr = WIN_GetPtr(cs->hwndParent);
1253 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1255 flags = wndPtr->flags;
1256 WIN_ReleasePtr(wndPtr);
1259 if (!(flags & WIN_ISMDICLIENT))
1261 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1262 return 0;
1265 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1266 * MDICREATESTRUCT members have the originally passed values.
1268 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1269 * have the same layout.
1271 mdi_cs.szClass = cs->lpszClass;
1272 mdi_cs.szTitle = cs->lpszName;
1273 mdi_cs.hOwner = cs->hInstance;
1274 mdi_cs.x = cs->x;
1275 mdi_cs.y = cs->y;
1276 mdi_cs.cx = cs->cx;
1277 mdi_cs.cy = cs->cy;
1278 mdi_cs.style = cs->style;
1279 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1281 cs->lpCreateParams = &mdi_cs;
1283 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1285 if (cs->style & WS_POPUP)
1287 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1288 return 0;
1290 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1292 else
1294 cs->style &= ~WS_POPUP;
1295 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1296 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1299 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1301 if (top_child)
1303 /* Restore current maximized child */
1304 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1306 TRACE("Restoring current maximized child %p\n", top_child);
1307 if (cs->style & WS_MAXIMIZE)
1309 /* if the new window is maximized don't bother repainting */
1310 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1311 ShowWindow( top_child, SW_SHOWNORMAL );
1312 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1314 else ShowWindow( top_child, SW_SHOWNORMAL );
1319 /* Find the parent window */
1321 parent = cs->hwndParent;
1322 owner = 0;
1324 if (cs->hwndParent == HWND_MESSAGE)
1326 cs->hwndParent = parent = get_hwnd_message_parent();
1328 else if (cs->hwndParent)
1330 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1332 parent = GetDesktopWindow();
1333 owner = cs->hwndParent;
1335 else
1337 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1338 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1339 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1342 else
1344 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1346 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1348 WARN("No parent for child window\n" );
1349 SetLastError(ERROR_TLW_WITH_WSCHILD);
1350 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1352 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1353 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1354 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1356 DWORD layout;
1357 GetProcessDefaultLayout( &layout );
1358 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1359 parent = GetDesktopWindow();
1363 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1365 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1366 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1367 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1368 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1369 else
1370 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1372 /* Create the window structure */
1374 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1375 return 0;
1376 hwnd = wndPtr->obj.handle;
1378 /* Fill the window structure */
1380 wndPtr->tid = GetCurrentThreadId();
1381 wndPtr->hInstance = cs->hInstance;
1382 wndPtr->text = NULL;
1383 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1384 wndPtr->dwExStyle = cs->dwExStyle;
1385 wndPtr->wIDmenu = 0;
1386 wndPtr->helpContext = 0;
1387 wndPtr->pScroll = NULL;
1388 wndPtr->userdata = 0;
1389 wndPtr->hIcon = 0;
1390 wndPtr->hIconSmall = 0;
1391 wndPtr->hSysMenu = 0;
1393 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1394 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1396 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1399 * Correct the window styles.
1401 * It affects only the style loaded into the WIN structure.
1404 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1406 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1407 if (!(wndPtr->dwStyle & WS_POPUP))
1408 wndPtr->dwStyle |= WS_CAPTION;
1411 /* WS_EX_WINDOWEDGE depends on some other styles */
1412 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1413 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1414 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1416 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1417 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1418 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1420 else
1421 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1423 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1424 wndPtr->flags |= WIN_NEED_SIZE;
1426 SERVER_START_REQ( set_window_info )
1428 req->handle = wine_server_user_handle( hwnd );
1429 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1430 req->style = wndPtr->dwStyle;
1431 req->ex_style = wndPtr->dwExStyle;
1432 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1433 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1434 req->extra_offset = -1;
1435 wine_server_call( req );
1437 SERVER_END_REQ;
1439 /* Set the window menu */
1441 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1443 if (cs->hMenu)
1445 if (!MENU_SetMenu(hwnd, cs->hMenu))
1447 WIN_ReleasePtr( wndPtr );
1448 free_window_handle( hwnd );
1449 return 0;
1452 else
1454 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1455 if (menuName)
1457 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1458 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1462 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1464 /* call the WH_CBT hook */
1466 /* the window style passed to the hook must be the real window style,
1467 * rather than just the window style that the caller to CreateWindowEx
1468 * passed in, so we have to copy the original CREATESTRUCT and get the
1469 * the real style. */
1470 cbcs = *cs;
1471 cbcs.style = wndPtr->dwStyle;
1472 cbtc.lpcs = &cbcs;
1473 cbtc.hwndInsertAfter = HWND_TOP;
1474 WIN_ReleasePtr( wndPtr );
1475 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1477 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1479 cx = cs->cx;
1480 cy = cs->cy;
1481 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1483 POINT maxSize, maxPos, minTrack, maxTrack;
1484 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1485 if (maxTrack.x < cx) cx = maxTrack.x;
1486 if (maxTrack.y < cy) cy = maxTrack.y;
1487 if (minTrack.x > cx) cx = minTrack.x;
1488 if (minTrack.y > cy) cy = minTrack.y;
1491 if (cx < 0) cx = 0;
1492 if (cy < 0) cy = 0;
1493 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1494 /* check for wraparound */
1495 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1496 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1497 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1499 /* send WM_NCCREATE */
1501 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1502 if (unicode)
1503 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1504 else
1505 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1506 if (!result)
1508 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1509 goto failed;
1512 /* send WM_NCCALCSIZE */
1514 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1516 /* yes, even if the CBT hook was called with HWND_TOP */
1517 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1518 RECT client_rect = rect;
1520 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1521 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1522 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1523 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1524 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1526 else return 0;
1528 /* send WM_CREATE */
1530 if (unicode)
1531 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1532 else
1533 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1534 if (result == -1) goto failed;
1536 /* call the driver */
1538 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1540 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1542 /* send the size messages */
1544 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1545 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1546 if (!(wndPtr->flags & WIN_NEED_SIZE))
1548 WIN_ReleasePtr( wndPtr );
1549 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1550 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1551 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1552 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1554 else WIN_ReleasePtr( wndPtr );
1556 /* Show the window, maximizing or minimizing if needed */
1558 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1559 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1561 RECT newPos;
1562 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1564 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1565 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1566 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1567 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1568 newPos.bottom - newPos.top, swFlag );
1571 /* Notify the parent window only */
1573 send_parent_notify( hwnd, WM_CREATE );
1574 if (!IsWindow( hwnd )) return 0;
1576 if (cs->style & WS_VISIBLE)
1578 if (cs->style & WS_MAXIMIZE)
1579 sw = SW_SHOW;
1580 else if (cs->style & WS_MINIMIZE)
1581 sw = SW_SHOWMINIMIZED;
1583 ShowWindow( hwnd, sw );
1584 if (cs->dwExStyle & WS_EX_MDICHILD)
1586 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1587 /* ShowWindow won't activate child windows */
1588 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1592 /* Call WH_SHELL hook */
1594 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1595 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1597 TRACE("created window %p\n", hwnd);
1598 return hwnd;
1600 failed:
1601 WIN_DestroyWindow( hwnd );
1602 return 0;
1606 /***********************************************************************
1607 * CreateWindowExA (USER32.@)
1609 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1610 LPCSTR windowName, DWORD style, INT x,
1611 INT y, INT width, INT height,
1612 HWND parent, HMENU menu,
1613 HINSTANCE instance, LPVOID data )
1615 CREATESTRUCTA cs;
1617 cs.lpCreateParams = data;
1618 cs.hInstance = instance;
1619 cs.hMenu = menu;
1620 cs.hwndParent = parent;
1621 cs.x = x;
1622 cs.y = y;
1623 cs.cx = width;
1624 cs.cy = height;
1625 cs.style = style;
1626 cs.lpszName = windowName;
1627 cs.lpszClass = className;
1628 cs.dwExStyle = exStyle;
1630 if (!IS_INTRESOURCE(className))
1632 WCHAR bufferW[256];
1633 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1634 return 0;
1635 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1637 /* Note: we rely on the fact that CREATESTRUCTA and */
1638 /* CREATESTRUCTW have the same layout. */
1639 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1643 /***********************************************************************
1644 * CreateWindowExW (USER32.@)
1646 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1647 LPCWSTR windowName, DWORD style, INT x,
1648 INT y, INT width, INT height,
1649 HWND parent, HMENU menu,
1650 HINSTANCE instance, LPVOID data )
1652 CREATESTRUCTW cs;
1654 cs.lpCreateParams = data;
1655 cs.hInstance = instance;
1656 cs.hMenu = menu;
1657 cs.hwndParent = parent;
1658 cs.x = x;
1659 cs.y = y;
1660 cs.cx = width;
1661 cs.cy = height;
1662 cs.style = style;
1663 cs.lpszName = windowName;
1664 cs.lpszClass = className;
1665 cs.dwExStyle = exStyle;
1667 return wow_handlers.create_window( &cs, className, instance, TRUE );
1671 /***********************************************************************
1672 * WIN_SendDestroyMsg
1674 static void WIN_SendDestroyMsg( HWND hwnd )
1676 GUITHREADINFO info;
1678 info.cbSize = sizeof(info);
1679 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1681 if (hwnd == info.hwndCaret) DestroyCaret();
1682 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1686 * Send the WM_DESTROY to the window.
1688 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1691 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1692 * make sure that the window still exists when we come back.
1694 if (IsWindow(hwnd))
1696 HWND* pWndArray;
1697 int i;
1699 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1701 for (i = 0; pWndArray[i]; i++)
1703 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1705 HeapFree( GetProcessHeap(), 0, pWndArray );
1707 else
1708 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1712 /***********************************************************************
1713 * DestroyWindow (USER32.@)
1715 BOOL WINAPI DestroyWindow( HWND hwnd )
1717 BOOL is_child;
1719 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1721 SetLastError( ERROR_ACCESS_DENIED );
1722 return FALSE;
1725 TRACE("(%p)\n", hwnd);
1727 /* Call hooks */
1729 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1731 if (MENU_IsMenuActive() == hwnd)
1732 EndMenu();
1734 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1736 if (is_child)
1738 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1739 send_parent_notify( hwnd, WM_DESTROY );
1741 else if (!GetWindow( hwnd, GW_OWNER ))
1743 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1744 /* FIXME: clean up palette - see "Internals" p.352 */
1747 if (!IsWindow(hwnd)) return TRUE;
1749 /* Hide the window */
1750 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1752 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1753 if (is_child)
1754 ShowWindow( hwnd, SW_HIDE );
1755 else
1756 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1757 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1760 if (!IsWindow(hwnd)) return TRUE;
1762 /* Recursively destroy owned windows */
1764 if (!is_child)
1766 for (;;)
1768 int i, got_one = 0;
1769 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1770 if (list)
1772 for (i = 0; list[i]; i++)
1774 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1775 if (WIN_IsCurrentThread( list[i] ))
1777 DestroyWindow( list[i] );
1778 got_one = 1;
1779 continue;
1781 WIN_SetOwner( list[i], 0 );
1783 HeapFree( GetProcessHeap(), 0, list );
1785 if (!got_one) break;
1789 /* Send destroy messages */
1791 WIN_SendDestroyMsg( hwnd );
1792 if (!IsWindow( hwnd )) return TRUE;
1794 if (GetClipboardOwner() == hwnd)
1795 CLIPBOARD_ReleaseOwner();
1797 /* Destroy the window storage */
1799 WIN_DestroyWindow( hwnd );
1800 return TRUE;
1804 /***********************************************************************
1805 * CloseWindow (USER32.@)
1807 BOOL WINAPI CloseWindow( HWND hwnd )
1809 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1810 ShowWindow( hwnd, SW_MINIMIZE );
1811 return TRUE;
1815 /***********************************************************************
1816 * OpenIcon (USER32.@)
1818 BOOL WINAPI OpenIcon( HWND hwnd )
1820 if (!IsIconic( hwnd )) return FALSE;
1821 ShowWindow( hwnd, SW_SHOWNORMAL );
1822 return TRUE;
1826 /***********************************************************************
1827 * FindWindowExW (USER32.@)
1829 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1831 HWND *list = NULL;
1832 HWND retvalue = 0;
1833 int i = 0, len = 0;
1834 WCHAR *buffer = NULL;
1836 if (!parent && child) parent = GetDesktopWindow();
1837 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1839 if (title)
1841 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1842 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1845 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1847 if (child)
1849 child = WIN_GetFullHandle( child );
1850 while (list[i] && list[i] != child) i++;
1851 if (!list[i]) goto done;
1852 i++; /* start from next window */
1855 if (title)
1857 while (list[i])
1859 if (GetWindowTextW( list[i], buffer, len + 1 ))
1861 if (!strcmpiW( buffer, title )) break;
1863 else
1865 if (!title[0]) break;
1867 i++;
1870 retvalue = list[i];
1872 done:
1873 HeapFree( GetProcessHeap(), 0, list );
1874 HeapFree( GetProcessHeap(), 0, buffer );
1875 return retvalue;
1880 /***********************************************************************
1881 * FindWindowA (USER32.@)
1883 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1885 HWND ret = FindWindowExA( 0, 0, className, title );
1886 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1887 return ret;
1891 /***********************************************************************
1892 * FindWindowExA (USER32.@)
1894 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1896 LPWSTR titleW = NULL;
1897 HWND hwnd = 0;
1899 if (title)
1901 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1902 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1903 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1906 if (!IS_INTRESOURCE(className))
1908 WCHAR classW[256];
1909 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1910 hwnd = FindWindowExW( parent, child, classW, titleW );
1912 else
1914 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1917 HeapFree( GetProcessHeap(), 0, titleW );
1918 return hwnd;
1922 /***********************************************************************
1923 * FindWindowW (USER32.@)
1925 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1927 return FindWindowExW( 0, 0, className, title );
1931 /**********************************************************************
1932 * GetDesktopWindow (USER32.@)
1934 HWND WINAPI GetDesktopWindow(void)
1936 struct user_thread_info *thread_info = get_user_thread_info();
1938 if (thread_info->top_window) return thread_info->top_window;
1940 SERVER_START_REQ( get_desktop_window )
1942 req->force = 0;
1943 if (!wine_server_call( req ))
1945 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1946 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1949 SERVER_END_REQ;
1951 if (!thread_info->top_window)
1953 USEROBJECTFLAGS flags;
1954 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1955 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1957 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1958 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1959 STARTUPINFOW si;
1960 PROCESS_INFORMATION pi;
1961 WCHAR windir[MAX_PATH];
1962 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1963 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1964 void *redir;
1966 memset( &si, 0, sizeof(si) );
1967 si.cb = sizeof(si);
1968 si.dwFlags = STARTF_USESTDHANDLES;
1969 si.hStdInput = 0;
1970 si.hStdOutput = 0;
1971 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1973 GetSystemDirectoryW( windir, MAX_PATH );
1974 strcpyW( app, windir );
1975 strcatW( app, explorer );
1976 strcpyW( cmdline, app );
1977 strcatW( cmdline, args );
1979 Wow64DisableWow64FsRedirection( &redir );
1980 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1981 NULL, windir, &si, &pi ))
1983 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1984 WaitForInputIdle( pi.hProcess, 10000 );
1985 CloseHandle( pi.hThread );
1986 CloseHandle( pi.hProcess );
1988 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1989 Wow64RevertWow64FsRedirection( redir );
1991 else TRACE( "not starting explorer since winstation is not visible\n" );
1993 SERVER_START_REQ( get_desktop_window )
1995 req->force = 1;
1996 if (!wine_server_call( req ))
1998 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1999 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2002 SERVER_END_REQ;
2005 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2006 ERR( "failed to create desktop window\n" );
2008 return thread_info->top_window;
2012 /*******************************************************************
2013 * EnableWindow (USER32.@)
2015 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2017 BOOL retvalue;
2018 HWND full_handle;
2020 if (is_broadcast(hwnd))
2022 SetLastError( ERROR_INVALID_PARAMETER );
2023 return FALSE;
2026 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2027 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2029 hwnd = full_handle;
2031 TRACE("( %p, %d )\n", hwnd, enable);
2033 retvalue = !IsWindowEnabled( hwnd );
2035 if (enable && retvalue)
2037 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2038 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2040 else if (!enable && !retvalue)
2042 HWND capture_wnd;
2044 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2046 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2048 if (hwnd == GetFocus())
2049 SetFocus( 0 ); /* A disabled window can't have the focus */
2051 capture_wnd = GetCapture();
2052 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2053 ReleaseCapture(); /* A disabled window can't capture the mouse */
2055 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2057 return retvalue;
2061 /***********************************************************************
2062 * IsWindowEnabled (USER32.@)
2064 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2066 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2070 /***********************************************************************
2071 * IsWindowUnicode (USER32.@)
2073 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2075 WND * wndPtr;
2076 BOOL retvalue = FALSE;
2078 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2080 if (wndPtr == WND_DESKTOP) return TRUE;
2082 if (wndPtr != WND_OTHER_PROCESS)
2084 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2085 WIN_ReleasePtr( wndPtr );
2087 else
2089 SERVER_START_REQ( get_window_info )
2091 req->handle = wine_server_user_handle( hwnd );
2092 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2094 SERVER_END_REQ;
2096 return retvalue;
2100 /**********************************************************************
2101 * WIN_GetWindowLong
2103 * Helper function for GetWindowLong().
2105 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2107 LONG_PTR retvalue = 0;
2108 WND *wndPtr;
2110 if (offset == GWLP_HWNDPARENT)
2112 HWND parent = GetAncestor( hwnd, GA_PARENT );
2113 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2114 return (ULONG_PTR)parent;
2117 if (!(wndPtr = WIN_GetPtr( hwnd )))
2119 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2120 return 0;
2123 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2125 if (offset == GWLP_WNDPROC)
2127 SetLastError( ERROR_ACCESS_DENIED );
2128 return 0;
2130 SERVER_START_REQ( set_window_info )
2132 req->handle = wine_server_user_handle( hwnd );
2133 req->flags = 0; /* don't set anything, just retrieve */
2134 req->extra_offset = (offset >= 0) ? offset : -1;
2135 req->extra_size = (offset >= 0) ? size : 0;
2136 if (!wine_server_call_err( req ))
2138 switch(offset)
2140 case GWL_STYLE: retvalue = reply->old_style; break;
2141 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2142 case GWLP_ID: retvalue = reply->old_id; break;
2143 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2144 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2145 default:
2146 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2147 else SetLastError( ERROR_INVALID_INDEX );
2148 break;
2152 SERVER_END_REQ;
2153 return retvalue;
2156 /* now we have a valid wndPtr */
2158 if (offset >= 0)
2160 if (offset > (int)(wndPtr->cbWndExtra - size))
2162 WARN("Invalid offset %d\n", offset );
2163 WIN_ReleasePtr( wndPtr );
2164 SetLastError( ERROR_INVALID_INDEX );
2165 return 0;
2167 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2169 /* Special case for dialog window procedure */
2170 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2171 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2172 WIN_ReleasePtr( wndPtr );
2173 return retvalue;
2176 switch(offset)
2178 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2179 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2180 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2181 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2182 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2183 case GWLP_WNDPROC:
2184 /* This looks like a hack only for the edit control (see tests). This makes these controls
2185 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2186 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2188 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2189 retvalue = (ULONG_PTR)wndPtr->winproc;
2190 else
2191 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2192 break;
2193 default:
2194 WARN("Unknown offset %d\n", offset );
2195 SetLastError( ERROR_INVALID_INDEX );
2196 break;
2198 WIN_ReleasePtr(wndPtr);
2199 return retvalue;
2203 /**********************************************************************
2204 * WIN_SetWindowLong
2206 * Helper function for SetWindowLong().
2208 * 0 is the failure code. However, in the case of failure SetLastError
2209 * must be set to distinguish between a 0 return value and a failure.
2211 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2213 STYLESTRUCT style;
2214 BOOL ok, needs_show = FALSE;
2215 LONG_PTR retval = 0;
2216 WND *wndPtr;
2218 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2220 if (is_broadcast(hwnd))
2222 SetLastError( ERROR_INVALID_PARAMETER );
2223 return FALSE;
2226 if (!(wndPtr = WIN_GetPtr( hwnd )))
2228 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2229 return 0;
2231 if (wndPtr == WND_DESKTOP)
2233 /* can't change anything on the desktop window */
2234 SetLastError( ERROR_ACCESS_DENIED );
2235 return 0;
2237 if (wndPtr == WND_OTHER_PROCESS)
2239 if (offset == GWLP_WNDPROC)
2241 SetLastError( ERROR_ACCESS_DENIED );
2242 return 0;
2244 if (offset > 32767 || offset < -32767)
2246 SetLastError( ERROR_INVALID_INDEX );
2247 return 0;
2249 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2252 /* first some special cases */
2253 switch( offset )
2255 case GWL_STYLE:
2256 style.styleOld = wndPtr->dwStyle;
2257 style.styleNew = newval;
2258 WIN_ReleasePtr( wndPtr );
2259 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2260 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2261 newval = style.styleNew;
2262 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2263 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2264 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2265 WS_EX_WINDOWEDGE too */
2266 break;
2267 case GWL_EXSTYLE:
2268 style.styleOld = wndPtr->dwExStyle;
2269 style.styleNew = newval;
2270 WIN_ReleasePtr( wndPtr );
2271 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2272 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2273 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2274 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2275 /* WS_EX_WINDOWEDGE depends on some other styles */
2276 if (newval & WS_EX_DLGMODALFRAME)
2277 newval |= WS_EX_WINDOWEDGE;
2278 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2279 newval |= WS_EX_WINDOWEDGE;
2280 else
2281 newval &= ~WS_EX_WINDOWEDGE;
2282 break;
2283 case GWLP_HWNDPARENT:
2284 if (wndPtr->parent == GetDesktopWindow())
2286 WIN_ReleasePtr( wndPtr );
2287 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2289 else
2291 WIN_ReleasePtr( wndPtr );
2292 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2294 case GWLP_WNDPROC:
2296 WNDPROC proc;
2297 UINT old_flags = wndPtr->flags;
2298 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2299 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2300 if (proc) wndPtr->winproc = proc;
2301 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2302 else wndPtr->flags &= ~WIN_ISUNICODE;
2303 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2305 WIN_ReleasePtr( wndPtr );
2306 return retval;
2308 /* update is_unicode flag on the server side */
2309 break;
2311 case GWLP_ID:
2312 case GWLP_HINSTANCE:
2313 case GWLP_USERDATA:
2314 break;
2315 case DWLP_DLGPROC:
2316 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2317 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2319 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2320 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2321 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2322 WIN_ReleasePtr( wndPtr );
2323 return retval;
2325 /* fall through */
2326 default:
2327 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2329 WARN("Invalid offset %d\n", offset );
2330 WIN_ReleasePtr( wndPtr );
2331 SetLastError( ERROR_INVALID_INDEX );
2332 return 0;
2334 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2336 /* already set to the same value */
2337 WIN_ReleasePtr( wndPtr );
2338 return newval;
2340 break;
2343 SERVER_START_REQ( set_window_info )
2345 req->handle = wine_server_user_handle( hwnd );
2346 req->extra_offset = -1;
2347 switch(offset)
2349 case GWL_STYLE:
2350 req->flags = SET_WIN_STYLE;
2351 req->style = newval;
2352 break;
2353 case GWL_EXSTYLE:
2354 req->flags = SET_WIN_EXSTYLE;
2355 req->ex_style = newval;
2356 break;
2357 case GWLP_ID:
2358 req->flags = SET_WIN_ID;
2359 req->id = newval;
2360 break;
2361 case GWLP_HINSTANCE:
2362 req->flags = SET_WIN_INSTANCE;
2363 req->instance = wine_server_client_ptr( (void *)newval );
2364 break;
2365 case GWLP_WNDPROC:
2366 req->flags = SET_WIN_UNICODE;
2367 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2368 break;
2369 case GWLP_USERDATA:
2370 req->flags = SET_WIN_USERDATA;
2371 req->user_data = newval;
2372 break;
2373 default:
2374 req->flags = SET_WIN_EXTRA;
2375 req->extra_offset = offset;
2376 req->extra_size = size;
2377 set_win_data( &req->extra_value, newval, size );
2379 if ((ok = !wine_server_call_err( req )))
2381 switch(offset)
2383 case GWL_STYLE:
2384 wndPtr->dwStyle = newval;
2385 retval = reply->old_style;
2386 break;
2387 case GWL_EXSTYLE:
2388 wndPtr->dwExStyle = newval;
2389 retval = reply->old_ex_style;
2390 break;
2391 case GWLP_ID:
2392 wndPtr->wIDmenu = newval;
2393 retval = reply->old_id;
2394 break;
2395 case GWLP_HINSTANCE:
2396 wndPtr->hInstance = (HINSTANCE)newval;
2397 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2398 break;
2399 case GWLP_WNDPROC:
2400 break;
2401 case GWLP_USERDATA:
2402 wndPtr->userdata = newval;
2403 retval = reply->old_user_data;
2404 break;
2405 default:
2406 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2407 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2408 break;
2412 SERVER_END_REQ;
2414 if (offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
2416 needs_show = !(wndPtr->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
2417 invalidate_dce( wndPtr, NULL );
2419 WIN_ReleasePtr( wndPtr );
2421 if (!ok) return 0;
2423 if (needs_show)
2425 RECT window_rect, client_rect;
2426 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
2427 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
2428 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW,
2429 &window_rect, &client_rect, NULL );
2431 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2433 style.styleOld = retval;
2434 style.styleNew = newval;
2435 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2436 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2439 return retval;
2443 /**********************************************************************
2444 * GetWindowWord (USER32.@)
2446 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2448 switch(offset)
2450 case GWLP_ID:
2451 case GWLP_HINSTANCE:
2452 case GWLP_HWNDPARENT:
2453 break;
2454 default:
2455 if (offset < 0)
2457 WARN("Invalid offset %d\n", offset );
2458 SetLastError( ERROR_INVALID_INDEX );
2459 return 0;
2461 break;
2463 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2467 /**********************************************************************
2468 * GetWindowLongA (USER32.@)
2470 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2472 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2476 /**********************************************************************
2477 * GetWindowLongW (USER32.@)
2479 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2481 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2485 /**********************************************************************
2486 * SetWindowWord (USER32.@)
2488 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2490 switch(offset)
2492 case GWLP_ID:
2493 case GWLP_HINSTANCE:
2494 case GWLP_HWNDPARENT:
2495 break;
2496 default:
2497 if (offset < 0)
2499 WARN("Invalid offset %d\n", offset );
2500 SetLastError( ERROR_INVALID_INDEX );
2501 return 0;
2503 break;
2505 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2509 /**********************************************************************
2510 * SetWindowLongA (USER32.@)
2512 * See SetWindowLongW.
2514 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2516 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2520 /**********************************************************************
2521 * SetWindowLongW (USER32.@) Set window attribute
2523 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2524 * value in a window's extra memory.
2526 * The _hwnd_ parameter specifies the window. is the handle to a
2527 * window that has extra memory. The _newval_ parameter contains the
2528 * new attribute or extra memory value. If positive, the _offset_
2529 * parameter is the byte-addressed location in the window's extra
2530 * memory to set. If negative, _offset_ specifies the window
2531 * attribute to set, and should be one of the following values:
2533 * GWL_EXSTYLE The window's extended window style
2535 * GWL_STYLE The window's window style.
2537 * GWLP_WNDPROC Pointer to the window's window procedure.
2539 * GWLP_HINSTANCE The window's pplication instance handle.
2541 * GWLP_ID The window's identifier.
2543 * GWLP_USERDATA The window's user-specified data.
2545 * If the window is a dialog box, the _offset_ parameter can be one of
2546 * the following values:
2548 * DWLP_DLGPROC The address of the window's dialog box procedure.
2550 * DWLP_MSGRESULT The return value of a message
2551 * that the dialog box procedure processed.
2553 * DWLP_USER Application specific information.
2555 * RETURNS
2557 * If successful, returns the previous value located at _offset_. Otherwise,
2558 * returns 0.
2560 * NOTES
2562 * Extra memory for a window class is specified by a nonzero cbWndExtra
2563 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2564 * time of class creation.
2566 * Using GWL_WNDPROC to set a new window procedure effectively creates
2567 * a window subclass. Use CallWindowProc() in the new windows procedure
2568 * to pass messages to the superclass's window procedure.
2570 * The user data is reserved for use by the application which created
2571 * the window.
2573 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2574 * instead, call the EnableWindow() function to change the window's
2575 * disabled state.
2577 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2578 * SetParent() instead.
2580 * Win95:
2581 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2582 * it sends WM_STYLECHANGING before changing the settings
2583 * and WM_STYLECHANGED afterwards.
2584 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2586 LONG WINAPI SetWindowLongW(
2587 HWND hwnd, /* [in] window to alter */
2588 INT offset, /* [in] offset, in bytes, of location to alter */
2589 LONG newval /* [in] new value of location */
2591 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2595 /*******************************************************************
2596 * GetWindowTextA (USER32.@)
2598 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2600 WCHAR *buffer;
2602 if (!lpString) return 0;
2604 if (WIN_IsCurrentProcess( hwnd ))
2605 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2607 /* when window belongs to other process, don't send a message */
2608 if (nMaxCount <= 0) return 0;
2609 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2610 get_server_window_text( hwnd, buffer, nMaxCount );
2611 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2612 lpString[nMaxCount-1] = 0;
2613 HeapFree( GetProcessHeap(), 0, buffer );
2614 return strlen(lpString);
2618 /*******************************************************************
2619 * InternalGetWindowText (USER32.@)
2621 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2623 WND *win;
2625 if (nMaxCount <= 0) return 0;
2626 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2627 if (win == WND_DESKTOP) lpString[0] = 0;
2628 else if (win != WND_OTHER_PROCESS)
2630 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2631 else lpString[0] = 0;
2632 WIN_ReleasePtr( win );
2634 else
2636 get_server_window_text( hwnd, lpString, nMaxCount );
2638 return strlenW(lpString);
2642 /*******************************************************************
2643 * GetWindowTextW (USER32.@)
2645 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2647 if (!lpString) return 0;
2649 if (WIN_IsCurrentProcess( hwnd ))
2650 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2652 /* when window belongs to other process, don't send a message */
2653 if (nMaxCount <= 0) return 0;
2654 get_server_window_text( hwnd, lpString, nMaxCount );
2655 return strlenW(lpString);
2659 /*******************************************************************
2660 * SetWindowTextA (USER32.@)
2661 * SetWindowText (USER32.@)
2663 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2665 if (is_broadcast(hwnd))
2667 SetLastError( ERROR_INVALID_PARAMETER );
2668 return FALSE;
2670 if (!WIN_IsCurrentProcess( hwnd ))
2671 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2672 debugstr_a(lpString), hwnd );
2673 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2677 /*******************************************************************
2678 * SetWindowTextW (USER32.@)
2680 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2682 if (is_broadcast(hwnd))
2684 SetLastError( ERROR_INVALID_PARAMETER );
2685 return FALSE;
2687 if (!WIN_IsCurrentProcess( hwnd ))
2688 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2689 debugstr_w(lpString), hwnd );
2690 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2694 /*******************************************************************
2695 * GetWindowTextLengthA (USER32.@)
2697 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2699 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2702 /*******************************************************************
2703 * GetWindowTextLengthW (USER32.@)
2705 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2707 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2711 /*******************************************************************
2712 * IsWindow (USER32.@)
2714 BOOL WINAPI IsWindow( HWND hwnd )
2716 WND *ptr;
2717 BOOL ret;
2719 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2720 if (ptr == WND_DESKTOP) return TRUE;
2722 if (ptr != WND_OTHER_PROCESS)
2724 WIN_ReleasePtr( ptr );
2725 return TRUE;
2728 /* check other processes */
2729 SERVER_START_REQ( get_window_info )
2731 req->handle = wine_server_user_handle( hwnd );
2732 ret = !wine_server_call_err( req );
2734 SERVER_END_REQ;
2735 return ret;
2739 /***********************************************************************
2740 * GetWindowThreadProcessId (USER32.@)
2742 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2744 WND *ptr;
2745 DWORD tid = 0;
2747 if (!(ptr = WIN_GetPtr( hwnd )))
2749 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2750 return 0;
2753 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2755 /* got a valid window */
2756 tid = ptr->tid;
2757 if (process) *process = GetCurrentProcessId();
2758 WIN_ReleasePtr( ptr );
2759 return tid;
2762 /* check other processes */
2763 SERVER_START_REQ( get_window_info )
2765 req->handle = wine_server_user_handle( hwnd );
2766 if (!wine_server_call_err( req ))
2768 tid = (DWORD)reply->tid;
2769 if (process) *process = (DWORD)reply->pid;
2772 SERVER_END_REQ;
2773 return tid;
2777 /*****************************************************************
2778 * GetParent (USER32.@)
2780 HWND WINAPI GetParent( HWND hwnd )
2782 WND *wndPtr;
2783 HWND retvalue = 0;
2785 if (!(wndPtr = WIN_GetPtr( hwnd )))
2787 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2788 return 0;
2790 if (wndPtr == WND_DESKTOP) return 0;
2791 if (wndPtr == WND_OTHER_PROCESS)
2793 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2794 if (style & (WS_POPUP | WS_CHILD))
2796 SERVER_START_REQ( get_window_tree )
2798 req->handle = wine_server_user_handle( hwnd );
2799 if (!wine_server_call_err( req ))
2801 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2802 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2805 SERVER_END_REQ;
2808 else
2810 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2811 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2812 WIN_ReleasePtr( wndPtr );
2814 return retvalue;
2818 /*****************************************************************
2819 * GetAncestor (USER32.@)
2821 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2823 WND *win;
2824 HWND *list, ret = 0;
2826 switch(type)
2828 case GA_PARENT:
2829 if (!(win = WIN_GetPtr( hwnd )))
2831 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2832 return 0;
2834 if (win == WND_DESKTOP) return 0;
2835 if (win != WND_OTHER_PROCESS)
2837 ret = win->parent;
2838 WIN_ReleasePtr( win );
2840 else /* need to query the server */
2842 SERVER_START_REQ( get_window_tree )
2844 req->handle = wine_server_user_handle( hwnd );
2845 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2847 SERVER_END_REQ;
2849 break;
2851 case GA_ROOT:
2852 if (!(list = list_window_parents( hwnd ))) return 0;
2854 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2855 else
2857 int count = 2;
2858 while (list[count]) count++;
2859 ret = list[count - 2]; /* get the one before the desktop */
2861 HeapFree( GetProcessHeap(), 0, list );
2862 break;
2864 case GA_ROOTOWNER:
2865 if (is_desktop_window( hwnd )) return 0;
2866 ret = WIN_GetFullHandle( hwnd );
2867 for (;;)
2869 HWND parent = GetParent( ret );
2870 if (!parent) break;
2871 ret = parent;
2873 break;
2875 return ret;
2879 /*****************************************************************
2880 * SetParent (USER32.@)
2882 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2884 HWND full_handle;
2885 HWND old_parent = 0;
2886 BOOL was_visible;
2887 WND *wndPtr;
2888 POINT pt;
2889 BOOL ret;
2891 if (is_broadcast(hwnd) || is_broadcast(parent))
2893 SetLastError(ERROR_INVALID_PARAMETER);
2894 return 0;
2897 if (!parent) parent = GetDesktopWindow();
2898 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2899 else parent = WIN_GetFullHandle( parent );
2901 if (!IsWindow( parent ))
2903 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2904 return 0;
2907 /* Some applications try to set a child as a parent */
2908 if (IsChild(hwnd, parent))
2910 SetLastError( ERROR_INVALID_PARAMETER );
2911 return 0;
2914 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2915 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2917 if (full_handle == parent)
2919 SetLastError( ERROR_INVALID_PARAMETER );
2920 return 0;
2923 /* Windows hides the window first, then shows it again
2924 * including the WM_SHOWWINDOW messages and all */
2925 was_visible = ShowWindow( hwnd, SW_HIDE );
2927 wndPtr = WIN_GetPtr( hwnd );
2928 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2930 pt.x = wndPtr->rectWindow.left;
2931 pt.y = wndPtr->rectWindow.top;
2933 SERVER_START_REQ( set_parent )
2935 req->handle = wine_server_user_handle( hwnd );
2936 req->parent = wine_server_user_handle( parent );
2937 if ((ret = !wine_server_call( req )))
2939 old_parent = wine_server_ptr_handle( reply->old_parent );
2940 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2944 SERVER_END_REQ;
2945 WIN_ReleasePtr( wndPtr );
2946 if (!ret) return 0;
2948 USER_Driver->pSetParent( full_handle, parent, old_parent );
2950 /* SetParent additionally needs to make hwnd the topmost window
2951 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2952 WM_WINDOWPOSCHANGED notification messages.
2954 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
2956 if (was_visible) ShowWindow( hwnd, SW_SHOW );
2958 return old_parent;
2962 /*******************************************************************
2963 * IsChild (USER32.@)
2965 BOOL WINAPI IsChild( HWND parent, HWND child )
2967 HWND *list = list_window_parents( child );
2968 int i;
2969 BOOL ret;
2971 if (!list) return FALSE;
2972 parent = WIN_GetFullHandle( parent );
2973 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2974 ret = list[i] && list[i+1];
2975 HeapFree( GetProcessHeap(), 0, list );
2976 return ret;
2980 /***********************************************************************
2981 * IsWindowVisible (USER32.@)
2983 BOOL WINAPI IsWindowVisible( HWND hwnd )
2985 HWND *list;
2986 BOOL retval = TRUE;
2987 int i;
2989 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2990 if (!(list = list_window_parents( hwnd ))) return TRUE;
2991 if (list[0])
2993 for (i = 0; list[i+1]; i++)
2994 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2995 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2997 HeapFree( GetProcessHeap(), 0, list );
2998 return retval;
3002 /***********************************************************************
3003 * WIN_IsWindowDrawable
3005 * hwnd is drawable when it is visible, all parents are not
3006 * minimized, and it is itself not minimized unless we are
3007 * trying to draw its default class icon.
3009 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3011 HWND *list;
3012 BOOL retval = TRUE;
3013 int i;
3014 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3016 if (!(style & WS_VISIBLE)) return FALSE;
3017 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3019 if (!(list = list_window_parents( hwnd ))) return TRUE;
3020 if (list[0])
3022 for (i = 0; list[i+1]; i++)
3023 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3024 break;
3025 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3027 HeapFree( GetProcessHeap(), 0, list );
3028 return retval;
3032 /*******************************************************************
3033 * GetTopWindow (USER32.@)
3035 HWND WINAPI GetTopWindow( HWND hwnd )
3037 if (!hwnd) hwnd = GetDesktopWindow();
3038 return GetWindow( hwnd, GW_CHILD );
3042 /*******************************************************************
3043 * GetWindow (USER32.@)
3045 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3047 HWND retval = 0;
3049 if (rel == GW_OWNER) /* this one may be available locally */
3051 WND *wndPtr = WIN_GetPtr( hwnd );
3052 if (!wndPtr)
3054 SetLastError( ERROR_INVALID_HANDLE );
3055 return 0;
3057 if (wndPtr == WND_DESKTOP) return 0;
3058 if (wndPtr != WND_OTHER_PROCESS)
3060 retval = wndPtr->owner;
3061 WIN_ReleasePtr( wndPtr );
3062 return retval;
3064 /* else fall through to server call */
3067 SERVER_START_REQ( get_window_tree )
3069 req->handle = wine_server_user_handle( hwnd );
3070 if (!wine_server_call_err( req ))
3072 switch(rel)
3074 case GW_HWNDFIRST:
3075 retval = wine_server_ptr_handle( reply->first_sibling );
3076 break;
3077 case GW_HWNDLAST:
3078 retval = wine_server_ptr_handle( reply->last_sibling );
3079 break;
3080 case GW_HWNDNEXT:
3081 retval = wine_server_ptr_handle( reply->next_sibling );
3082 break;
3083 case GW_HWNDPREV:
3084 retval = wine_server_ptr_handle( reply->prev_sibling );
3085 break;
3086 case GW_OWNER:
3087 retval = wine_server_ptr_handle( reply->owner );
3088 break;
3089 case GW_CHILD:
3090 retval = wine_server_ptr_handle( reply->first_child );
3091 break;
3095 SERVER_END_REQ;
3096 return retval;
3100 /*******************************************************************
3101 * ShowOwnedPopups (USER32.@)
3103 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3105 int count = 0;
3106 WND *pWnd;
3107 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3109 if (!win_array) return TRUE;
3111 while (win_array[count]) count++;
3112 while (--count >= 0)
3114 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3115 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3116 if (pWnd == WND_OTHER_PROCESS) continue;
3117 if (fShow)
3119 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3121 WIN_ReleasePtr( pWnd );
3122 /* In Windows, ShowOwnedPopups(TRUE) generates
3123 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3124 * regardless of the state of the owner
3126 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3127 continue;
3130 else
3132 if (pWnd->dwStyle & WS_VISIBLE)
3134 WIN_ReleasePtr( pWnd );
3135 /* In Windows, ShowOwnedPopups(FALSE) generates
3136 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3137 * regardless of the state of the owner
3139 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3140 continue;
3143 WIN_ReleasePtr( pWnd );
3145 HeapFree( GetProcessHeap(), 0, win_array );
3146 return TRUE;
3150 /*******************************************************************
3151 * GetLastActivePopup (USER32.@)
3153 HWND WINAPI GetLastActivePopup( HWND hwnd )
3155 HWND retval = hwnd;
3157 SERVER_START_REQ( get_window_info )
3159 req->handle = wine_server_user_handle( hwnd );
3160 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3162 SERVER_END_REQ;
3163 return retval;
3167 /*******************************************************************
3168 * WIN_ListChildren
3170 * Build an array of the children of a given window. The array must be
3171 * freed with HeapFree. Returns NULL when no windows are found.
3173 HWND *WIN_ListChildren( HWND hwnd )
3175 if (!hwnd)
3177 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3178 return NULL;
3180 return list_window_children( 0, hwnd, NULL, 0 );
3184 /*******************************************************************
3185 * EnumWindows (USER32.@)
3187 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3189 HWND *list;
3190 BOOL ret = TRUE;
3191 int i;
3193 USER_CheckNotLock();
3195 /* We have to build a list of all windows first, to avoid */
3196 /* unpleasant side-effects, for instance if the callback */
3197 /* function changes the Z-order of the windows. */
3199 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3201 /* Now call the callback function for every window */
3203 for (i = 0; list[i]; i++)
3205 /* Make sure that the window still exists */
3206 if (!IsWindow( list[i] )) continue;
3207 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3209 HeapFree( GetProcessHeap(), 0, list );
3210 return ret;
3214 /**********************************************************************
3215 * EnumThreadWindows (USER32.@)
3217 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3219 HWND *list;
3220 int i;
3221 BOOL ret = TRUE;
3223 USER_CheckNotLock();
3225 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3227 /* Now call the callback function for every window */
3229 for (i = 0; list[i]; i++)
3230 if (!(ret = func( list[i], lParam ))) break;
3231 HeapFree( GetProcessHeap(), 0, list );
3232 return ret;
3236 /***********************************************************************
3237 * EnumDesktopWindows (USER32.@)
3239 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3241 HWND *list;
3242 int i;
3244 USER_CheckNotLock();
3246 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3248 for (i = 0; list[i]; i++)
3249 if (!func( list[i], lparam )) break;
3250 HeapFree( GetProcessHeap(), 0, list );
3251 return TRUE;
3255 /**********************************************************************
3256 * WIN_EnumChildWindows
3258 * Helper function for EnumChildWindows().
3260 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3262 HWND *childList;
3263 BOOL ret = FALSE;
3265 for ( ; *list; list++)
3267 /* Make sure that the window still exists */
3268 if (!IsWindow( *list )) continue;
3269 /* Build children list first */
3270 childList = WIN_ListChildren( *list );
3272 ret = func( *list, lParam );
3274 if (childList)
3276 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3277 HeapFree( GetProcessHeap(), 0, childList );
3279 if (!ret) return FALSE;
3281 return TRUE;
3285 /**********************************************************************
3286 * EnumChildWindows (USER32.@)
3288 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3290 HWND *list;
3291 BOOL ret;
3293 USER_CheckNotLock();
3295 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3296 ret = WIN_EnumChildWindows( list, func, lParam );
3297 HeapFree( GetProcessHeap(), 0, list );
3298 return ret;
3302 /*******************************************************************
3303 * AnyPopup (USER32.@)
3305 BOOL WINAPI AnyPopup(void)
3307 int i;
3308 BOOL retvalue;
3309 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3311 if (!list) return FALSE;
3312 for (i = 0; list[i]; i++)
3314 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3316 retvalue = (list[i] != 0);
3317 HeapFree( GetProcessHeap(), 0, list );
3318 return retvalue;
3322 /*******************************************************************
3323 * FlashWindow (USER32.@)
3325 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3327 WND *wndPtr;
3329 TRACE("%p\n", hWnd);
3331 if (IsIconic( hWnd ))
3333 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3335 wndPtr = WIN_GetPtr(hWnd);
3336 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3337 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3339 wndPtr->flags |= WIN_NCACTIVATED;
3341 else
3343 wndPtr->flags &= ~WIN_NCACTIVATED;
3345 WIN_ReleasePtr( wndPtr );
3346 return TRUE;
3348 else
3350 WPARAM wparam;
3352 wndPtr = WIN_GetPtr(hWnd);
3353 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3354 hWnd = wndPtr->obj.handle; /* make it a full handle */
3356 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3357 else wparam = (hWnd == GetForegroundWindow());
3359 WIN_ReleasePtr( wndPtr );
3360 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3361 return wparam;
3365 /*******************************************************************
3366 * FlashWindowEx (USER32.@)
3368 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3370 FIXME("%p\n", pfwi);
3371 return TRUE;
3374 /*******************************************************************
3375 * GetWindowContextHelpId (USER32.@)
3377 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3379 DWORD retval;
3380 WND *wnd = WIN_GetPtr( hwnd );
3381 if (!wnd || wnd == WND_DESKTOP) return 0;
3382 if (wnd == WND_OTHER_PROCESS)
3384 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3385 return 0;
3387 retval = wnd->helpContext;
3388 WIN_ReleasePtr( wnd );
3389 return retval;
3393 /*******************************************************************
3394 * SetWindowContextHelpId (USER32.@)
3396 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3398 WND *wnd = WIN_GetPtr( hwnd );
3399 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3400 if (wnd == WND_OTHER_PROCESS)
3402 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3403 return 0;
3405 wnd->helpContext = id;
3406 WIN_ReleasePtr( wnd );
3407 return TRUE;
3411 /*******************************************************************
3412 * DragDetect (USER32.@)
3414 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3416 MSG msg;
3417 RECT rect;
3418 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3419 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3421 rect.left = pt.x - wDragWidth;
3422 rect.right = pt.x + wDragWidth;
3424 rect.top = pt.y - wDragHeight;
3425 rect.bottom = pt.y + wDragHeight;
3427 SetCapture(hWnd);
3429 while(1)
3431 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3433 if( msg.message == WM_LBUTTONUP )
3435 ReleaseCapture();
3436 return 0;
3438 if( msg.message == WM_MOUSEMOVE )
3440 POINT tmp;
3441 tmp.x = (short)LOWORD(msg.lParam);
3442 tmp.y = (short)HIWORD(msg.lParam);
3443 if( !PtInRect( &rect, tmp ))
3445 ReleaseCapture();
3446 return 1;
3450 WaitMessage();
3452 return 0;
3455 /******************************************************************************
3456 * GetWindowModuleFileNameA (USER32.@)
3458 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3460 WND *win;
3461 HINSTANCE hinst;
3463 TRACE( "%p, %p, %u\n", hwnd, module, size );
3465 win = WIN_GetPtr( hwnd );
3466 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3468 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3469 return 0;
3471 hinst = win->hInstance;
3472 WIN_ReleasePtr( win );
3474 return GetModuleFileNameA( hinst, module, size );
3477 /******************************************************************************
3478 * GetWindowModuleFileNameW (USER32.@)
3480 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3482 WND *win;
3483 HINSTANCE hinst;
3485 TRACE( "%p, %p, %u\n", hwnd, module, size );
3487 win = WIN_GetPtr( hwnd );
3488 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3490 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3491 return 0;
3493 hinst = win->hInstance;
3494 WIN_ReleasePtr( win );
3496 return GetModuleFileNameW( hinst, module, size );
3499 /******************************************************************************
3500 * GetWindowInfo (USER32.@)
3502 * Note: tests show that Windows doesn't check cbSize of the structure.
3504 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3506 if (!pwi) return FALSE;
3507 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3509 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3510 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3511 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3513 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3514 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3516 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3517 pwi->wCreatorVersion = 0x0400;
3519 return TRUE;
3522 /******************************************************************************
3523 * SwitchDesktop (USER32.@)
3525 * NOTES: Sets the current input or interactive desktop.
3527 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3529 FIXME("(hwnd %p) stub!\n", hDesktop);
3530 return TRUE;
3533 /*****************************************************************************
3534 * SetLayeredWindowAttributes (USER32.@)
3536 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3538 BOOL ret;
3540 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3542 SERVER_START_REQ( set_window_layered_info )
3544 req->handle = wine_server_user_handle( hwnd );
3545 req->color_key = key;
3546 req->alpha = alpha;
3547 req->flags = flags;
3548 ret = !wine_server_call_err( req );
3550 SERVER_END_REQ;
3552 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3554 return ret;
3558 /*****************************************************************************
3559 * GetLayeredWindowAttributes (USER32.@)
3561 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3563 BOOL ret;
3565 SERVER_START_REQ( get_window_layered_info )
3567 req->handle = wine_server_user_handle( hwnd );
3568 if ((ret = !wine_server_call_err( req )))
3570 if (key) *key = reply->color_key;
3571 if (alpha) *alpha = reply->alpha;
3572 if (flags) *flags = reply->flags;
3575 SERVER_END_REQ;
3577 return ret;
3581 /*****************************************************************************
3582 * UpdateLayeredWindowIndirect (USER32.@)
3584 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3586 BYTE alpha = 0xff;
3588 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3589 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3591 SetLastError( ERROR_INVALID_PARAMETER );
3592 return FALSE;
3595 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3597 int x = 0, y = 0, cx = 0, cy = 0;
3598 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3600 if (info->pptDst)
3602 x = info->pptDst->x;
3603 y = info->pptDst->y;
3604 flags &= ~SWP_NOMOVE;
3606 if (info->psize)
3608 cx = info->psize->cx;
3609 cy = info->psize->cy;
3610 flags &= ~SWP_NOSIZE;
3612 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3613 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3616 if (info->hdcSrc)
3618 HDC hdc = GetWindowDC( hwnd );
3620 if (hdc)
3622 int x = 0, y = 0;
3623 RECT rect;
3625 GetWindowRect( hwnd, &rect );
3626 OffsetRect( &rect, -rect.left, -rect.top);
3627 if (info->pptSrc)
3629 x = info->pptSrc->x;
3630 y = info->pptSrc->y;
3633 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3635 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3636 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3637 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3639 ReleaseDC( hwnd, hdc );
3643 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3644 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3645 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3646 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3647 return TRUE;
3651 /*****************************************************************************
3652 * UpdateLayeredWindow (USER32.@)
3654 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3655 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3656 DWORD dwFlags)
3658 UPDATELAYEREDWINDOWINFO info;
3660 info.cbSize = sizeof(info);
3661 info.hdcDst = hdcDst;
3662 info.pptDst = pptDst;
3663 info.psize = psize;
3664 info.hdcSrc = hdcSrc;
3665 info.pptSrc = pptSrc;
3666 info.crKey = crKey;
3667 info.pblend = pblend;
3668 info.dwFlags = dwFlags;
3669 info.prcDirty = NULL;
3670 return UpdateLayeredWindowIndirect( hwnd, &info );
3674 /******************************************************************************
3675 * GetProcessDefaultLayout [USER32.@]
3677 * Gets the default layout for parentless windows.
3679 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3681 if (!layout)
3683 SetLastError( ERROR_NOACCESS );
3684 return FALSE;
3686 if (process_layout == ~0u)
3688 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3689 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3690 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3691 '\\','%','0','4','x','%','0','4','x',
3692 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3693 WCHAR *str, buffer[MAX_PATH];
3694 DWORD i, len, version_layout = 0;
3695 DWORD user_lang = GetUserDefaultLangID();
3696 DWORD *languages;
3697 void *data = NULL;
3699 GetModuleFileNameW( 0, buffer, MAX_PATH );
3700 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3701 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3702 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3703 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3705 len /= sizeof(DWORD);
3706 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3707 if (i == len) /* try neutral language */
3708 for (i = 0; i < len; i++)
3709 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3710 if (i == len) i = 0; /* default to the first one */
3712 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3713 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3714 TRACE( "found description %s\n", debugstr_w( str ));
3715 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3717 done:
3718 HeapFree( GetProcessHeap(), 0, data );
3719 process_layout = version_layout;
3721 *layout = process_layout;
3722 return TRUE;
3726 /******************************************************************************
3727 * SetProcessDefaultLayout [USER32.@]
3729 * Sets the default layout for parentless windows.
3731 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3733 process_layout = layout;
3734 return TRUE;
3738 /* 64bit versions */
3740 #ifdef GetWindowLongPtrW
3741 #undef GetWindowLongPtrW
3742 #endif
3744 #ifdef GetWindowLongPtrA
3745 #undef GetWindowLongPtrA
3746 #endif
3748 #ifdef SetWindowLongPtrW
3749 #undef SetWindowLongPtrW
3750 #endif
3752 #ifdef SetWindowLongPtrA
3753 #undef SetWindowLongPtrA
3754 #endif
3756 /*****************************************************************************
3757 * GetWindowLongPtrW (USER32.@)
3759 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3761 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3764 /*****************************************************************************
3765 * GetWindowLongPtrA (USER32.@)
3767 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3769 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3772 /*****************************************************************************
3773 * SetWindowLongPtrW (USER32.@)
3775 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3777 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3780 /*****************************************************************************
3781 * SetWindowLongPtrA (USER32.@)
3783 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3785 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );