user32: Store the pixel format in the window structure.
[wine.git] / dlls / user32 / win.c
blob7da497249f1b700d9929cbe6c5d21b9fa2b59668
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 * update_window_state
436 * Trigger an update of the window's driver state and surface.
438 static void update_window_state( HWND hwnd )
440 RECT window_rect, client_rect;
442 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
443 set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
444 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW, &window_rect, &client_rect, NULL );
448 /*******************************************************************
449 * get_server_window_text
451 * Retrieve the window text from the server.
453 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
455 size_t len = 0;
457 SERVER_START_REQ( get_window_text )
459 req->handle = wine_server_user_handle( hwnd );
460 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
461 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
463 SERVER_END_REQ;
464 text[len / sizeof(WCHAR)] = 0;
468 /*******************************************************************
469 * get_hwnd_message_parent
471 * Return the parent for HWND_MESSAGE windows.
473 HWND get_hwnd_message_parent(void)
475 struct user_thread_info *thread_info = get_user_thread_info();
477 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
478 return thread_info->msg_window;
482 /*******************************************************************
483 * is_desktop_window
485 * Check if window is the desktop or the HWND_MESSAGE top parent.
487 BOOL is_desktop_window( HWND hwnd )
489 struct user_thread_info *thread_info = get_user_thread_info();
491 if (!hwnd) return FALSE;
492 if (hwnd == thread_info->top_window) return TRUE;
493 if (hwnd == thread_info->msg_window) return TRUE;
495 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
497 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
498 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
500 return FALSE;
504 /*******************************************************************
505 * Dummy window surface for windows that shouldn't get painted.
508 static void dummy_surface_lock( struct window_surface *window_surface )
510 /* nothing to do */
513 static void dummy_surface_unlock( struct window_surface *window_surface )
515 /* nothing to do */
518 static void *dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
520 static DWORD dummy_data;
522 info->bmiHeader.biSize = sizeof( info->bmiHeader );
523 info->bmiHeader.biWidth = dummy_surface.rect.right;
524 info->bmiHeader.biHeight = dummy_surface.rect.bottom;
525 info->bmiHeader.biPlanes = 1;
526 info->bmiHeader.biBitCount = 32;
527 info->bmiHeader.biCompression = BI_RGB;
528 info->bmiHeader.biSizeImage = 0;
529 info->bmiHeader.biXPelsPerMeter = 0;
530 info->bmiHeader.biYPelsPerMeter = 0;
531 info->bmiHeader.biClrUsed = 0;
532 info->bmiHeader.biClrImportant = 0;
533 return &dummy_data;
536 static RECT *dummy_surface_get_bounds( struct window_surface *window_surface )
538 static RECT dummy_bounds;
539 return &dummy_bounds;
542 static void dummy_surface_flush( struct window_surface *window_surface )
544 /* nothing to do */
547 static void dummy_surface_destroy( struct window_surface *window_surface )
549 /* nothing to do */
552 static const struct window_surface_funcs dummy_surface_funcs =
554 dummy_surface_lock,
555 dummy_surface_unlock,
556 dummy_surface_get_bitmap_info,
557 dummy_surface_get_bounds,
558 dummy_surface_flush,
559 dummy_surface_destroy
562 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
565 /*******************************************************************
566 * register_window_surface
568 * Register a window surface in the global list, possibly replacing another one.
570 void register_window_surface( struct window_surface *old, struct window_surface *new )
572 if (old == new) return;
573 EnterCriticalSection( &surfaces_section );
574 if (old && old != &dummy_surface) list_remove( &old->entry );
575 if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
576 LeaveCriticalSection( &surfaces_section );
580 /*******************************************************************
581 * flush_window_surfaces
583 * Flush pending output from all window surfaces.
585 void flush_window_surfaces( BOOL idle )
587 static DWORD last_idle;
588 DWORD now;
589 struct window_surface *surface;
591 EnterCriticalSection( &surfaces_section );
592 now = GetTickCount();
593 if (idle) last_idle = now;
594 /* if not idle, we only flush if there's evidence that the app never goes idle */
595 else if ((int)(now - last_idle) < 1000) goto done;
597 LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
598 surface->funcs->flush( surface );
599 done:
600 LeaveCriticalSection( &surfaces_section );
604 /***********************************************************************
605 * WIN_GetPtr
607 * Return a pointer to the WND structure if local to the process,
608 * or WND_OTHER_PROCESS if handle may be valid in other process.
609 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
611 WND *WIN_GetPtr( HWND hwnd )
613 WND *ptr;
615 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
617 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
619 return ptr;
623 /***********************************************************************
624 * WIN_IsCurrentProcess
626 * Check whether a given window belongs to the current process (and return the full handle).
628 HWND WIN_IsCurrentProcess( HWND hwnd )
630 WND *ptr;
631 HWND ret;
633 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
634 ret = ptr->obj.handle;
635 WIN_ReleasePtr( ptr );
636 return ret;
640 /***********************************************************************
641 * WIN_IsCurrentThread
643 * Check whether a given window belongs to the current thread (and return the full handle).
645 HWND WIN_IsCurrentThread( HWND hwnd )
647 WND *ptr;
648 HWND ret = 0;
650 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
651 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
652 WIN_ReleasePtr( ptr );
653 return ret;
657 /***********************************************************************
658 * WIN_GetFullHandle
660 * Convert a possibly truncated window handle to a full 32-bit handle.
662 HWND WIN_GetFullHandle( HWND hwnd )
664 WND *ptr;
666 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
667 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
668 /* do sign extension for -2 and -3 */
669 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
671 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
673 if (ptr == WND_DESKTOP)
675 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
676 else return get_hwnd_message_parent();
679 if (ptr != WND_OTHER_PROCESS)
681 hwnd = ptr->obj.handle;
682 WIN_ReleasePtr( ptr );
684 else /* may belong to another process */
686 SERVER_START_REQ( get_window_info )
688 req->handle = wine_server_user_handle( hwnd );
689 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
691 SERVER_END_REQ;
693 return hwnd;
697 /***********************************************************************
698 * WIN_SetOwner
700 * Change the owner of a window.
702 HWND WIN_SetOwner( HWND hwnd, HWND owner )
704 WND *win = WIN_GetPtr( hwnd );
705 HWND ret = 0;
707 if (!win || win == WND_DESKTOP) return 0;
708 if (win == WND_OTHER_PROCESS)
710 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
711 return 0;
713 SERVER_START_REQ( set_window_owner )
715 req->handle = wine_server_user_handle( hwnd );
716 req->owner = wine_server_user_handle( owner );
717 if (!wine_server_call( req ))
719 win->owner = wine_server_ptr_handle( reply->full_owner );
720 ret = wine_server_ptr_handle( reply->prev_owner );
723 SERVER_END_REQ;
724 WIN_ReleasePtr( win );
725 return ret;
729 /***********************************************************************
730 * WIN_SetStyle
732 * Change the style of a window.
734 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
736 BOOL ok, made_visible = FALSE;
737 STYLESTRUCT style;
738 WND *win = WIN_GetPtr( hwnd );
740 if (!win || win == WND_DESKTOP) return 0;
741 if (win == WND_OTHER_PROCESS)
743 if (IsWindow(hwnd))
744 ERR( "cannot set style %x/%x on other process window %p\n",
745 set_bits, clear_bits, hwnd );
746 return 0;
748 style.styleOld = win->dwStyle;
749 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
750 if (style.styleNew == style.styleOld)
752 WIN_ReleasePtr( win );
753 return style.styleNew;
755 SERVER_START_REQ( set_window_info )
757 req->handle = wine_server_user_handle( hwnd );
758 req->flags = SET_WIN_STYLE;
759 req->style = style.styleNew;
760 req->extra_offset = -1;
761 if ((ok = !wine_server_call( req )))
763 style.styleOld = reply->old_style;
764 win->dwStyle = style.styleNew;
767 SERVER_END_REQ;
769 if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
771 /* Some apps try to make their window visible through WM_SETREDRAW.
772 * Only do that if the window was never explicitly hidden,
773 * because Steam messes with WM_SETREDRAW after hiding its windows. */
774 made_visible = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
775 invalidate_dce( win, NULL );
777 WIN_ReleasePtr( win );
779 if (!ok) return 0;
781 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
782 if (made_visible) update_window_state( hwnd );
784 return style.styleOld;
788 /***********************************************************************
789 * WIN_GetRectangles
791 * Get the window and client rectangles.
793 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
795 WND *win = WIN_GetPtr( hwnd );
796 BOOL ret = TRUE;
798 if (!win)
800 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
801 return FALSE;
803 if (win == WND_DESKTOP)
805 RECT rect;
806 rect.left = rect.top = 0;
807 if (hwnd == get_hwnd_message_parent())
809 rect.right = 100;
810 rect.bottom = 100;
812 else
814 rect.right = GetSystemMetrics(SM_CXSCREEN);
815 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
817 if (rectWindow) *rectWindow = rect;
818 if (rectClient) *rectClient = rect;
819 return TRUE;
821 if (win != WND_OTHER_PROCESS)
823 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
825 switch (relative)
827 case COORDS_CLIENT:
828 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
829 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
830 if (win->dwExStyle & WS_EX_LAYOUTRTL)
831 mirror_rect( &win->rectClient, &window_rect );
832 break;
833 case COORDS_WINDOW:
834 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
835 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
836 if (win->dwExStyle & WS_EX_LAYOUTRTL)
837 mirror_rect( &win->rectWindow, &client_rect );
838 break;
839 case COORDS_PARENT:
840 if (win->parent)
842 WND *parent = WIN_GetPtr( win->parent );
843 if (parent == WND_DESKTOP) break;
844 if (!parent || parent == WND_OTHER_PROCESS)
846 WIN_ReleasePtr( win );
847 goto other_process;
849 if (parent->flags & WIN_CHILDREN_MOVED)
851 WIN_ReleasePtr( parent );
852 WIN_ReleasePtr( win );
853 goto other_process;
855 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
857 mirror_rect( &parent->rectClient, &window_rect );
858 mirror_rect( &parent->rectClient, &client_rect );
860 WIN_ReleasePtr( parent );
862 break;
863 case COORDS_SCREEN:
864 while (win->parent)
866 WND *parent = WIN_GetPtr( win->parent );
867 if (parent == WND_DESKTOP) break;
868 if (!parent || parent == WND_OTHER_PROCESS)
870 WIN_ReleasePtr( win );
871 goto other_process;
873 WIN_ReleasePtr( win );
874 if (parent->flags & WIN_CHILDREN_MOVED)
876 WIN_ReleasePtr( parent );
877 goto other_process;
879 win = parent;
880 if (win->parent)
882 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
883 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
886 break;
888 if (rectWindow) *rectWindow = window_rect;
889 if (rectClient) *rectClient = client_rect;
890 WIN_ReleasePtr( win );
891 return TRUE;
894 other_process:
895 SERVER_START_REQ( get_window_rectangles )
897 req->handle = wine_server_user_handle( hwnd );
898 req->relative = relative;
899 if ((ret = !wine_server_call_err( req )))
901 if (rectWindow)
903 rectWindow->left = reply->window.left;
904 rectWindow->top = reply->window.top;
905 rectWindow->right = reply->window.right;
906 rectWindow->bottom = reply->window.bottom;
908 if (rectClient)
910 rectClient->left = reply->client.left;
911 rectClient->top = reply->client.top;
912 rectClient->right = reply->client.right;
913 rectClient->bottom = reply->client.bottom;
917 SERVER_END_REQ;
918 return ret;
922 /***********************************************************************
923 * WIN_DestroyWindow
925 * Destroy storage associated to a window. "Internals" p.358
927 LRESULT WIN_DestroyWindow( HWND hwnd )
929 WND *wndPtr;
930 HWND *list;
931 HMENU menu = 0, sys_menu;
932 HWND icon_title;
933 struct window_surface *surface;
935 TRACE("%p\n", hwnd );
937 /* free child windows */
938 if ((list = WIN_ListChildren( hwnd )))
940 int i;
941 for (i = 0; list[i]; i++)
943 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
944 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
946 HeapFree( GetProcessHeap(), 0, list );
949 /* Unlink now so we won't bother with the children later on */
950 SERVER_START_REQ( set_parent )
952 req->handle = wine_server_user_handle( hwnd );
953 req->parent = 0;
954 wine_server_call( req );
956 SERVER_END_REQ;
959 * Send the WM_NCDESTROY to the window being destroyed.
961 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
963 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
965 /* free resources associated with the window */
967 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
968 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
969 menu = (HMENU)wndPtr->wIDmenu;
970 sys_menu = wndPtr->hSysMenu;
971 free_dce( wndPtr->dce, hwnd );
972 wndPtr->dce = NULL;
973 icon_title = wndPtr->icon_title;
974 HeapFree( GetProcessHeap(), 0, wndPtr->text );
975 wndPtr->text = NULL;
976 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
977 wndPtr->pScroll = NULL;
978 surface = wndPtr->surface;
979 wndPtr->surface = NULL;
980 WIN_ReleasePtr( wndPtr );
982 if (icon_title) DestroyWindow( icon_title );
983 if (menu) DestroyMenu( menu );
984 if (sys_menu) DestroyMenu( sys_menu );
985 if (surface)
987 register_window_surface( surface, NULL );
988 window_surface_release( surface );
991 USER_Driver->pDestroyWindow( hwnd );
993 free_window_handle( hwnd );
994 return 0;
998 /***********************************************************************
999 * destroy_thread_window
1001 * Destroy a window upon exit of its thread.
1003 static void destroy_thread_window( HWND hwnd )
1005 WND *wndPtr;
1006 HWND *list;
1007 HMENU menu = 0, sys_menu = 0;
1008 struct window_surface *surface = NULL;
1009 WORD index;
1011 /* free child windows */
1013 if ((list = WIN_ListChildren( hwnd )))
1015 int i;
1016 for (i = 0; list[i]; i++)
1018 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
1019 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1021 HeapFree( GetProcessHeap(), 0, list );
1024 /* destroy the client-side storage */
1026 index = USER_HANDLE_TO_INDEX(hwnd);
1027 if (index >= NB_USER_HANDLES) return;
1028 USER_Lock();
1029 if ((wndPtr = user_handles[index]))
1031 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
1032 sys_menu = wndPtr->hSysMenu;
1033 free_dce( wndPtr->dce, hwnd );
1034 surface = wndPtr->surface;
1035 wndPtr->surface = NULL;
1036 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
1038 USER_Unlock();
1040 HeapFree( GetProcessHeap(), 0, wndPtr );
1041 if (menu) DestroyMenu( menu );
1042 if (sys_menu) DestroyMenu( sys_menu );
1043 if (surface)
1045 register_window_surface( surface, NULL );
1046 window_surface_release( surface );
1051 /***********************************************************************
1052 * destroy_thread_child_windows
1054 * Destroy child windows upon exit of its thread.
1056 static void destroy_thread_child_windows( HWND hwnd )
1058 HWND *list;
1059 int i;
1061 if (WIN_IsCurrentThread( hwnd ))
1063 destroy_thread_window( hwnd );
1065 else if ((list = WIN_ListChildren( hwnd )))
1067 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1068 HeapFree( GetProcessHeap(), 0, list );
1073 /***********************************************************************
1074 * WIN_DestroyThreadWindows
1076 * Destroy all children of 'wnd' owned by the current thread.
1078 void WIN_DestroyThreadWindows( HWND hwnd )
1080 HWND *list;
1081 int i;
1083 if (!(list = WIN_ListChildren( hwnd ))) return;
1085 /* reset owners of top-level windows */
1086 for (i = 0; list[i]; i++)
1088 if (!WIN_IsCurrentThread( list[i] ))
1090 HWND owner = GetWindow( list[i], GW_OWNER );
1091 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1095 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1096 HeapFree( GetProcessHeap(), 0, list );
1100 /***********************************************************************
1101 * WIN_FixCoordinates
1103 * Fix the coordinates - Helper for WIN_CreateWindowEx.
1104 * returns default show mode in sw.
1106 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1108 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1109 POINT pos[2];
1111 if (cs->dwExStyle & WS_EX_MDICHILD)
1113 UINT id = 0;
1115 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1116 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1118 TRACE("MDI child id %04x\n", id);
1121 if (cs->style & (WS_CHILD | WS_POPUP))
1123 if (cs->dwExStyle & WS_EX_MDICHILD)
1125 if (IS_DEFAULT(cs->x))
1127 cs->x = pos[0].x;
1128 cs->y = pos[0].y;
1130 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1131 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1133 else
1135 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1136 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1139 else /* overlapped window */
1141 HMONITOR monitor;
1142 MONITORINFO mon_info;
1143 STARTUPINFOW info;
1145 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1147 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1148 mon_info.cbSize = sizeof(mon_info);
1149 GetMonitorInfoW( monitor, &mon_info );
1150 GetStartupInfoW( &info );
1152 if (IS_DEFAULT(cs->x))
1154 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1155 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1156 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1159 if (IS_DEFAULT(cs->cx))
1161 if (info.dwFlags & STARTF_USESIZE)
1163 cs->cx = info.dwXSize;
1164 cs->cy = info.dwYSize;
1166 else
1168 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1169 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1172 /* neither x nor cx are default. Check the y values .
1173 * In the trace we see Outlook and Outlook Express using
1174 * cy set to CW_USEDEFAULT when opening the address book.
1176 else if (IS_DEFAULT(cs->cy))
1178 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1179 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1182 #undef IS_DEFAULT
1185 /***********************************************************************
1186 * dump_window_styles
1188 static void dump_window_styles( DWORD style, DWORD exstyle )
1190 TRACE( "style:" );
1191 if(style & WS_POPUP) TRACE(" WS_POPUP");
1192 if(style & WS_CHILD) TRACE(" WS_CHILD");
1193 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1194 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1195 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1196 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1197 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1198 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1199 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1200 else
1202 if(style & WS_BORDER) TRACE(" WS_BORDER");
1203 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1205 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1206 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1207 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1208 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1209 if (style & WS_CHILD)
1211 if(style & WS_GROUP) TRACE(" WS_GROUP");
1212 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1214 else
1216 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1217 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1220 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1221 #define DUMPED_STYLES \
1222 ((DWORD)(WS_POPUP | \
1223 WS_CHILD | \
1224 WS_MINIMIZE | \
1225 WS_VISIBLE | \
1226 WS_DISABLED | \
1227 WS_CLIPSIBLINGS | \
1228 WS_CLIPCHILDREN | \
1229 WS_MAXIMIZE | \
1230 WS_BORDER | \
1231 WS_DLGFRAME | \
1232 WS_VSCROLL | \
1233 WS_HSCROLL | \
1234 WS_SYSMENU | \
1235 WS_THICKFRAME | \
1236 WS_GROUP | \
1237 WS_TABSTOP | \
1238 WS_MINIMIZEBOX | \
1239 WS_MAXIMIZEBOX))
1241 if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1242 TRACE("\n");
1243 #undef DUMPED_STYLES
1245 TRACE( "exstyle:" );
1246 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1247 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1248 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1249 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1250 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1251 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1252 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1253 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1254 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1255 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1256 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1257 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1258 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1259 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1260 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1261 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1262 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1263 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1264 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1266 #define DUMPED_EX_STYLES \
1267 ((DWORD)(WS_EX_DLGMODALFRAME | \
1268 WS_EX_DRAGDETECT | \
1269 WS_EX_NOPARENTNOTIFY | \
1270 WS_EX_TOPMOST | \
1271 WS_EX_ACCEPTFILES | \
1272 WS_EX_TRANSPARENT | \
1273 WS_EX_MDICHILD | \
1274 WS_EX_TOOLWINDOW | \
1275 WS_EX_WINDOWEDGE | \
1276 WS_EX_CLIENTEDGE | \
1277 WS_EX_CONTEXTHELP | \
1278 WS_EX_RIGHT | \
1279 WS_EX_RTLREADING | \
1280 WS_EX_LEFTSCROLLBAR | \
1281 WS_EX_CONTROLPARENT | \
1282 WS_EX_STATICEDGE | \
1283 WS_EX_APPWINDOW | \
1284 WS_EX_LAYERED | \
1285 WS_EX_LAYOUTRTL))
1287 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1288 TRACE("\n");
1289 #undef DUMPED_EX_STYLES
1293 /***********************************************************************
1294 * WIN_CreateWindowEx
1296 * Implementation of CreateWindowEx().
1298 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1300 INT cx, cy, style, sw = SW_SHOW;
1301 LRESULT result;
1302 RECT rect;
1303 WND *wndPtr;
1304 HWND hwnd, parent, owner, top_child = 0;
1305 MDICREATESTRUCTW mdi_cs;
1306 CBT_CREATEWNDW cbtc;
1307 CREATESTRUCTW cbcs;
1309 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1310 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1311 debugstr_w(className),
1312 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1313 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1314 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1316 /* Fix the styles for MDI children */
1317 if (cs->dwExStyle & WS_EX_MDICHILD)
1319 UINT flags = 0;
1321 wndPtr = WIN_GetPtr(cs->hwndParent);
1322 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1324 flags = wndPtr->flags;
1325 WIN_ReleasePtr(wndPtr);
1328 if (!(flags & WIN_ISMDICLIENT))
1330 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1331 return 0;
1334 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1335 * MDICREATESTRUCT members have the originally passed values.
1337 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1338 * have the same layout.
1340 mdi_cs.szClass = cs->lpszClass;
1341 mdi_cs.szTitle = cs->lpszName;
1342 mdi_cs.hOwner = cs->hInstance;
1343 mdi_cs.x = cs->x;
1344 mdi_cs.y = cs->y;
1345 mdi_cs.cx = cs->cx;
1346 mdi_cs.cy = cs->cy;
1347 mdi_cs.style = cs->style;
1348 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1350 cs->lpCreateParams = &mdi_cs;
1352 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1354 if (cs->style & WS_POPUP)
1356 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1357 return 0;
1359 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1361 else
1363 cs->style &= ~WS_POPUP;
1364 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1365 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1368 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1370 if (top_child)
1372 /* Restore current maximized child */
1373 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1375 TRACE("Restoring current maximized child %p\n", top_child);
1376 if (cs->style & WS_MAXIMIZE)
1378 /* if the new window is maximized don't bother repainting */
1379 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1380 ShowWindow( top_child, SW_SHOWNORMAL );
1381 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1383 else ShowWindow( top_child, SW_SHOWNORMAL );
1388 /* Find the parent window */
1390 parent = cs->hwndParent;
1391 owner = 0;
1393 if (cs->hwndParent == HWND_MESSAGE)
1395 cs->hwndParent = parent = get_hwnd_message_parent();
1397 else if (cs->hwndParent)
1399 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1401 parent = GetDesktopWindow();
1402 owner = cs->hwndParent;
1404 else
1406 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1407 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1408 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1411 else
1413 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1415 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1417 WARN("No parent for child window\n" );
1418 SetLastError(ERROR_TLW_WITH_WSCHILD);
1419 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1421 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1422 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1423 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1425 DWORD layout;
1426 GetProcessDefaultLayout( &layout );
1427 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1428 parent = GetDesktopWindow();
1432 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1434 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1435 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1436 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1437 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1438 else
1439 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1441 /* Create the window structure */
1443 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1444 return 0;
1445 hwnd = wndPtr->obj.handle;
1447 /* Fill the window structure */
1449 wndPtr->tid = GetCurrentThreadId();
1450 wndPtr->hInstance = cs->hInstance;
1451 wndPtr->text = NULL;
1452 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1453 wndPtr->dwExStyle = cs->dwExStyle;
1454 wndPtr->wIDmenu = 0;
1455 wndPtr->helpContext = 0;
1456 wndPtr->pScroll = NULL;
1457 wndPtr->userdata = 0;
1458 wndPtr->hIcon = 0;
1459 wndPtr->hIconSmall = 0;
1460 wndPtr->hSysMenu = 0;
1462 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1463 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1465 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1468 * Correct the window styles.
1470 * It affects only the style loaded into the WIN structure.
1473 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1475 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1476 if (!(wndPtr->dwStyle & WS_POPUP))
1477 wndPtr->dwStyle |= WS_CAPTION;
1480 /* WS_EX_WINDOWEDGE depends on some other styles */
1481 if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1482 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1483 else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1485 if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1486 (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1487 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1489 else
1490 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1492 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1493 wndPtr->flags |= WIN_NEED_SIZE;
1495 SERVER_START_REQ( set_window_info )
1497 req->handle = wine_server_user_handle( hwnd );
1498 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1499 req->style = wndPtr->dwStyle;
1500 req->ex_style = wndPtr->dwExStyle;
1501 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1502 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1503 req->extra_offset = -1;
1504 wine_server_call( req );
1506 SERVER_END_REQ;
1508 /* Set the window menu */
1510 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1512 if (cs->hMenu)
1514 if (!MENU_SetMenu(hwnd, cs->hMenu))
1516 WIN_ReleasePtr( wndPtr );
1517 free_window_handle( hwnd );
1518 return 0;
1521 else
1523 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1524 if (menuName)
1526 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1527 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1531 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1533 /* call the WH_CBT hook */
1535 /* the window style passed to the hook must be the real window style,
1536 * rather than just the window style that the caller to CreateWindowEx
1537 * passed in, so we have to copy the original CREATESTRUCT and get the
1538 * the real style. */
1539 cbcs = *cs;
1540 cbcs.style = wndPtr->dwStyle;
1541 cbtc.lpcs = &cbcs;
1542 cbtc.hwndInsertAfter = HWND_TOP;
1543 WIN_ReleasePtr( wndPtr );
1544 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1546 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1548 cx = cs->cx;
1549 cy = cs->cy;
1550 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1552 POINT maxSize, maxPos, minTrack, maxTrack;
1553 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1554 if (maxTrack.x < cx) cx = maxTrack.x;
1555 if (maxTrack.y < cy) cy = maxTrack.y;
1556 if (minTrack.x > cx) cx = minTrack.x;
1557 if (minTrack.y > cy) cy = minTrack.y;
1560 if (cx < 0) cx = 0;
1561 if (cy < 0) cy = 0;
1562 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1563 /* check for wraparound */
1564 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1565 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1566 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1568 /* send WM_NCCREATE */
1570 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1571 if (unicode)
1572 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1573 else
1574 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1575 if (!result)
1577 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1578 goto failed;
1581 /* send WM_NCCALCSIZE */
1583 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1585 /* yes, even if the CBT hook was called with HWND_TOP */
1586 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1587 RECT client_rect = rect;
1589 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1590 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1591 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1592 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1593 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1595 else return 0;
1597 /* send WM_CREATE */
1599 if (unicode)
1600 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1601 else
1602 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1603 if (result == -1) goto failed;
1605 /* call the driver */
1607 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1609 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1611 /* send the size messages */
1613 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1614 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1615 if (!(wndPtr->flags & WIN_NEED_SIZE))
1617 WIN_ReleasePtr( wndPtr );
1618 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1619 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1620 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1621 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1623 else WIN_ReleasePtr( wndPtr );
1625 /* Show the window, maximizing or minimizing if needed */
1627 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1628 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1630 RECT newPos;
1631 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1633 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1634 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1635 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1636 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1637 newPos.bottom - newPos.top, swFlag );
1640 /* Notify the parent window only */
1642 send_parent_notify( hwnd, WM_CREATE );
1643 if (!IsWindow( hwnd )) return 0;
1645 if (cs->style & WS_VISIBLE)
1647 if (cs->style & WS_MAXIMIZE)
1648 sw = SW_SHOW;
1649 else if (cs->style & WS_MINIMIZE)
1650 sw = SW_SHOWMINIMIZED;
1652 ShowWindow( hwnd, sw );
1653 if (cs->dwExStyle & WS_EX_MDICHILD)
1655 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1656 /* ShowWindow won't activate child windows */
1657 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1661 /* Call WH_SHELL hook */
1663 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1664 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1666 TRACE("created window %p\n", hwnd);
1667 return hwnd;
1669 failed:
1670 WIN_DestroyWindow( hwnd );
1671 return 0;
1675 /***********************************************************************
1676 * CreateWindowExA (USER32.@)
1678 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1679 LPCSTR windowName, DWORD style, INT x,
1680 INT y, INT width, INT height,
1681 HWND parent, HMENU menu,
1682 HINSTANCE instance, LPVOID data )
1684 CREATESTRUCTA cs;
1686 cs.lpCreateParams = data;
1687 cs.hInstance = instance;
1688 cs.hMenu = menu;
1689 cs.hwndParent = parent;
1690 cs.x = x;
1691 cs.y = y;
1692 cs.cx = width;
1693 cs.cy = height;
1694 cs.style = style;
1695 cs.lpszName = windowName;
1696 cs.lpszClass = className;
1697 cs.dwExStyle = exStyle;
1699 if (!IS_INTRESOURCE(className))
1701 WCHAR bufferW[256];
1702 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1703 return 0;
1704 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1706 /* Note: we rely on the fact that CREATESTRUCTA and */
1707 /* CREATESTRUCTW have the same layout. */
1708 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1712 /***********************************************************************
1713 * CreateWindowExW (USER32.@)
1715 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1716 LPCWSTR windowName, DWORD style, INT x,
1717 INT y, INT width, INT height,
1718 HWND parent, HMENU menu,
1719 HINSTANCE instance, LPVOID data )
1721 CREATESTRUCTW cs;
1723 cs.lpCreateParams = data;
1724 cs.hInstance = instance;
1725 cs.hMenu = menu;
1726 cs.hwndParent = parent;
1727 cs.x = x;
1728 cs.y = y;
1729 cs.cx = width;
1730 cs.cy = height;
1731 cs.style = style;
1732 cs.lpszName = windowName;
1733 cs.lpszClass = className;
1734 cs.dwExStyle = exStyle;
1736 return wow_handlers.create_window( &cs, className, instance, TRUE );
1740 /***********************************************************************
1741 * WIN_SendDestroyMsg
1743 static void WIN_SendDestroyMsg( HWND hwnd )
1745 GUITHREADINFO info;
1747 info.cbSize = sizeof(info);
1748 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1750 if (hwnd == info.hwndCaret) DestroyCaret();
1751 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1755 * Send the WM_DESTROY to the window.
1757 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1760 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1761 * make sure that the window still exists when we come back.
1763 if (IsWindow(hwnd))
1765 HWND* pWndArray;
1766 int i;
1768 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1770 for (i = 0; pWndArray[i]; i++)
1772 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1774 HeapFree( GetProcessHeap(), 0, pWndArray );
1776 else
1777 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1781 /***********************************************************************
1782 * DestroyWindow (USER32.@)
1784 BOOL WINAPI DestroyWindow( HWND hwnd )
1786 BOOL is_child;
1788 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1790 SetLastError( ERROR_ACCESS_DENIED );
1791 return FALSE;
1794 TRACE("(%p)\n", hwnd);
1796 /* Call hooks */
1798 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1800 if (MENU_IsMenuActive() == hwnd)
1801 EndMenu();
1803 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1805 if (is_child)
1807 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1808 send_parent_notify( hwnd, WM_DESTROY );
1810 else if (!GetWindow( hwnd, GW_OWNER ))
1812 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1813 /* FIXME: clean up palette - see "Internals" p.352 */
1816 if (!IsWindow(hwnd)) return TRUE;
1818 /* Hide the window */
1819 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1821 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1822 if (is_child)
1823 ShowWindow( hwnd, SW_HIDE );
1824 else
1825 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1826 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1829 if (!IsWindow(hwnd)) return TRUE;
1831 /* Recursively destroy owned windows */
1833 if (!is_child)
1835 for (;;)
1837 int i, got_one = 0;
1838 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1839 if (list)
1841 for (i = 0; list[i]; i++)
1843 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1844 if (WIN_IsCurrentThread( list[i] ))
1846 DestroyWindow( list[i] );
1847 got_one = 1;
1848 continue;
1850 WIN_SetOwner( list[i], 0 );
1852 HeapFree( GetProcessHeap(), 0, list );
1854 if (!got_one) break;
1858 /* Send destroy messages */
1860 WIN_SendDestroyMsg( hwnd );
1861 if (!IsWindow( hwnd )) return TRUE;
1863 if (GetClipboardOwner() == hwnd)
1864 CLIPBOARD_ReleaseOwner();
1866 /* Destroy the window storage */
1868 WIN_DestroyWindow( hwnd );
1869 return TRUE;
1873 /***********************************************************************
1874 * CloseWindow (USER32.@)
1876 BOOL WINAPI CloseWindow( HWND hwnd )
1878 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1879 ShowWindow( hwnd, SW_MINIMIZE );
1880 return TRUE;
1884 /***********************************************************************
1885 * OpenIcon (USER32.@)
1887 BOOL WINAPI OpenIcon( HWND hwnd )
1889 if (!IsIconic( hwnd )) return FALSE;
1890 ShowWindow( hwnd, SW_SHOWNORMAL );
1891 return TRUE;
1895 /***********************************************************************
1896 * FindWindowExW (USER32.@)
1898 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1900 HWND *list = NULL;
1901 HWND retvalue = 0;
1902 int i = 0, len = 0;
1903 WCHAR *buffer = NULL;
1905 if (!parent && child) parent = GetDesktopWindow();
1906 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1908 if (title)
1910 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1911 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1914 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1916 if (child)
1918 child = WIN_GetFullHandle( child );
1919 while (list[i] && list[i] != child) i++;
1920 if (!list[i]) goto done;
1921 i++; /* start from next window */
1924 if (title)
1926 while (list[i])
1928 if (GetWindowTextW( list[i], buffer, len + 1 ))
1930 if (!strcmpiW( buffer, title )) break;
1932 else
1934 if (!title[0]) break;
1936 i++;
1939 retvalue = list[i];
1941 done:
1942 HeapFree( GetProcessHeap(), 0, list );
1943 HeapFree( GetProcessHeap(), 0, buffer );
1944 return retvalue;
1949 /***********************************************************************
1950 * FindWindowA (USER32.@)
1952 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1954 HWND ret = FindWindowExA( 0, 0, className, title );
1955 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1956 return ret;
1960 /***********************************************************************
1961 * FindWindowExA (USER32.@)
1963 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1965 LPWSTR titleW = NULL;
1966 HWND hwnd = 0;
1968 if (title)
1970 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1971 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1972 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1975 if (!IS_INTRESOURCE(className))
1977 WCHAR classW[256];
1978 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1979 hwnd = FindWindowExW( parent, child, classW, titleW );
1981 else
1983 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1986 HeapFree( GetProcessHeap(), 0, titleW );
1987 return hwnd;
1991 /***********************************************************************
1992 * FindWindowW (USER32.@)
1994 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1996 return FindWindowExW( 0, 0, className, title );
2000 /**********************************************************************
2001 * GetDesktopWindow (USER32.@)
2003 HWND WINAPI GetDesktopWindow(void)
2005 struct user_thread_info *thread_info = get_user_thread_info();
2007 if (thread_info->top_window) return thread_info->top_window;
2009 SERVER_START_REQ( get_desktop_window )
2011 req->force = 0;
2012 if (!wine_server_call( req ))
2014 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2015 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2018 SERVER_END_REQ;
2020 if (!thread_info->top_window)
2022 USEROBJECTFLAGS flags;
2023 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2024 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2026 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2027 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2028 STARTUPINFOW si;
2029 PROCESS_INFORMATION pi;
2030 WCHAR windir[MAX_PATH];
2031 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2032 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2033 void *redir;
2035 memset( &si, 0, sizeof(si) );
2036 si.cb = sizeof(si);
2037 si.dwFlags = STARTF_USESTDHANDLES;
2038 si.hStdInput = 0;
2039 si.hStdOutput = 0;
2040 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
2042 GetSystemDirectoryW( windir, MAX_PATH );
2043 strcpyW( app, windir );
2044 strcatW( app, explorer );
2045 strcpyW( cmdline, app );
2046 strcatW( cmdline, args );
2048 Wow64DisableWow64FsRedirection( &redir );
2049 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2050 NULL, windir, &si, &pi ))
2052 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2053 WaitForInputIdle( pi.hProcess, 10000 );
2054 CloseHandle( pi.hThread );
2055 CloseHandle( pi.hProcess );
2057 else WARN( "failed to start explorer, err %d\n", GetLastError() );
2058 Wow64RevertWow64FsRedirection( redir );
2060 else TRACE( "not starting explorer since winstation is not visible\n" );
2062 SERVER_START_REQ( get_desktop_window )
2064 req->force = 1;
2065 if (!wine_server_call( req ))
2067 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2068 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2071 SERVER_END_REQ;
2074 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2075 ERR( "failed to create desktop window\n" );
2077 return thread_info->top_window;
2081 /*******************************************************************
2082 * EnableWindow (USER32.@)
2084 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2086 BOOL retvalue;
2087 HWND full_handle;
2089 if (is_broadcast(hwnd))
2091 SetLastError( ERROR_INVALID_PARAMETER );
2092 return FALSE;
2095 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2096 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2098 hwnd = full_handle;
2100 TRACE("( %p, %d )\n", hwnd, enable);
2102 retvalue = !IsWindowEnabled( hwnd );
2104 if (enable && retvalue)
2106 WIN_SetStyle( hwnd, 0, WS_DISABLED );
2107 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2109 else if (!enable && !retvalue)
2111 HWND capture_wnd;
2113 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2115 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2117 if (hwnd == GetFocus())
2118 SetFocus( 0 ); /* A disabled window can't have the focus */
2120 capture_wnd = GetCapture();
2121 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2122 ReleaseCapture(); /* A disabled window can't capture the mouse */
2124 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2126 return retvalue;
2130 /***********************************************************************
2131 * IsWindowEnabled (USER32.@)
2133 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2135 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2139 /***********************************************************************
2140 * IsWindowUnicode (USER32.@)
2142 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2144 WND * wndPtr;
2145 BOOL retvalue = FALSE;
2147 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2149 if (wndPtr == WND_DESKTOP) return TRUE;
2151 if (wndPtr != WND_OTHER_PROCESS)
2153 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2154 WIN_ReleasePtr( wndPtr );
2156 else
2158 SERVER_START_REQ( get_window_info )
2160 req->handle = wine_server_user_handle( hwnd );
2161 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2163 SERVER_END_REQ;
2165 return retvalue;
2169 /**********************************************************************
2170 * WIN_GetWindowLong
2172 * Helper function for GetWindowLong().
2174 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2176 LONG_PTR retvalue = 0;
2177 WND *wndPtr;
2179 if (offset == GWLP_HWNDPARENT)
2181 HWND parent = GetAncestor( hwnd, GA_PARENT );
2182 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2183 return (ULONG_PTR)parent;
2186 if (!(wndPtr = WIN_GetPtr( hwnd )))
2188 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2189 return 0;
2192 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2194 if (offset == GWLP_WNDPROC)
2196 SetLastError( ERROR_ACCESS_DENIED );
2197 return 0;
2199 SERVER_START_REQ( set_window_info )
2201 req->handle = wine_server_user_handle( hwnd );
2202 req->flags = 0; /* don't set anything, just retrieve */
2203 req->extra_offset = (offset >= 0) ? offset : -1;
2204 req->extra_size = (offset >= 0) ? size : 0;
2205 if (!wine_server_call_err( req ))
2207 switch(offset)
2209 case GWL_STYLE: retvalue = reply->old_style; break;
2210 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2211 case GWLP_ID: retvalue = reply->old_id; break;
2212 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2213 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2214 default:
2215 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2216 else SetLastError( ERROR_INVALID_INDEX );
2217 break;
2221 SERVER_END_REQ;
2222 return retvalue;
2225 /* now we have a valid wndPtr */
2227 if (offset >= 0)
2229 if (offset > (int)(wndPtr->cbWndExtra - size))
2231 WARN("Invalid offset %d\n", offset );
2232 WIN_ReleasePtr( wndPtr );
2233 SetLastError( ERROR_INVALID_INDEX );
2234 return 0;
2236 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2238 /* Special case for dialog window procedure */
2239 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2240 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2241 WIN_ReleasePtr( wndPtr );
2242 return retvalue;
2245 switch(offset)
2247 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2248 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2249 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2250 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2251 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2252 case GWLP_WNDPROC:
2253 /* This looks like a hack only for the edit control (see tests). This makes these controls
2254 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2255 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2257 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2258 retvalue = (ULONG_PTR)wndPtr->winproc;
2259 else
2260 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2261 break;
2262 default:
2263 WARN("Unknown offset %d\n", offset );
2264 SetLastError( ERROR_INVALID_INDEX );
2265 break;
2267 WIN_ReleasePtr(wndPtr);
2268 return retvalue;
2272 /**********************************************************************
2273 * WIN_SetWindowLong
2275 * Helper function for SetWindowLong().
2277 * 0 is the failure code. However, in the case of failure SetLastError
2278 * must be set to distinguish between a 0 return value and a failure.
2280 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2282 STYLESTRUCT style;
2283 BOOL ok, made_visible = FALSE;
2284 LONG_PTR retval = 0;
2285 WND *wndPtr;
2287 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2289 if (is_broadcast(hwnd))
2291 SetLastError( ERROR_INVALID_PARAMETER );
2292 return FALSE;
2295 if (!(wndPtr = WIN_GetPtr( hwnd )))
2297 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2298 return 0;
2300 if (wndPtr == WND_DESKTOP)
2302 /* can't change anything on the desktop window */
2303 SetLastError( ERROR_ACCESS_DENIED );
2304 return 0;
2306 if (wndPtr == WND_OTHER_PROCESS)
2308 if (offset == GWLP_WNDPROC)
2310 SetLastError( ERROR_ACCESS_DENIED );
2311 return 0;
2313 if (offset > 32767 || offset < -32767)
2315 SetLastError( ERROR_INVALID_INDEX );
2316 return 0;
2318 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2321 /* first some special cases */
2322 switch( offset )
2324 case GWL_STYLE:
2325 style.styleOld = wndPtr->dwStyle;
2326 style.styleNew = newval;
2327 WIN_ReleasePtr( wndPtr );
2328 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2329 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2330 newval = style.styleNew;
2331 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2332 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2333 /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2334 WS_EX_WINDOWEDGE too */
2335 break;
2336 case GWL_EXSTYLE:
2337 style.styleOld = wndPtr->dwExStyle;
2338 style.styleNew = newval;
2339 WIN_ReleasePtr( wndPtr );
2340 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2341 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2342 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2343 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2344 /* WS_EX_WINDOWEDGE depends on some other styles */
2345 if (newval & WS_EX_DLGMODALFRAME)
2346 newval |= WS_EX_WINDOWEDGE;
2347 else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2348 newval |= WS_EX_WINDOWEDGE;
2349 else
2350 newval &= ~WS_EX_WINDOWEDGE;
2351 break;
2352 case GWLP_HWNDPARENT:
2353 if (wndPtr->parent == GetDesktopWindow())
2355 WIN_ReleasePtr( wndPtr );
2356 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2358 else
2360 WIN_ReleasePtr( wndPtr );
2361 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2363 case GWLP_WNDPROC:
2365 WNDPROC proc;
2366 UINT old_flags = wndPtr->flags;
2367 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2368 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2369 if (proc) wndPtr->winproc = proc;
2370 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2371 else wndPtr->flags &= ~WIN_ISUNICODE;
2372 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2374 WIN_ReleasePtr( wndPtr );
2375 return retval;
2377 /* update is_unicode flag on the server side */
2378 break;
2380 case GWLP_ID:
2381 case GWLP_HINSTANCE:
2382 case GWLP_USERDATA:
2383 break;
2384 case DWLP_DLGPROC:
2385 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2386 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2388 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2389 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2390 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2391 WIN_ReleasePtr( wndPtr );
2392 return retval;
2394 /* fall through */
2395 default:
2396 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2398 WARN("Invalid offset %d\n", offset );
2399 WIN_ReleasePtr( wndPtr );
2400 SetLastError( ERROR_INVALID_INDEX );
2401 return 0;
2403 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2405 /* already set to the same value */
2406 WIN_ReleasePtr( wndPtr );
2407 return newval;
2409 break;
2412 SERVER_START_REQ( set_window_info )
2414 req->handle = wine_server_user_handle( hwnd );
2415 req->extra_offset = -1;
2416 switch(offset)
2418 case GWL_STYLE:
2419 req->flags = SET_WIN_STYLE;
2420 req->style = newval;
2421 break;
2422 case GWL_EXSTYLE:
2423 req->flags = SET_WIN_EXSTYLE;
2424 req->ex_style = newval;
2425 break;
2426 case GWLP_ID:
2427 req->flags = SET_WIN_ID;
2428 req->id = newval;
2429 break;
2430 case GWLP_HINSTANCE:
2431 req->flags = SET_WIN_INSTANCE;
2432 req->instance = wine_server_client_ptr( (void *)newval );
2433 break;
2434 case GWLP_WNDPROC:
2435 req->flags = SET_WIN_UNICODE;
2436 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2437 break;
2438 case GWLP_USERDATA:
2439 req->flags = SET_WIN_USERDATA;
2440 req->user_data = newval;
2441 break;
2442 default:
2443 req->flags = SET_WIN_EXTRA;
2444 req->extra_offset = offset;
2445 req->extra_size = size;
2446 set_win_data( &req->extra_value, newval, size );
2448 if ((ok = !wine_server_call_err( req )))
2450 switch(offset)
2452 case GWL_STYLE:
2453 wndPtr->dwStyle = newval;
2454 retval = reply->old_style;
2455 break;
2456 case GWL_EXSTYLE:
2457 wndPtr->dwExStyle = newval;
2458 retval = reply->old_ex_style;
2459 break;
2460 case GWLP_ID:
2461 wndPtr->wIDmenu = newval;
2462 retval = reply->old_id;
2463 break;
2464 case GWLP_HINSTANCE:
2465 wndPtr->hInstance = (HINSTANCE)newval;
2466 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2467 break;
2468 case GWLP_WNDPROC:
2469 break;
2470 case GWLP_USERDATA:
2471 wndPtr->userdata = newval;
2472 retval = reply->old_user_data;
2473 break;
2474 default:
2475 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2476 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2477 break;
2481 SERVER_END_REQ;
2483 if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2484 (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2486 made_visible = !(wndPtr->flags & WIN_HIDDEN) && (wndPtr->dwStyle & WS_VISIBLE);
2487 invalidate_dce( wndPtr, NULL );
2489 WIN_ReleasePtr( wndPtr );
2491 if (!ok) return 0;
2493 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2495 style.styleOld = retval;
2496 style.styleNew = newval;
2497 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2498 if (made_visible) update_window_state( hwnd );
2499 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2502 return retval;
2506 /**********************************************************************
2507 * GetWindowWord (USER32.@)
2509 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2511 switch(offset)
2513 case GWLP_ID:
2514 case GWLP_HINSTANCE:
2515 case GWLP_HWNDPARENT:
2516 break;
2517 default:
2518 if (offset < 0)
2520 WARN("Invalid offset %d\n", offset );
2521 SetLastError( ERROR_INVALID_INDEX );
2522 return 0;
2524 break;
2526 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2530 /**********************************************************************
2531 * GetWindowLongA (USER32.@)
2533 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2535 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2539 /**********************************************************************
2540 * GetWindowLongW (USER32.@)
2542 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2544 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2548 /**********************************************************************
2549 * SetWindowWord (USER32.@)
2551 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2553 switch(offset)
2555 case GWLP_ID:
2556 case GWLP_HINSTANCE:
2557 case GWLP_HWNDPARENT:
2558 break;
2559 default:
2560 if (offset < 0)
2562 WARN("Invalid offset %d\n", offset );
2563 SetLastError( ERROR_INVALID_INDEX );
2564 return 0;
2566 break;
2568 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2572 /**********************************************************************
2573 * SetWindowLongA (USER32.@)
2575 * See SetWindowLongW.
2577 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2579 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2583 /**********************************************************************
2584 * SetWindowLongW (USER32.@) Set window attribute
2586 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2587 * value in a window's extra memory.
2589 * The _hwnd_ parameter specifies the window. is the handle to a
2590 * window that has extra memory. The _newval_ parameter contains the
2591 * new attribute or extra memory value. If positive, the _offset_
2592 * parameter is the byte-addressed location in the window's extra
2593 * memory to set. If negative, _offset_ specifies the window
2594 * attribute to set, and should be one of the following values:
2596 * GWL_EXSTYLE The window's extended window style
2598 * GWL_STYLE The window's window style.
2600 * GWLP_WNDPROC Pointer to the window's window procedure.
2602 * GWLP_HINSTANCE The window's pplication instance handle.
2604 * GWLP_ID The window's identifier.
2606 * GWLP_USERDATA The window's user-specified data.
2608 * If the window is a dialog box, the _offset_ parameter can be one of
2609 * the following values:
2611 * DWLP_DLGPROC The address of the window's dialog box procedure.
2613 * DWLP_MSGRESULT The return value of a message
2614 * that the dialog box procedure processed.
2616 * DWLP_USER Application specific information.
2618 * RETURNS
2620 * If successful, returns the previous value located at _offset_. Otherwise,
2621 * returns 0.
2623 * NOTES
2625 * Extra memory for a window class is specified by a nonzero cbWndExtra
2626 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2627 * time of class creation.
2629 * Using GWL_WNDPROC to set a new window procedure effectively creates
2630 * a window subclass. Use CallWindowProc() in the new windows procedure
2631 * to pass messages to the superclass's window procedure.
2633 * The user data is reserved for use by the application which created
2634 * the window.
2636 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2637 * instead, call the EnableWindow() function to change the window's
2638 * disabled state.
2640 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2641 * SetParent() instead.
2643 * Win95:
2644 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2645 * it sends WM_STYLECHANGING before changing the settings
2646 * and WM_STYLECHANGED afterwards.
2647 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2649 LONG WINAPI SetWindowLongW(
2650 HWND hwnd, /* [in] window to alter */
2651 INT offset, /* [in] offset, in bytes, of location to alter */
2652 LONG newval /* [in] new value of location */
2654 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2658 /*******************************************************************
2659 * GetWindowTextA (USER32.@)
2661 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2663 WCHAR *buffer;
2665 if (!lpString) return 0;
2667 if (WIN_IsCurrentProcess( hwnd ))
2668 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2670 /* when window belongs to other process, don't send a message */
2671 if (nMaxCount <= 0) return 0;
2672 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2673 get_server_window_text( hwnd, buffer, nMaxCount );
2674 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2675 lpString[nMaxCount-1] = 0;
2676 HeapFree( GetProcessHeap(), 0, buffer );
2677 return strlen(lpString);
2681 /*******************************************************************
2682 * InternalGetWindowText (USER32.@)
2684 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2686 WND *win;
2688 if (nMaxCount <= 0) return 0;
2689 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2690 if (win == WND_DESKTOP) lpString[0] = 0;
2691 else if (win != WND_OTHER_PROCESS)
2693 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2694 else lpString[0] = 0;
2695 WIN_ReleasePtr( win );
2697 else
2699 get_server_window_text( hwnd, lpString, nMaxCount );
2701 return strlenW(lpString);
2705 /*******************************************************************
2706 * GetWindowTextW (USER32.@)
2708 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2710 if (!lpString) return 0;
2712 if (WIN_IsCurrentProcess( hwnd ))
2713 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2715 /* when window belongs to other process, don't send a message */
2716 if (nMaxCount <= 0) return 0;
2717 get_server_window_text( hwnd, lpString, nMaxCount );
2718 return strlenW(lpString);
2722 /*******************************************************************
2723 * SetWindowTextA (USER32.@)
2724 * SetWindowText (USER32.@)
2726 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2728 if (is_broadcast(hwnd))
2730 SetLastError( ERROR_INVALID_PARAMETER );
2731 return FALSE;
2733 if (!WIN_IsCurrentProcess( hwnd ))
2734 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2735 debugstr_a(lpString), hwnd );
2736 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2740 /*******************************************************************
2741 * SetWindowTextW (USER32.@)
2743 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2745 if (is_broadcast(hwnd))
2747 SetLastError( ERROR_INVALID_PARAMETER );
2748 return FALSE;
2750 if (!WIN_IsCurrentProcess( hwnd ))
2751 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2752 debugstr_w(lpString), hwnd );
2753 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2757 /*******************************************************************
2758 * GetWindowTextLengthA (USER32.@)
2760 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2762 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2765 /*******************************************************************
2766 * GetWindowTextLengthW (USER32.@)
2768 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2770 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2774 /*******************************************************************
2775 * IsWindow (USER32.@)
2777 BOOL WINAPI IsWindow( HWND hwnd )
2779 WND *ptr;
2780 BOOL ret;
2782 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2783 if (ptr == WND_DESKTOP) return TRUE;
2785 if (ptr != WND_OTHER_PROCESS)
2787 WIN_ReleasePtr( ptr );
2788 return TRUE;
2791 /* check other processes */
2792 SERVER_START_REQ( get_window_info )
2794 req->handle = wine_server_user_handle( hwnd );
2795 ret = !wine_server_call_err( req );
2797 SERVER_END_REQ;
2798 return ret;
2802 /***********************************************************************
2803 * GetWindowThreadProcessId (USER32.@)
2805 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2807 WND *ptr;
2808 DWORD tid = 0;
2810 if (!(ptr = WIN_GetPtr( hwnd )))
2812 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2813 return 0;
2816 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2818 /* got a valid window */
2819 tid = ptr->tid;
2820 if (process) *process = GetCurrentProcessId();
2821 WIN_ReleasePtr( ptr );
2822 return tid;
2825 /* check other processes */
2826 SERVER_START_REQ( get_window_info )
2828 req->handle = wine_server_user_handle( hwnd );
2829 if (!wine_server_call_err( req ))
2831 tid = (DWORD)reply->tid;
2832 if (process) *process = (DWORD)reply->pid;
2835 SERVER_END_REQ;
2836 return tid;
2840 /*****************************************************************
2841 * GetParent (USER32.@)
2843 HWND WINAPI GetParent( HWND hwnd )
2845 WND *wndPtr;
2846 HWND retvalue = 0;
2848 if (!(wndPtr = WIN_GetPtr( hwnd )))
2850 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2851 return 0;
2853 if (wndPtr == WND_DESKTOP) return 0;
2854 if (wndPtr == WND_OTHER_PROCESS)
2856 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2857 if (style & (WS_POPUP | WS_CHILD))
2859 SERVER_START_REQ( get_window_tree )
2861 req->handle = wine_server_user_handle( hwnd );
2862 if (!wine_server_call_err( req ))
2864 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2865 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2868 SERVER_END_REQ;
2871 else
2873 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2874 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2875 WIN_ReleasePtr( wndPtr );
2877 return retvalue;
2881 /*****************************************************************
2882 * GetAncestor (USER32.@)
2884 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2886 WND *win;
2887 HWND *list, ret = 0;
2889 switch(type)
2891 case GA_PARENT:
2892 if (!(win = WIN_GetPtr( hwnd )))
2894 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2895 return 0;
2897 if (win == WND_DESKTOP) return 0;
2898 if (win != WND_OTHER_PROCESS)
2900 ret = win->parent;
2901 WIN_ReleasePtr( win );
2903 else /* need to query the server */
2905 SERVER_START_REQ( get_window_tree )
2907 req->handle = wine_server_user_handle( hwnd );
2908 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2910 SERVER_END_REQ;
2912 break;
2914 case GA_ROOT:
2915 if (!(list = list_window_parents( hwnd ))) return 0;
2917 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2918 else
2920 int count = 2;
2921 while (list[count]) count++;
2922 ret = list[count - 2]; /* get the one before the desktop */
2924 HeapFree( GetProcessHeap(), 0, list );
2925 break;
2927 case GA_ROOTOWNER:
2928 if (is_desktop_window( hwnd )) return 0;
2929 ret = WIN_GetFullHandle( hwnd );
2930 for (;;)
2932 HWND parent = GetParent( ret );
2933 if (!parent) break;
2934 ret = parent;
2936 break;
2938 return ret;
2942 /*****************************************************************
2943 * SetParent (USER32.@)
2945 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2947 HWND full_handle;
2948 HWND old_parent = 0;
2949 BOOL was_visible;
2950 WND *wndPtr;
2951 POINT pt;
2952 BOOL ret;
2954 if (is_broadcast(hwnd) || is_broadcast(parent))
2956 SetLastError(ERROR_INVALID_PARAMETER);
2957 return 0;
2960 if (!parent) parent = GetDesktopWindow();
2961 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2962 else parent = WIN_GetFullHandle( parent );
2964 if (!IsWindow( parent ))
2966 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2967 return 0;
2970 /* Some applications try to set a child as a parent */
2971 if (IsChild(hwnd, parent))
2973 SetLastError( ERROR_INVALID_PARAMETER );
2974 return 0;
2977 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2978 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2980 if (full_handle == parent)
2982 SetLastError( ERROR_INVALID_PARAMETER );
2983 return 0;
2986 /* Windows hides the window first, then shows it again
2987 * including the WM_SHOWWINDOW messages and all */
2988 was_visible = ShowWindow( hwnd, SW_HIDE );
2990 wndPtr = WIN_GetPtr( hwnd );
2991 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2993 pt.x = wndPtr->rectWindow.left;
2994 pt.y = wndPtr->rectWindow.top;
2996 SERVER_START_REQ( set_parent )
2998 req->handle = wine_server_user_handle( hwnd );
2999 req->parent = wine_server_user_handle( parent );
3000 if ((ret = !wine_server_call( req )))
3002 old_parent = wine_server_ptr_handle( reply->old_parent );
3003 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3007 SERVER_END_REQ;
3008 WIN_ReleasePtr( wndPtr );
3009 if (!ret) return 0;
3011 USER_Driver->pSetParent( full_handle, parent, old_parent );
3013 /* SetParent additionally needs to make hwnd the topmost window
3014 in the x-order and send the expected WM_WINDOWPOSCHANGING and
3015 WM_WINDOWPOSCHANGED notification messages.
3017 SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3019 if (was_visible) ShowWindow( hwnd, SW_SHOW );
3021 return old_parent;
3025 /*******************************************************************
3026 * IsChild (USER32.@)
3028 BOOL WINAPI IsChild( HWND parent, HWND child )
3030 HWND *list = list_window_parents( child );
3031 int i;
3032 BOOL ret;
3034 if (!list) return FALSE;
3035 parent = WIN_GetFullHandle( parent );
3036 for (i = 0; list[i]; i++) if (list[i] == parent) break;
3037 ret = list[i] && list[i+1];
3038 HeapFree( GetProcessHeap(), 0, list );
3039 return ret;
3043 /***********************************************************************
3044 * IsWindowVisible (USER32.@)
3046 BOOL WINAPI IsWindowVisible( HWND hwnd )
3048 HWND *list;
3049 BOOL retval = TRUE;
3050 int i;
3052 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3053 if (!(list = list_window_parents( hwnd ))) return TRUE;
3054 if (list[0])
3056 for (i = 0; list[i+1]; i++)
3057 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3058 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3060 HeapFree( GetProcessHeap(), 0, list );
3061 return retval;
3065 /***********************************************************************
3066 * WIN_IsWindowDrawable
3068 * hwnd is drawable when it is visible, all parents are not
3069 * minimized, and it is itself not minimized unless we are
3070 * trying to draw its default class icon.
3072 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3074 HWND *list;
3075 BOOL retval = TRUE;
3076 int i;
3077 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3079 if (!(style & WS_VISIBLE)) return FALSE;
3080 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
3082 if (!(list = list_window_parents( hwnd ))) return TRUE;
3083 if (list[0])
3085 for (i = 0; list[i+1]; i++)
3086 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3087 break;
3088 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
3090 HeapFree( GetProcessHeap(), 0, list );
3091 return retval;
3095 /*******************************************************************
3096 * GetTopWindow (USER32.@)
3098 HWND WINAPI GetTopWindow( HWND hwnd )
3100 if (!hwnd) hwnd = GetDesktopWindow();
3101 return GetWindow( hwnd, GW_CHILD );
3105 /*******************************************************************
3106 * GetWindow (USER32.@)
3108 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3110 HWND retval = 0;
3112 if (rel == GW_OWNER) /* this one may be available locally */
3114 WND *wndPtr = WIN_GetPtr( hwnd );
3115 if (!wndPtr)
3117 SetLastError( ERROR_INVALID_HANDLE );
3118 return 0;
3120 if (wndPtr == WND_DESKTOP) return 0;
3121 if (wndPtr != WND_OTHER_PROCESS)
3123 retval = wndPtr->owner;
3124 WIN_ReleasePtr( wndPtr );
3125 return retval;
3127 /* else fall through to server call */
3130 SERVER_START_REQ( get_window_tree )
3132 req->handle = wine_server_user_handle( hwnd );
3133 if (!wine_server_call_err( req ))
3135 switch(rel)
3137 case GW_HWNDFIRST:
3138 retval = wine_server_ptr_handle( reply->first_sibling );
3139 break;
3140 case GW_HWNDLAST:
3141 retval = wine_server_ptr_handle( reply->last_sibling );
3142 break;
3143 case GW_HWNDNEXT:
3144 retval = wine_server_ptr_handle( reply->next_sibling );
3145 break;
3146 case GW_HWNDPREV:
3147 retval = wine_server_ptr_handle( reply->prev_sibling );
3148 break;
3149 case GW_OWNER:
3150 retval = wine_server_ptr_handle( reply->owner );
3151 break;
3152 case GW_CHILD:
3153 retval = wine_server_ptr_handle( reply->first_child );
3154 break;
3158 SERVER_END_REQ;
3159 return retval;
3163 /*******************************************************************
3164 * ShowOwnedPopups (USER32.@)
3166 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3168 int count = 0;
3169 WND *pWnd;
3170 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3172 if (!win_array) return TRUE;
3174 while (win_array[count]) count++;
3175 while (--count >= 0)
3177 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3178 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3179 if (pWnd == WND_OTHER_PROCESS) continue;
3180 if (fShow)
3182 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3184 WIN_ReleasePtr( pWnd );
3185 /* In Windows, ShowOwnedPopups(TRUE) generates
3186 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3187 * regardless of the state of the owner
3189 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3190 continue;
3193 else
3195 if (pWnd->dwStyle & WS_VISIBLE)
3197 WIN_ReleasePtr( pWnd );
3198 /* In Windows, ShowOwnedPopups(FALSE) generates
3199 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3200 * regardless of the state of the owner
3202 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3203 continue;
3206 WIN_ReleasePtr( pWnd );
3208 HeapFree( GetProcessHeap(), 0, win_array );
3209 return TRUE;
3213 /*******************************************************************
3214 * GetLastActivePopup (USER32.@)
3216 HWND WINAPI GetLastActivePopup( HWND hwnd )
3218 HWND retval = hwnd;
3220 SERVER_START_REQ( get_window_info )
3222 req->handle = wine_server_user_handle( hwnd );
3223 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3225 SERVER_END_REQ;
3226 return retval;
3230 /*******************************************************************
3231 * WIN_ListChildren
3233 * Build an array of the children of a given window. The array must be
3234 * freed with HeapFree. Returns NULL when no windows are found.
3236 HWND *WIN_ListChildren( HWND hwnd )
3238 if (!hwnd)
3240 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3241 return NULL;
3243 return list_window_children( 0, hwnd, NULL, 0 );
3247 /*******************************************************************
3248 * EnumWindows (USER32.@)
3250 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3252 HWND *list;
3253 BOOL ret = TRUE;
3254 int i;
3256 USER_CheckNotLock();
3258 /* We have to build a list of all windows first, to avoid */
3259 /* unpleasant side-effects, for instance if the callback */
3260 /* function changes the Z-order of the windows. */
3262 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3264 /* Now call the callback function for every window */
3266 for (i = 0; list[i]; i++)
3268 /* Make sure that the window still exists */
3269 if (!IsWindow( list[i] )) continue;
3270 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3272 HeapFree( GetProcessHeap(), 0, list );
3273 return ret;
3277 /**********************************************************************
3278 * EnumThreadWindows (USER32.@)
3280 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3282 HWND *list;
3283 int i;
3284 BOOL ret = TRUE;
3286 USER_CheckNotLock();
3288 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3290 /* Now call the callback function for every window */
3292 for (i = 0; list[i]; i++)
3293 if (!(ret = func( list[i], lParam ))) break;
3294 HeapFree( GetProcessHeap(), 0, list );
3295 return ret;
3299 /***********************************************************************
3300 * EnumDesktopWindows (USER32.@)
3302 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3304 HWND *list;
3305 int i;
3307 USER_CheckNotLock();
3309 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3311 for (i = 0; list[i]; i++)
3312 if (!func( list[i], lparam )) break;
3313 HeapFree( GetProcessHeap(), 0, list );
3314 return TRUE;
3318 /**********************************************************************
3319 * WIN_EnumChildWindows
3321 * Helper function for EnumChildWindows().
3323 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3325 HWND *childList;
3326 BOOL ret = FALSE;
3328 for ( ; *list; list++)
3330 /* Make sure that the window still exists */
3331 if (!IsWindow( *list )) continue;
3332 /* Build children list first */
3333 childList = WIN_ListChildren( *list );
3335 ret = func( *list, lParam );
3337 if (childList)
3339 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3340 HeapFree( GetProcessHeap(), 0, childList );
3342 if (!ret) return FALSE;
3344 return TRUE;
3348 /**********************************************************************
3349 * EnumChildWindows (USER32.@)
3351 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3353 HWND *list;
3354 BOOL ret;
3356 USER_CheckNotLock();
3358 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3359 ret = WIN_EnumChildWindows( list, func, lParam );
3360 HeapFree( GetProcessHeap(), 0, list );
3361 return ret;
3365 /*******************************************************************
3366 * AnyPopup (USER32.@)
3368 BOOL WINAPI AnyPopup(void)
3370 int i;
3371 BOOL retvalue;
3372 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3374 if (!list) return FALSE;
3375 for (i = 0; list[i]; i++)
3377 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3379 retvalue = (list[i] != 0);
3380 HeapFree( GetProcessHeap(), 0, list );
3381 return retvalue;
3385 /*******************************************************************
3386 * FlashWindow (USER32.@)
3388 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3390 WND *wndPtr;
3392 TRACE("%p\n", hWnd);
3394 if (IsIconic( hWnd ))
3396 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3398 wndPtr = WIN_GetPtr(hWnd);
3399 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3400 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3402 wndPtr->flags |= WIN_NCACTIVATED;
3404 else
3406 wndPtr->flags &= ~WIN_NCACTIVATED;
3408 WIN_ReleasePtr( wndPtr );
3409 return TRUE;
3411 else
3413 WPARAM wparam;
3415 wndPtr = WIN_GetPtr(hWnd);
3416 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3417 hWnd = wndPtr->obj.handle; /* make it a full handle */
3419 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3420 else wparam = (hWnd == GetForegroundWindow());
3422 WIN_ReleasePtr( wndPtr );
3423 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3424 return wparam;
3428 /*******************************************************************
3429 * FlashWindowEx (USER32.@)
3431 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3433 FIXME("%p\n", pfwi);
3434 return TRUE;
3437 /*******************************************************************
3438 * GetWindowContextHelpId (USER32.@)
3440 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3442 DWORD retval;
3443 WND *wnd = WIN_GetPtr( hwnd );
3444 if (!wnd || wnd == WND_DESKTOP) return 0;
3445 if (wnd == WND_OTHER_PROCESS)
3447 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3448 return 0;
3450 retval = wnd->helpContext;
3451 WIN_ReleasePtr( wnd );
3452 return retval;
3456 /*******************************************************************
3457 * SetWindowContextHelpId (USER32.@)
3459 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3461 WND *wnd = WIN_GetPtr( hwnd );
3462 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3463 if (wnd == WND_OTHER_PROCESS)
3465 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3466 return 0;
3468 wnd->helpContext = id;
3469 WIN_ReleasePtr( wnd );
3470 return TRUE;
3474 /*******************************************************************
3475 * DragDetect (USER32.@)
3477 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3479 MSG msg;
3480 RECT rect;
3481 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3482 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3484 rect.left = pt.x - wDragWidth;
3485 rect.right = pt.x + wDragWidth;
3487 rect.top = pt.y - wDragHeight;
3488 rect.bottom = pt.y + wDragHeight;
3490 SetCapture(hWnd);
3492 while(1)
3494 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3496 if( msg.message == WM_LBUTTONUP )
3498 ReleaseCapture();
3499 return 0;
3501 if( msg.message == WM_MOUSEMOVE )
3503 POINT tmp;
3504 tmp.x = (short)LOWORD(msg.lParam);
3505 tmp.y = (short)HIWORD(msg.lParam);
3506 if( !PtInRect( &rect, tmp ))
3508 ReleaseCapture();
3509 return 1;
3513 WaitMessage();
3515 return 0;
3518 /******************************************************************************
3519 * GetWindowModuleFileNameA (USER32.@)
3521 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3523 WND *win;
3524 HINSTANCE hinst;
3526 TRACE( "%p, %p, %u\n", hwnd, module, size );
3528 win = WIN_GetPtr( hwnd );
3529 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3531 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3532 return 0;
3534 hinst = win->hInstance;
3535 WIN_ReleasePtr( win );
3537 return GetModuleFileNameA( hinst, module, size );
3540 /******************************************************************************
3541 * GetWindowModuleFileNameW (USER32.@)
3543 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3545 WND *win;
3546 HINSTANCE hinst;
3548 TRACE( "%p, %p, %u\n", hwnd, module, size );
3550 win = WIN_GetPtr( hwnd );
3551 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3553 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3554 return 0;
3556 hinst = win->hInstance;
3557 WIN_ReleasePtr( win );
3559 return GetModuleFileNameW( hinst, module, size );
3562 /******************************************************************************
3563 * GetWindowInfo (USER32.@)
3565 * Note: tests show that Windows doesn't check cbSize of the structure.
3567 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3569 if (!pwi) return FALSE;
3570 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3572 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3573 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3574 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3576 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3577 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3579 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3580 pwi->wCreatorVersion = 0x0400;
3582 return TRUE;
3585 /******************************************************************************
3586 * SwitchDesktop (USER32.@)
3588 * NOTES: Sets the current input or interactive desktop.
3590 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3592 FIXME("(hwnd %p) stub!\n", hDesktop);
3593 return TRUE;
3597 /***********************************************************************
3598 * __wine_set_pixel_format
3600 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3602 WND *win = WIN_GetPtr( hwnd );
3604 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3606 WARN( "setting format %d on win %p not supported\n", format, hwnd );
3607 return FALSE;
3609 win->pixel_format = format;
3610 WIN_ReleasePtr( win );
3612 update_window_state( hwnd );
3613 return TRUE;
3617 /*****************************************************************************
3618 * SetLayeredWindowAttributes (USER32.@)
3620 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3622 BOOL ret;
3624 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3626 SERVER_START_REQ( set_window_layered_info )
3628 req->handle = wine_server_user_handle( hwnd );
3629 req->color_key = key;
3630 req->alpha = alpha;
3631 req->flags = flags;
3632 ret = !wine_server_call_err( req );
3634 SERVER_END_REQ;
3636 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3638 return ret;
3642 /*****************************************************************************
3643 * GetLayeredWindowAttributes (USER32.@)
3645 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3647 BOOL ret;
3649 SERVER_START_REQ( get_window_layered_info )
3651 req->handle = wine_server_user_handle( hwnd );
3652 if ((ret = !wine_server_call_err( req )))
3654 if (key) *key = reply->color_key;
3655 if (alpha) *alpha = reply->alpha;
3656 if (flags) *flags = reply->flags;
3659 SERVER_END_REQ;
3661 return ret;
3665 /*****************************************************************************
3666 * UpdateLayeredWindowIndirect (USER32.@)
3668 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3670 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3671 RECT window_rect, client_rect;
3672 SIZE offset;
3674 if (!info ||
3675 info->cbSize != sizeof(*info) ||
3676 info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3677 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3678 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3680 SetLastError( ERROR_INVALID_PARAMETER );
3681 return FALSE;
3684 WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3686 if (info->pptDst)
3688 offset.cx = info->pptDst->x - window_rect.left;
3689 offset.cy = info->pptDst->y - window_rect.top;
3690 OffsetRect( &client_rect, offset.cx, offset.cy );
3691 OffsetRect( &window_rect, offset.cx, offset.cy );
3692 flags &= ~SWP_NOMOVE;
3694 if (info->psize)
3696 offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3697 offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3698 if (info->psize->cx <= 0 || info->psize->cy <= 0)
3700 SetLastError( ERROR_INVALID_PARAMETER );
3701 return FALSE;
3703 if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3705 SetLastError( ERROR_INCORRECT_SIZE );
3706 return FALSE;
3708 client_rect.right += offset.cx;
3709 client_rect.bottom += offset.cy;
3710 window_rect.right += offset.cx;
3711 window_rect.bottom += offset.cy;
3712 flags &= ~SWP_NOSIZE;
3715 TRACE( "window %p win %s client %s\n", hwnd,
3716 wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3718 if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3720 set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3721 return TRUE;
3725 /*****************************************************************************
3726 * UpdateLayeredWindow (USER32.@)
3728 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3729 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3730 DWORD flags)
3732 UPDATELAYEREDWINDOWINFO info;
3734 if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
3736 SetLastError( ERROR_INVALID_PARAMETER );
3737 return FALSE;
3739 info.cbSize = sizeof(info);
3740 info.hdcDst = hdcDst;
3741 info.pptDst = pptDst;
3742 info.psize = psize;
3743 info.hdcSrc = hdcSrc;
3744 info.pptSrc = pptSrc;
3745 info.crKey = crKey;
3746 info.pblend = pblend;
3747 info.dwFlags = flags;
3748 info.prcDirty = NULL;
3749 return UpdateLayeredWindowIndirect( hwnd, &info );
3753 /******************************************************************************
3754 * GetProcessDefaultLayout [USER32.@]
3756 * Gets the default layout for parentless windows.
3758 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3760 if (!layout)
3762 SetLastError( ERROR_NOACCESS );
3763 return FALSE;
3765 if (process_layout == ~0u)
3767 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3768 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3769 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3770 '\\','%','0','4','x','%','0','4','x',
3771 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3772 WCHAR *str, buffer[MAX_PATH];
3773 DWORD i, len, version_layout = 0;
3774 DWORD user_lang = GetUserDefaultLangID();
3775 DWORD *languages;
3776 void *data = NULL;
3778 GetModuleFileNameW( 0, buffer, MAX_PATH );
3779 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3780 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3781 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3782 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3784 len /= sizeof(DWORD);
3785 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3786 if (i == len) /* try neutral language */
3787 for (i = 0; i < len; i++)
3788 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3789 if (i == len) i = 0; /* default to the first one */
3791 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3792 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3793 TRACE( "found description %s\n", debugstr_w( str ));
3794 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3796 done:
3797 HeapFree( GetProcessHeap(), 0, data );
3798 process_layout = version_layout;
3800 *layout = process_layout;
3801 return TRUE;
3805 /******************************************************************************
3806 * SetProcessDefaultLayout [USER32.@]
3808 * Sets the default layout for parentless windows.
3810 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3812 process_layout = layout;
3813 return TRUE;
3817 /* 64bit versions */
3819 #ifdef GetWindowLongPtrW
3820 #undef GetWindowLongPtrW
3821 #endif
3823 #ifdef GetWindowLongPtrA
3824 #undef GetWindowLongPtrA
3825 #endif
3827 #ifdef SetWindowLongPtrW
3828 #undef SetWindowLongPtrW
3829 #endif
3831 #ifdef SetWindowLongPtrA
3832 #undef SetWindowLongPtrA
3833 #endif
3835 /*****************************************************************************
3836 * GetWindowLongPtrW (USER32.@)
3838 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3840 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3843 /*****************************************************************************
3844 * GetWindowLongPtrA (USER32.@)
3846 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3848 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3851 /*****************************************************************************
3852 * SetWindowLongPtrW (USER32.@)
3854 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3856 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3859 /*****************************************************************************
3860 * SetWindowLongPtrA (USER32.@)
3862 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3864 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );