user32: Check structure size in GetGUIThreadInfo.
[wine/multimedia.git] / dlls / user32 / win.c
blobf1da48b45b6feaae064f2cbebdaa7f0d1f96a393
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/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(win);
41 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
42 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
44 static DWORD process_layout = ~0u;
46 /**********************************************************************/
48 /* helper for Get/SetWindowLong */
49 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 if (size == sizeof(WORD))
53 WORD ret;
54 memcpy( &ret, ptr, sizeof(ret) );
55 return ret;
57 else if (size == sizeof(DWORD))
59 DWORD ret;
60 memcpy( &ret, ptr, sizeof(ret) );
61 return ret;
63 else
65 LONG_PTR ret;
66 memcpy( &ret, ptr, sizeof(ret) );
67 return ret;
71 /* helper for Get/SetWindowLong */
72 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 if (size == sizeof(WORD))
76 WORD newval = val;
77 memcpy( ptr, &newval, sizeof(newval) );
79 else if (size == sizeof(DWORD))
81 DWORD newval = val;
82 memcpy( ptr, &newval, sizeof(newval) );
84 else
86 memcpy( ptr, &val, sizeof(val) );
91 static void *user_handles[NB_USER_HANDLES];
93 /***********************************************************************
94 * alloc_user_handle
96 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
98 HANDLE handle = 0;
100 SERVER_START_REQ( alloc_user_handle )
102 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
104 SERVER_END_REQ;
106 if (handle)
108 UINT index = USER_HANDLE_TO_INDEX( handle );
110 assert( index < NB_USER_HANDLES );
111 ptr->handle = handle;
112 ptr->type = type;
113 InterlockedExchangePointer( &user_handles[index], ptr );
115 return handle;
119 /***********************************************************************
120 * get_user_handle_ptr
122 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
124 struct user_object *ptr;
125 WORD index = USER_HANDLE_TO_INDEX( handle );
127 if (index >= NB_USER_HANDLES) return NULL;
129 USER_Lock();
130 if ((ptr = user_handles[index]))
132 if (ptr->type == type &&
133 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
134 !HIWORD(handle) || HIWORD(handle) == 0xffff))
135 return ptr;
136 ptr = NULL;
138 else ptr = OBJ_OTHER_PROCESS;
139 USER_Unlock();
140 return ptr;
144 /***********************************************************************
145 * release_user_handle_ptr
147 void release_user_handle_ptr( void *ptr )
149 assert( ptr && ptr != OBJ_OTHER_PROCESS );
150 USER_Unlock();
154 /***********************************************************************
155 * free_user_handle
157 void *free_user_handle( HANDLE handle, enum user_obj_type type )
159 struct user_object *ptr;
160 WORD index = USER_HANDLE_TO_INDEX( handle );
162 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
164 SERVER_START_REQ( free_user_handle )
166 req->handle = wine_server_user_handle( handle );
167 if (wine_server_call( req )) ptr = NULL;
168 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
170 SERVER_END_REQ;
171 release_user_handle_ptr( ptr );
173 return ptr;
177 /***********************************************************************
178 * create_window_handle
180 * Create a window handle with the server.
182 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
183 HINSTANCE instance, BOOL unicode )
185 WORD index;
186 WND *win;
187 HWND handle = 0, full_parent = 0, full_owner = 0;
188 struct tagCLASS *class = NULL;
189 int extra_bytes = 0;
191 SERVER_START_REQ( create_window )
193 req->parent = wine_server_user_handle( parent );
194 req->owner = wine_server_user_handle( owner );
195 req->instance = wine_server_client_ptr( instance );
196 if (!(req->atom = get_int_atom_value( name )) && name)
197 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
198 if (!wine_server_call_err( req ))
200 handle = wine_server_ptr_handle( reply->handle );
201 full_parent = wine_server_ptr_handle( reply->parent );
202 full_owner = wine_server_ptr_handle( reply->owner );
203 extra_bytes = reply->extra;
204 class = wine_server_get_ptr( reply->class_ptr );
207 SERVER_END_REQ;
209 if (!handle)
211 WARN( "error %d creating window\n", GetLastError() );
212 return NULL;
215 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
216 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
218 SERVER_START_REQ( destroy_window )
220 req->handle = wine_server_user_handle( handle );
221 wine_server_call( req );
223 SERVER_END_REQ;
224 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
225 return NULL;
228 if (!parent) /* if parent is 0 we don't have a desktop window yet */
230 struct user_thread_info *thread_info = get_user_thread_info();
232 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
234 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
235 else assert( full_parent == thread_info->top_window );
236 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
237 ERR( "failed to create desktop window\n" );
239 else /* HWND_MESSAGE parent */
241 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
245 USER_Lock();
247 index = USER_HANDLE_TO_INDEX(handle);
248 assert( index < NB_USER_HANDLES );
249 win->obj.handle = handle;
250 win->obj.type = USER_WINDOW;
251 win->parent = full_parent;
252 win->owner = full_owner;
253 win->class = class;
254 win->winproc = get_class_winproc( class );
255 win->cbWndExtra = extra_bytes;
256 InterlockedExchangePointer( &user_handles[index], win );
257 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
258 return win;
262 /***********************************************************************
263 * free_window_handle
265 * Free a window handle.
267 static void free_window_handle( HWND hwnd )
269 struct user_object *ptr;
270 WORD index = USER_HANDLE_TO_INDEX(hwnd);
272 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
274 SERVER_START_REQ( destroy_window )
276 req->handle = wine_server_user_handle( hwnd );
277 if (wine_server_call_err( req )) ptr = NULL;
278 else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
280 SERVER_END_REQ;
281 release_user_handle_ptr( ptr );
282 HeapFree( GetProcessHeap(), 0, ptr );
287 /*******************************************************************
288 * list_window_children
290 * Build an array of the children of a given window. The array must be
291 * freed with HeapFree. Returns NULL when no windows are found.
293 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
295 HWND *list;
296 int i, size = 128;
297 ATOM atom = get_int_atom_value( class );
299 /* empty class is not the same as NULL class */
300 if (!atom && class && !class[0]) return NULL;
302 for (;;)
304 int count = 0;
306 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
308 SERVER_START_REQ( get_window_children )
310 req->desktop = wine_server_obj_handle( desktop );
311 req->parent = wine_server_user_handle( hwnd );
312 req->tid = tid;
313 req->atom = atom;
314 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
315 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
316 if (!wine_server_call( req )) count = reply->count;
318 SERVER_END_REQ;
319 if (count && count < size)
321 /* start from the end since HWND is potentially larger than user_handle_t */
322 for (i = count - 1; i >= 0; i--)
323 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
324 list[count] = 0;
325 return list;
327 HeapFree( GetProcessHeap(), 0, list );
328 if (!count) break;
329 size = count + 1; /* restart with a large enough buffer */
331 return NULL;
335 /*******************************************************************
336 * list_window_parents
338 * Build an array of all parents of a given window, starting with
339 * the immediate parent. The array must be freed with HeapFree.
341 static HWND *list_window_parents( HWND hwnd )
343 WND *win;
344 HWND current, *list;
345 int i, pos = 0, size = 16, count = 0;
347 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
349 current = hwnd;
350 for (;;)
352 if (!(win = WIN_GetPtr( current ))) goto empty;
353 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
354 if (win == WND_DESKTOP)
356 if (!pos) goto empty;
357 list[pos] = 0;
358 return list;
360 list[pos] = current = win->parent;
361 WIN_ReleasePtr( win );
362 if (!current) return list;
363 if (++pos == size - 1)
365 /* need to grow the list */
366 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
367 if (!new_list) goto empty;
368 list = new_list;
369 size += 16;
373 /* at least one parent belongs to another process, have to query the server */
375 for (;;)
377 count = 0;
378 SERVER_START_REQ( get_window_parents )
380 req->handle = wine_server_user_handle( hwnd );
381 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
382 if (!wine_server_call( req )) count = reply->count;
384 SERVER_END_REQ;
385 if (!count) goto empty;
386 if (size > count)
388 /* start from the end since HWND is potentially larger than user_handle_t */
389 for (i = count - 1; i >= 0; i--)
390 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
391 list[count] = 0;
392 return list;
394 HeapFree( GetProcessHeap(), 0, list );
395 size = count + 1;
396 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
399 empty:
400 HeapFree( GetProcessHeap(), 0, list );
401 return NULL;
405 /*******************************************************************
406 * send_parent_notify
408 static void send_parent_notify( HWND hwnd, UINT msg )
410 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
411 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
413 HWND parent = GetParent(hwnd);
414 if (parent && parent != GetDesktopWindow())
415 SendMessageW( parent, WM_PARENTNOTIFY,
416 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
421 /*******************************************************************
422 * get_server_window_text
424 * Retrieve the window text from the server.
426 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
428 size_t len = 0;
430 SERVER_START_REQ( get_window_text )
432 req->handle = wine_server_user_handle( hwnd );
433 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
434 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
436 SERVER_END_REQ;
437 text[len / sizeof(WCHAR)] = 0;
441 /*******************************************************************
442 * get_hwnd_message_parent
444 * Return the parent for HWND_MESSAGE windows.
446 HWND get_hwnd_message_parent(void)
448 struct user_thread_info *thread_info = get_user_thread_info();
450 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
451 return thread_info->msg_window;
455 /*******************************************************************
456 * is_desktop_window
458 * Check if window is the desktop or the HWND_MESSAGE top parent.
460 BOOL is_desktop_window( HWND hwnd )
462 struct user_thread_info *thread_info = get_user_thread_info();
464 if (!hwnd) return FALSE;
465 if (hwnd == thread_info->top_window) return TRUE;
466 if (hwnd == thread_info->msg_window) return TRUE;
468 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
470 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
471 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
473 return FALSE;
477 /***********************************************************************
478 * WIN_GetPtr
480 * Return a pointer to the WND structure if local to the process,
481 * or WND_OTHER_PROCESS if handle may be valid in other process.
482 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
484 WND *WIN_GetPtr( HWND hwnd )
486 WND *ptr;
488 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
490 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
492 return ptr;
496 /***********************************************************************
497 * WIN_IsCurrentProcess
499 * Check whether a given window belongs to the current process (and return the full handle).
501 HWND WIN_IsCurrentProcess( HWND hwnd )
503 WND *ptr;
504 HWND ret;
506 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
507 ret = ptr->obj.handle;
508 WIN_ReleasePtr( ptr );
509 return ret;
513 /***********************************************************************
514 * WIN_IsCurrentThread
516 * Check whether a given window belongs to the current thread (and return the full handle).
518 HWND WIN_IsCurrentThread( HWND hwnd )
520 WND *ptr;
521 HWND ret = 0;
523 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
524 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
525 WIN_ReleasePtr( ptr );
526 return ret;
530 /***********************************************************************
531 * WIN_GetFullHandle
533 * Convert a possibly truncated window handle to a full 32-bit handle.
535 HWND WIN_GetFullHandle( HWND hwnd )
537 WND *ptr;
539 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
540 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
541 /* do sign extension for -2 and -3 */
542 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
544 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
546 if (ptr == WND_DESKTOP)
548 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
549 else return get_hwnd_message_parent();
552 if (ptr != WND_OTHER_PROCESS)
554 hwnd = ptr->obj.handle;
555 WIN_ReleasePtr( ptr );
557 else /* may belong to another process */
559 SERVER_START_REQ( get_window_info )
561 req->handle = wine_server_user_handle( hwnd );
562 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
564 SERVER_END_REQ;
566 return hwnd;
570 /***********************************************************************
571 * WIN_SetOwner
573 * Change the owner of a window.
575 HWND WIN_SetOwner( HWND hwnd, HWND owner )
577 WND *win = WIN_GetPtr( hwnd );
578 HWND ret = 0;
580 if (!win || win == WND_DESKTOP) return 0;
581 if (win == WND_OTHER_PROCESS)
583 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
584 return 0;
586 SERVER_START_REQ( set_window_owner )
588 req->handle = wine_server_user_handle( hwnd );
589 req->owner = wine_server_user_handle( owner );
590 if (!wine_server_call( req ))
592 win->owner = wine_server_ptr_handle( reply->full_owner );
593 ret = wine_server_ptr_handle( reply->prev_owner );
596 SERVER_END_REQ;
597 WIN_ReleasePtr( win );
598 return ret;
602 /***********************************************************************
603 * WIN_SetStyle
605 * Change the style of a window.
607 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
609 BOOL ok;
610 STYLESTRUCT style;
611 WND *win = WIN_GetPtr( hwnd );
613 if (!win || win == WND_DESKTOP) return 0;
614 if (win == WND_OTHER_PROCESS)
616 if (IsWindow(hwnd))
617 ERR( "cannot set style %x/%x on other process window %p\n",
618 set_bits, clear_bits, hwnd );
619 return 0;
621 style.styleOld = win->dwStyle;
622 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
623 if (style.styleNew == style.styleOld)
625 WIN_ReleasePtr( win );
626 return style.styleNew;
628 SERVER_START_REQ( set_window_info )
630 req->handle = wine_server_user_handle( hwnd );
631 req->flags = SET_WIN_STYLE;
632 req->style = style.styleNew;
633 req->extra_offset = -1;
634 if ((ok = !wine_server_call( req )))
636 style.styleOld = reply->old_style;
637 win->dwStyle = style.styleNew;
640 SERVER_END_REQ;
641 WIN_ReleasePtr( win );
642 if (ok)
644 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
645 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
647 return style.styleOld;
651 /***********************************************************************
652 * WIN_GetRectangles
654 * Get the window and client rectangles.
656 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
658 WND *win = WIN_GetPtr( hwnd );
659 BOOL ret = TRUE;
661 if (!win)
663 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
664 return FALSE;
666 if (win == WND_DESKTOP)
668 RECT rect;
669 rect.left = rect.top = 0;
670 if (hwnd == get_hwnd_message_parent())
672 rect.right = 100;
673 rect.bottom = 100;
675 else
677 rect.right = GetSystemMetrics(SM_CXSCREEN);
678 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
680 if (rectWindow) *rectWindow = rect;
681 if (rectClient) *rectClient = rect;
682 return TRUE;
684 if (win != WND_OTHER_PROCESS)
686 RECT window_rect = win->rectWindow, client_rect = win->rectClient;
688 switch (relative)
690 case COORDS_CLIENT:
691 OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
692 OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
693 if (win->dwExStyle & WS_EX_LAYOUTRTL)
694 mirror_rect( &win->rectClient, &window_rect );
695 break;
696 case COORDS_WINDOW:
697 OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
698 OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
699 if (win->dwExStyle & WS_EX_LAYOUTRTL)
700 mirror_rect( &win->rectWindow, &client_rect );
701 break;
702 case COORDS_PARENT:
703 if (win->parent)
705 WND *parent = WIN_GetPtr( win->parent );
706 if (parent == WND_DESKTOP) break;
707 if (!parent || parent == WND_OTHER_PROCESS)
709 WIN_ReleasePtr( win );
710 goto other_process;
712 if (parent->flags & WIN_CHILDREN_MOVED)
714 WIN_ReleasePtr( parent );
715 WIN_ReleasePtr( win );
716 goto other_process;
718 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
720 mirror_rect( &parent->rectClient, &window_rect );
721 mirror_rect( &parent->rectClient, &client_rect );
723 WIN_ReleasePtr( parent );
725 break;
726 case COORDS_SCREEN:
727 while (win->parent)
729 WND *parent = WIN_GetPtr( win->parent );
730 if (parent == WND_DESKTOP) break;
731 if (!parent || parent == WND_OTHER_PROCESS)
733 WIN_ReleasePtr( win );
734 goto other_process;
736 WIN_ReleasePtr( win );
737 if (parent->flags & WIN_CHILDREN_MOVED)
739 WIN_ReleasePtr( parent );
740 goto other_process;
742 win = parent;
743 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
744 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
746 break;
748 if (rectWindow) *rectWindow = window_rect;
749 if (rectClient) *rectClient = client_rect;
750 WIN_ReleasePtr( win );
751 return TRUE;
754 other_process:
755 SERVER_START_REQ( get_window_rectangles )
757 req->handle = wine_server_user_handle( hwnd );
758 req->relative = relative;
759 if ((ret = !wine_server_call_err( req )))
761 if (rectWindow)
763 rectWindow->left = reply->window.left;
764 rectWindow->top = reply->window.top;
765 rectWindow->right = reply->window.right;
766 rectWindow->bottom = reply->window.bottom;
768 if (rectClient)
770 rectClient->left = reply->client.left;
771 rectClient->top = reply->client.top;
772 rectClient->right = reply->client.right;
773 rectClient->bottom = reply->client.bottom;
777 SERVER_END_REQ;
778 return ret;
782 /***********************************************************************
783 * WIN_DestroyWindow
785 * Destroy storage associated to a window. "Internals" p.358
787 LRESULT WIN_DestroyWindow( HWND hwnd )
789 WND *wndPtr;
790 HWND *list;
791 HMENU menu = 0, sys_menu;
792 HWND icon_title;
794 TRACE("%p\n", hwnd );
796 /* free child windows */
797 if ((list = WIN_ListChildren( hwnd )))
799 int i;
800 for (i = 0; list[i]; i++)
802 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
803 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
805 HeapFree( GetProcessHeap(), 0, list );
808 /* Unlink now so we won't bother with the children later on */
809 SERVER_START_REQ( set_parent )
811 req->handle = wine_server_user_handle( hwnd );
812 req->parent = 0;
813 wine_server_call( req );
815 SERVER_END_REQ;
818 * Send the WM_NCDESTROY to the window being destroyed.
820 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
822 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
824 /* free resources associated with the window */
826 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
827 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
828 menu = (HMENU)wndPtr->wIDmenu;
829 sys_menu = wndPtr->hSysMenu;
830 free_dce( wndPtr->dce, hwnd );
831 wndPtr->dce = NULL;
832 icon_title = wndPtr->icon_title;
833 HeapFree( GetProcessHeap(), 0, wndPtr->text );
834 wndPtr->text = NULL;
835 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
836 wndPtr->pScroll = NULL;
837 WIN_ReleasePtr( wndPtr );
839 if (icon_title) DestroyWindow( icon_title );
840 if (menu) DestroyMenu( menu );
841 if (sys_menu) DestroyMenu( sys_menu );
843 USER_Driver->pDestroyWindow( hwnd );
845 free_window_handle( hwnd );
846 return 0;
850 /***********************************************************************
851 * destroy_thread_window
853 * Destroy a window upon exit of its thread.
855 static void destroy_thread_window( HWND hwnd )
857 WND *wndPtr;
858 HWND *list;
859 HMENU menu = 0, sys_menu = 0;
860 WORD index;
862 /* free child windows */
864 if ((list = WIN_ListChildren( hwnd )))
866 int i;
867 for (i = 0; list[i]; i++)
869 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
870 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
872 HeapFree( GetProcessHeap(), 0, list );
875 /* destroy the client-side storage */
877 index = USER_HANDLE_TO_INDEX(hwnd);
878 if (index >= NB_USER_HANDLES) return;
879 USER_Lock();
880 if ((wndPtr = user_handles[index]))
882 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
883 sys_menu = wndPtr->hSysMenu;
884 free_dce( wndPtr->dce, hwnd );
885 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
887 USER_Unlock();
889 HeapFree( GetProcessHeap(), 0, wndPtr );
890 if (menu) DestroyMenu( menu );
891 if (sys_menu) DestroyMenu( sys_menu );
895 /***********************************************************************
896 * destroy_thread_child_windows
898 * Destroy child windows upon exit of its thread.
900 static void destroy_thread_child_windows( HWND hwnd )
902 HWND *list;
903 int i;
905 if (WIN_IsCurrentThread( hwnd ))
907 destroy_thread_window( hwnd );
909 else if ((list = WIN_ListChildren( hwnd )))
911 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
912 HeapFree( GetProcessHeap(), 0, list );
917 /***********************************************************************
918 * WIN_DestroyThreadWindows
920 * Destroy all children of 'wnd' owned by the current thread.
922 void WIN_DestroyThreadWindows( HWND hwnd )
924 HWND *list;
925 int i;
927 if (!(list = WIN_ListChildren( hwnd ))) return;
929 /* reset owners of top-level windows */
930 for (i = 0; list[i]; i++)
932 if (!WIN_IsCurrentThread( list[i] ))
934 HWND owner = GetWindow( list[i], GW_OWNER );
935 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
939 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
940 HeapFree( GetProcessHeap(), 0, list );
944 /***********************************************************************
945 * WIN_FixCoordinates
947 * Fix the coordinates - Helper for WIN_CreateWindowEx.
948 * returns default show mode in sw.
950 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
952 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
953 POINT pos[2];
955 if (cs->dwExStyle & WS_EX_MDICHILD)
957 UINT id = 0;
959 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
960 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
962 TRACE("MDI child id %04x\n", id);
965 if (cs->style & (WS_CHILD | WS_POPUP))
967 if (cs->dwExStyle & WS_EX_MDICHILD)
969 if (IS_DEFAULT(cs->x))
971 cs->x = pos[0].x;
972 cs->y = pos[0].y;
974 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
975 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
977 else
979 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
980 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
983 else /* overlapped window */
985 HMONITOR monitor;
986 MONITORINFO mon_info;
987 STARTUPINFOW info;
989 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
991 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
992 mon_info.cbSize = sizeof(mon_info);
993 GetMonitorInfoW( monitor, &mon_info );
994 GetStartupInfoW( &info );
996 if (IS_DEFAULT(cs->x))
998 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
999 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1000 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1003 if (IS_DEFAULT(cs->cx))
1005 if (info.dwFlags & STARTF_USESIZE)
1007 cs->cx = info.dwXSize;
1008 cs->cy = info.dwYSize;
1010 else
1012 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1013 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1016 /* neither x nor cx are default. Check the y values .
1017 * In the trace we see Outlook and Outlook Express using
1018 * cy set to CW_USEDEFAULT when opening the address book.
1020 else if (IS_DEFAULT(cs->cy))
1022 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1023 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1026 #undef IS_DEFAULT
1029 /***********************************************************************
1030 * dump_window_styles
1032 static void dump_window_styles( DWORD style, DWORD exstyle )
1034 TRACE( "style:" );
1035 if(style & WS_POPUP) TRACE(" WS_POPUP");
1036 if(style & WS_CHILD) TRACE(" WS_CHILD");
1037 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1038 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1039 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1040 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1041 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1042 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1043 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1044 else
1046 if(style & WS_BORDER) TRACE(" WS_BORDER");
1047 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1049 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1050 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1051 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1052 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1053 if (style & WS_CHILD)
1055 if(style & WS_GROUP) TRACE(" WS_GROUP");
1056 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1058 else
1060 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1061 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1064 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1065 #define DUMPED_STYLES \
1066 (WS_POPUP | \
1067 WS_CHILD | \
1068 WS_MINIMIZE | \
1069 WS_VISIBLE | \
1070 WS_DISABLED | \
1071 WS_CLIPSIBLINGS | \
1072 WS_CLIPCHILDREN | \
1073 WS_MAXIMIZE | \
1074 WS_BORDER | \
1075 WS_DLGFRAME | \
1076 WS_VSCROLL | \
1077 WS_HSCROLL | \
1078 WS_SYSMENU | \
1079 WS_THICKFRAME | \
1080 WS_GROUP | \
1081 WS_TABSTOP | \
1082 WS_MINIMIZEBOX | \
1083 WS_MAXIMIZEBOX)
1085 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1086 TRACE("\n");
1087 #undef DUMPED_STYLES
1089 TRACE( "exstyle:" );
1090 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1091 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1092 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1093 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1094 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1095 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1096 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1097 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1098 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1099 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1100 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1101 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1102 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1103 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1104 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1105 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1106 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1107 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1108 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1110 #define DUMPED_EX_STYLES \
1111 (WS_EX_DLGMODALFRAME | \
1112 WS_EX_DRAGDETECT | \
1113 WS_EX_NOPARENTNOTIFY | \
1114 WS_EX_TOPMOST | \
1115 WS_EX_ACCEPTFILES | \
1116 WS_EX_TRANSPARENT | \
1117 WS_EX_MDICHILD | \
1118 WS_EX_TOOLWINDOW | \
1119 WS_EX_WINDOWEDGE | \
1120 WS_EX_CLIENTEDGE | \
1121 WS_EX_CONTEXTHELP | \
1122 WS_EX_RIGHT | \
1123 WS_EX_RTLREADING | \
1124 WS_EX_LEFTSCROLLBAR | \
1125 WS_EX_CONTROLPARENT | \
1126 WS_EX_STATICEDGE | \
1127 WS_EX_APPWINDOW | \
1128 WS_EX_LAYERED | \
1129 WS_EX_LAYOUTRTL)
1131 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1132 TRACE("\n");
1133 #undef DUMPED_EX_STYLES
1137 /***********************************************************************
1138 * WIN_CreateWindowEx
1140 * Implementation of CreateWindowEx().
1142 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1144 INT cx, cy, style, sw = SW_SHOW;
1145 LRESULT result;
1146 RECT rect;
1147 WND *wndPtr;
1148 HWND hwnd, parent, owner, top_child = 0;
1149 MDICREATESTRUCTW mdi_cs;
1150 CBT_CREATEWNDW cbtc;
1151 CREATESTRUCTW cbcs;
1153 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1154 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1155 debugstr_w(className),
1156 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1157 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1158 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1160 /* Fix the styles for MDI children */
1161 if (cs->dwExStyle & WS_EX_MDICHILD)
1163 UINT flags = 0;
1165 wndPtr = WIN_GetPtr(cs->hwndParent);
1166 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1168 flags = wndPtr->flags;
1169 WIN_ReleasePtr(wndPtr);
1172 if (!(flags & WIN_ISMDICLIENT))
1174 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1175 return 0;
1178 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1179 * MDICREATESTRUCT members have the originally passed values.
1181 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1182 * have the same layout.
1184 mdi_cs.szClass = cs->lpszClass;
1185 mdi_cs.szTitle = cs->lpszName;
1186 mdi_cs.hOwner = cs->hInstance;
1187 mdi_cs.x = cs->x;
1188 mdi_cs.y = cs->y;
1189 mdi_cs.cx = cs->cx;
1190 mdi_cs.cy = cs->cy;
1191 mdi_cs.style = cs->style;
1192 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1194 cs->lpCreateParams = &mdi_cs;
1196 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1198 if (cs->style & WS_POPUP)
1200 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1201 return 0;
1203 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1205 else
1207 cs->style &= ~WS_POPUP;
1208 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1209 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1212 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1214 if (top_child)
1216 /* Restore current maximized child */
1217 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1219 TRACE("Restoring current maximized child %p\n", top_child);
1220 if (cs->style & WS_MAXIMIZE)
1222 /* if the new window is maximized don't bother repainting */
1223 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1224 ShowWindow( top_child, SW_SHOWNORMAL );
1225 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1227 else ShowWindow( top_child, SW_SHOWNORMAL );
1232 /* Find the parent window */
1234 parent = cs->hwndParent;
1235 owner = 0;
1237 if (cs->hwndParent == HWND_MESSAGE)
1239 cs->hwndParent = parent = get_hwnd_message_parent();
1241 else if (cs->hwndParent)
1243 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1245 parent = GetDesktopWindow();
1246 owner = cs->hwndParent;
1248 else
1250 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1251 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1252 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1255 else
1257 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1259 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1261 WARN("No parent for child window\n" );
1262 SetLastError(ERROR_TLW_WITH_WSCHILD);
1263 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1265 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1266 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1267 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1269 DWORD layout;
1270 GetProcessDefaultLayout( &layout );
1271 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1272 parent = GetDesktopWindow();
1276 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1278 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1279 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1280 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1281 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1282 else
1283 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1285 /* Create the window structure */
1287 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1288 return 0;
1289 hwnd = wndPtr->obj.handle;
1291 /* Fill the window structure */
1293 wndPtr->tid = GetCurrentThreadId();
1294 wndPtr->hInstance = cs->hInstance;
1295 wndPtr->text = NULL;
1296 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1297 wndPtr->dwExStyle = cs->dwExStyle;
1298 wndPtr->wIDmenu = 0;
1299 wndPtr->helpContext = 0;
1300 wndPtr->pScroll = NULL;
1301 wndPtr->userdata = 0;
1302 wndPtr->hIcon = 0;
1303 wndPtr->hIconSmall = 0;
1304 wndPtr->hSysMenu = 0;
1306 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1307 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1309 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1312 * Correct the window styles.
1314 * It affects only the style loaded into the WIN structure.
1317 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1319 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1320 if (!(wndPtr->dwStyle & WS_POPUP))
1321 wndPtr->dwStyle |= WS_CAPTION;
1325 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1326 * why does the user get to set it?
1329 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1330 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1331 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1332 else
1333 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1335 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1336 wndPtr->flags |= WIN_NEED_SIZE;
1338 SERVER_START_REQ( set_window_info )
1340 req->handle = wine_server_user_handle( hwnd );
1341 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1342 req->style = wndPtr->dwStyle;
1343 req->ex_style = wndPtr->dwExStyle;
1344 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1345 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1346 req->extra_offset = -1;
1347 wine_server_call( req );
1349 SERVER_END_REQ;
1351 /* Set the window menu */
1353 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1355 if (cs->hMenu)
1357 if (!MENU_SetMenu(hwnd, cs->hMenu))
1359 WIN_ReleasePtr( wndPtr );
1360 free_window_handle( hwnd );
1361 return 0;
1364 else
1366 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1367 if (menuName)
1369 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1370 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1374 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1376 /* call the WH_CBT hook */
1378 /* the window style passed to the hook must be the real window style,
1379 * rather than just the window style that the caller to CreateWindowEx
1380 * passed in, so we have to copy the original CREATESTRUCT and get the
1381 * the real style. */
1382 cbcs = *cs;
1383 cbcs.style = wndPtr->dwStyle;
1384 cbtc.lpcs = &cbcs;
1385 cbtc.hwndInsertAfter = HWND_TOP;
1386 WIN_ReleasePtr( wndPtr );
1387 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1389 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1391 cx = cs->cx;
1392 cy = cs->cy;
1393 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1395 POINT maxSize, maxPos, minTrack, maxTrack;
1396 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1397 if (maxTrack.x < cx) cx = maxTrack.x;
1398 if (maxTrack.y < cy) cy = maxTrack.y;
1399 if (minTrack.x > cx) cx = minTrack.x;
1400 if (minTrack.y > cy) cy = minTrack.y;
1403 if (cx < 0) cx = 0;
1404 if (cy < 0) cy = 0;
1405 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1406 /* check for wraparound */
1407 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1408 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1409 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1411 /* send WM_NCCREATE */
1413 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1414 if (unicode)
1415 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1416 else
1417 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1418 if (!result)
1420 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1421 goto failed;
1424 /* send WM_NCCALCSIZE */
1426 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1428 /* yes, even if the CBT hook was called with HWND_TOP */
1429 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1430 RECT client_rect = rect;
1432 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1433 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1434 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1435 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1436 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1438 else return 0;
1440 /* send WM_CREATE */
1442 if (unicode)
1443 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1444 else
1445 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1446 if (result == -1) goto failed;
1448 /* call the driver */
1450 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1452 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1454 /* send the size messages */
1456 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1457 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1458 if (!(wndPtr->flags & WIN_NEED_SIZE))
1460 WIN_ReleasePtr( wndPtr );
1461 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1462 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1463 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1464 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1466 else WIN_ReleasePtr( wndPtr );
1468 /* Show the window, maximizing or minimizing if needed */
1470 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1471 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1473 RECT newPos;
1474 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1476 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1477 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1478 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1479 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1480 newPos.bottom - newPos.top, swFlag );
1483 /* Notify the parent window only */
1485 send_parent_notify( hwnd, WM_CREATE );
1486 if (!IsWindow( hwnd )) return 0;
1488 if (cs->style & WS_VISIBLE)
1490 if (cs->style & WS_MAXIMIZE)
1491 sw = SW_SHOW;
1492 else if (cs->style & WS_MINIMIZE)
1493 sw = SW_SHOWMINIMIZED;
1495 ShowWindow( hwnd, sw );
1496 if (cs->dwExStyle & WS_EX_MDICHILD)
1498 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1499 /* ShowWindow won't activate child windows */
1500 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1504 /* Call WH_SHELL hook */
1506 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1507 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1509 TRACE("created window %p\n", hwnd);
1510 return hwnd;
1512 failed:
1513 WIN_DestroyWindow( hwnd );
1514 return 0;
1518 /***********************************************************************
1519 * CreateWindowExA (USER32.@)
1521 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1522 LPCSTR windowName, DWORD style, INT x,
1523 INT y, INT width, INT height,
1524 HWND parent, HMENU menu,
1525 HINSTANCE instance, LPVOID data )
1527 CREATESTRUCTA cs;
1529 cs.lpCreateParams = data;
1530 cs.hInstance = instance;
1531 cs.hMenu = menu;
1532 cs.hwndParent = parent;
1533 cs.x = x;
1534 cs.y = y;
1535 cs.cx = width;
1536 cs.cy = height;
1537 cs.style = style;
1538 cs.lpszName = windowName;
1539 cs.lpszClass = className;
1540 cs.dwExStyle = exStyle;
1542 if (!IS_INTRESOURCE(className))
1544 WCHAR bufferW[256];
1545 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1546 return 0;
1547 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1549 /* Note: we rely on the fact that CREATESTRUCTA and */
1550 /* CREATESTRUCTW have the same layout. */
1551 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1555 /***********************************************************************
1556 * CreateWindowExW (USER32.@)
1558 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1559 LPCWSTR windowName, DWORD style, INT x,
1560 INT y, INT width, INT height,
1561 HWND parent, HMENU menu,
1562 HINSTANCE instance, LPVOID data )
1564 CREATESTRUCTW cs;
1566 cs.lpCreateParams = data;
1567 cs.hInstance = instance;
1568 cs.hMenu = menu;
1569 cs.hwndParent = parent;
1570 cs.x = x;
1571 cs.y = y;
1572 cs.cx = width;
1573 cs.cy = height;
1574 cs.style = style;
1575 cs.lpszName = windowName;
1576 cs.lpszClass = className;
1577 cs.dwExStyle = exStyle;
1579 return wow_handlers.create_window( &cs, className, instance, TRUE );
1583 /***********************************************************************
1584 * WIN_SendDestroyMsg
1586 static void WIN_SendDestroyMsg( HWND hwnd )
1588 GUITHREADINFO info;
1590 info.cbSize = sizeof(info);
1591 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1593 if (hwnd == info.hwndCaret) DestroyCaret();
1594 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1598 * Send the WM_DESTROY to the window.
1600 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1603 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1604 * make sure that the window still exists when we come back.
1606 if (IsWindow(hwnd))
1608 HWND* pWndArray;
1609 int i;
1611 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1613 for (i = 0; pWndArray[i]; i++)
1615 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1617 HeapFree( GetProcessHeap(), 0, pWndArray );
1619 else
1620 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1624 /***********************************************************************
1625 * DestroyWindow (USER32.@)
1627 BOOL WINAPI DestroyWindow( HWND hwnd )
1629 BOOL is_child;
1631 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1633 SetLastError( ERROR_ACCESS_DENIED );
1634 return FALSE;
1637 TRACE("(%p)\n", hwnd);
1639 /* Call hooks */
1641 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1643 if (MENU_IsMenuActive() == hwnd)
1644 EndMenu();
1646 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1648 if (is_child)
1650 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1651 send_parent_notify( hwnd, WM_DESTROY );
1653 else if (!GetWindow( hwnd, GW_OWNER ))
1655 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1656 /* FIXME: clean up palette - see "Internals" p.352 */
1659 if (!IsWindow(hwnd)) return TRUE;
1661 /* Hide the window */
1662 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1664 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1665 if (is_child)
1666 ShowWindow( hwnd, SW_HIDE );
1667 else
1668 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1669 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1672 if (!IsWindow(hwnd)) return TRUE;
1674 /* Recursively destroy owned windows */
1676 if (!is_child)
1678 for (;;)
1680 int i, got_one = 0;
1681 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1682 if (list)
1684 for (i = 0; list[i]; i++)
1686 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1687 if (WIN_IsCurrentThread( list[i] ))
1689 DestroyWindow( list[i] );
1690 got_one = 1;
1691 continue;
1693 WIN_SetOwner( list[i], 0 );
1695 HeapFree( GetProcessHeap(), 0, list );
1697 if (!got_one) break;
1701 /* Send destroy messages */
1703 WIN_SendDestroyMsg( hwnd );
1704 if (!IsWindow( hwnd )) return TRUE;
1706 if (GetClipboardOwner() == hwnd)
1707 CLIPBOARD_ReleaseOwner();
1709 /* Destroy the window storage */
1711 WIN_DestroyWindow( hwnd );
1712 return TRUE;
1716 /***********************************************************************
1717 * CloseWindow (USER32.@)
1719 BOOL WINAPI CloseWindow( HWND hwnd )
1721 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1722 ShowWindow( hwnd, SW_MINIMIZE );
1723 return TRUE;
1727 /***********************************************************************
1728 * OpenIcon (USER32.@)
1730 BOOL WINAPI OpenIcon( HWND hwnd )
1732 if (!IsIconic( hwnd )) return FALSE;
1733 ShowWindow( hwnd, SW_SHOWNORMAL );
1734 return TRUE;
1738 /***********************************************************************
1739 * FindWindowExW (USER32.@)
1741 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1743 HWND *list = NULL;
1744 HWND retvalue = 0;
1745 int i = 0, len = 0;
1746 WCHAR *buffer = NULL;
1748 if (!parent && child) parent = GetDesktopWindow();
1749 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1751 if (title)
1753 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1754 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1757 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1759 if (child)
1761 child = WIN_GetFullHandle( child );
1762 while (list[i] && list[i] != child) i++;
1763 if (!list[i]) goto done;
1764 i++; /* start from next window */
1767 if (title)
1769 while (list[i])
1771 if (GetWindowTextW( list[i], buffer, len + 1 ))
1773 if (!strcmpiW( buffer, title )) break;
1775 else
1777 if (!title[0]) break;
1779 i++;
1782 retvalue = list[i];
1784 done:
1785 HeapFree( GetProcessHeap(), 0, list );
1786 HeapFree( GetProcessHeap(), 0, buffer );
1787 return retvalue;
1792 /***********************************************************************
1793 * FindWindowA (USER32.@)
1795 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1797 HWND ret = FindWindowExA( 0, 0, className, title );
1798 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1799 return ret;
1803 /***********************************************************************
1804 * FindWindowExA (USER32.@)
1806 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1808 LPWSTR titleW = NULL;
1809 HWND hwnd = 0;
1811 if (title)
1813 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1814 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1815 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1818 if (!IS_INTRESOURCE(className))
1820 WCHAR classW[256];
1821 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1822 hwnd = FindWindowExW( parent, child, classW, titleW );
1824 else
1826 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1829 HeapFree( GetProcessHeap(), 0, titleW );
1830 return hwnd;
1834 /***********************************************************************
1835 * FindWindowW (USER32.@)
1837 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1839 return FindWindowExW( 0, 0, className, title );
1843 /**********************************************************************
1844 * GetDesktopWindow (USER32.@)
1846 HWND WINAPI GetDesktopWindow(void)
1848 struct user_thread_info *thread_info = get_user_thread_info();
1850 if (thread_info->top_window) return thread_info->top_window;
1852 SERVER_START_REQ( get_desktop_window )
1854 req->force = 0;
1855 if (!wine_server_call( req ))
1857 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1858 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1861 SERVER_END_REQ;
1863 if (!thread_info->top_window)
1865 USEROBJECTFLAGS flags;
1866 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1867 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1869 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1870 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1871 STARTUPINFOW si;
1872 PROCESS_INFORMATION pi;
1873 WCHAR windir[MAX_PATH];
1874 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1875 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1876 void *redir;
1878 memset( &si, 0, sizeof(si) );
1879 si.cb = sizeof(si);
1880 si.dwFlags = STARTF_USESTDHANDLES;
1881 si.hStdInput = 0;
1882 si.hStdOutput = 0;
1883 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1885 GetSystemDirectoryW( windir, MAX_PATH );
1886 strcpyW( app, windir );
1887 strcatW( app, explorer );
1888 strcpyW( cmdline, app );
1889 strcatW( cmdline, args );
1891 Wow64DisableWow64FsRedirection( &redir );
1892 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1893 NULL, windir, &si, &pi ))
1895 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1896 WaitForInputIdle( pi.hProcess, 10000 );
1897 CloseHandle( pi.hThread );
1898 CloseHandle( pi.hProcess );
1900 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1901 Wow64RevertWow64FsRedirection( redir );
1903 else TRACE( "not starting explorer since winstation is not visible\n" );
1905 SERVER_START_REQ( get_desktop_window )
1907 req->force = 1;
1908 if (!wine_server_call( req ))
1910 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1911 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1914 SERVER_END_REQ;
1917 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1918 ERR( "failed to create desktop window\n" );
1920 return thread_info->top_window;
1924 /*******************************************************************
1925 * EnableWindow (USER32.@)
1927 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1929 BOOL retvalue;
1930 HWND full_handle;
1932 if (is_broadcast(hwnd))
1934 SetLastError( ERROR_INVALID_PARAMETER );
1935 return FALSE;
1938 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1939 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1941 hwnd = full_handle;
1943 TRACE("( %p, %d )\n", hwnd, enable);
1945 retvalue = !IsWindowEnabled( hwnd );
1947 if (enable && retvalue)
1949 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1950 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1952 else if (!enable && !retvalue)
1954 HWND capture_wnd;
1956 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1958 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1960 if (hwnd == GetFocus())
1961 SetFocus( 0 ); /* A disabled window can't have the focus */
1963 capture_wnd = GetCapture();
1964 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1965 ReleaseCapture(); /* A disabled window can't capture the mouse */
1967 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1969 return retvalue;
1973 /***********************************************************************
1974 * IsWindowEnabled (USER32.@)
1976 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1978 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1982 /***********************************************************************
1983 * IsWindowUnicode (USER32.@)
1985 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1987 WND * wndPtr;
1988 BOOL retvalue = FALSE;
1990 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1992 if (wndPtr == WND_DESKTOP) return TRUE;
1994 if (wndPtr != WND_OTHER_PROCESS)
1996 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1997 WIN_ReleasePtr( wndPtr );
1999 else
2001 SERVER_START_REQ( get_window_info )
2003 req->handle = wine_server_user_handle( hwnd );
2004 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2006 SERVER_END_REQ;
2008 return retvalue;
2012 /**********************************************************************
2013 * WIN_GetWindowLong
2015 * Helper function for GetWindowLong().
2017 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2019 LONG_PTR retvalue = 0;
2020 WND *wndPtr;
2022 if (offset == GWLP_HWNDPARENT)
2024 HWND parent = GetAncestor( hwnd, GA_PARENT );
2025 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2026 return (ULONG_PTR)parent;
2029 if (!(wndPtr = WIN_GetPtr( hwnd )))
2031 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2032 return 0;
2035 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2037 if (offset == GWLP_WNDPROC)
2039 SetLastError( ERROR_ACCESS_DENIED );
2040 return 0;
2042 SERVER_START_REQ( set_window_info )
2044 req->handle = wine_server_user_handle( hwnd );
2045 req->flags = 0; /* don't set anything, just retrieve */
2046 req->extra_offset = (offset >= 0) ? offset : -1;
2047 req->extra_size = (offset >= 0) ? size : 0;
2048 if (!wine_server_call_err( req ))
2050 switch(offset)
2052 case GWL_STYLE: retvalue = reply->old_style; break;
2053 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2054 case GWLP_ID: retvalue = reply->old_id; break;
2055 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2056 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2057 default:
2058 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2059 else SetLastError( ERROR_INVALID_INDEX );
2060 break;
2064 SERVER_END_REQ;
2065 return retvalue;
2068 /* now we have a valid wndPtr */
2070 if (offset >= 0)
2072 if (offset > (int)(wndPtr->cbWndExtra - size))
2074 WARN("Invalid offset %d\n", offset );
2075 WIN_ReleasePtr( wndPtr );
2076 SetLastError( ERROR_INVALID_INDEX );
2077 return 0;
2079 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2081 /* Special case for dialog window procedure */
2082 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2083 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2084 WIN_ReleasePtr( wndPtr );
2085 return retvalue;
2088 switch(offset)
2090 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2091 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2092 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2093 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2094 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2095 case GWLP_WNDPROC:
2096 /* This looks like a hack only for the edit control (see tests). This makes these controls
2097 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2098 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2100 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2101 retvalue = (ULONG_PTR)wndPtr->winproc;
2102 else
2103 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2104 break;
2105 default:
2106 WARN("Unknown offset %d\n", offset );
2107 SetLastError( ERROR_INVALID_INDEX );
2108 break;
2110 WIN_ReleasePtr(wndPtr);
2111 return retvalue;
2115 /**********************************************************************
2116 * WIN_SetWindowLong
2118 * Helper function for SetWindowLong().
2120 * 0 is the failure code. However, in the case of failure SetLastError
2121 * must be set to distinguish between a 0 return value and a failure.
2123 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2125 STYLESTRUCT style;
2126 BOOL ok;
2127 LONG_PTR retval = 0;
2128 WND *wndPtr;
2130 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2132 if (is_broadcast(hwnd))
2134 SetLastError( ERROR_INVALID_PARAMETER );
2135 return FALSE;
2138 if (!(wndPtr = WIN_GetPtr( hwnd )))
2140 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2141 return 0;
2143 if (wndPtr == WND_DESKTOP)
2145 /* can't change anything on the desktop window */
2146 SetLastError( ERROR_ACCESS_DENIED );
2147 return 0;
2149 if (wndPtr == WND_OTHER_PROCESS)
2151 if (offset == GWLP_WNDPROC)
2153 SetLastError( ERROR_ACCESS_DENIED );
2154 return 0;
2156 if (offset > 32767 || offset < -32767)
2158 SetLastError( ERROR_INVALID_INDEX );
2159 return 0;
2161 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2164 /* first some special cases */
2165 switch( offset )
2167 case GWL_STYLE:
2168 style.styleOld = wndPtr->dwStyle;
2169 style.styleNew = newval;
2170 WIN_ReleasePtr( wndPtr );
2171 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2172 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2173 newval = style.styleNew;
2174 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2175 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2176 break;
2177 case GWL_EXSTYLE:
2178 style.styleOld = wndPtr->dwExStyle;
2179 style.styleNew = newval;
2180 WIN_ReleasePtr( wndPtr );
2181 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2182 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2183 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2184 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2185 /* WS_EX_WINDOWEDGE depends on some other styles */
2186 if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2187 newval |= WS_EX_WINDOWEDGE;
2188 else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2189 newval &= ~WS_EX_WINDOWEDGE;
2190 break;
2191 case GWLP_HWNDPARENT:
2192 if (wndPtr->parent == GetDesktopWindow())
2194 WIN_ReleasePtr( wndPtr );
2195 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2197 else
2199 WIN_ReleasePtr( wndPtr );
2200 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2202 case GWLP_WNDPROC:
2204 WNDPROC proc;
2205 UINT old_flags = wndPtr->flags;
2206 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2207 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2208 if (proc) wndPtr->winproc = proc;
2209 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2210 else wndPtr->flags &= ~WIN_ISUNICODE;
2211 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2213 WIN_ReleasePtr( wndPtr );
2214 return retval;
2216 /* update is_unicode flag on the server side */
2217 break;
2219 case GWLP_ID:
2220 case GWLP_HINSTANCE:
2221 case GWLP_USERDATA:
2222 break;
2223 case DWLP_DLGPROC:
2224 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2225 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2227 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2228 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2229 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2230 WIN_ReleasePtr( wndPtr );
2231 return retval;
2233 /* fall through */
2234 default:
2235 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2237 WARN("Invalid offset %d\n", offset );
2238 WIN_ReleasePtr( wndPtr );
2239 SetLastError( ERROR_INVALID_INDEX );
2240 return 0;
2242 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2244 /* already set to the same value */
2245 WIN_ReleasePtr( wndPtr );
2246 return newval;
2248 break;
2251 SERVER_START_REQ( set_window_info )
2253 req->handle = wine_server_user_handle( hwnd );
2254 req->extra_offset = -1;
2255 switch(offset)
2257 case GWL_STYLE:
2258 req->flags = SET_WIN_STYLE;
2259 req->style = newval;
2260 break;
2261 case GWL_EXSTYLE:
2262 req->flags = SET_WIN_EXSTYLE;
2263 req->ex_style = newval;
2264 break;
2265 case GWLP_ID:
2266 req->flags = SET_WIN_ID;
2267 req->id = newval;
2268 break;
2269 case GWLP_HINSTANCE:
2270 req->flags = SET_WIN_INSTANCE;
2271 req->instance = wine_server_client_ptr( (void *)newval );
2272 break;
2273 case GWLP_WNDPROC:
2274 req->flags = SET_WIN_UNICODE;
2275 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2276 break;
2277 case GWLP_USERDATA:
2278 req->flags = SET_WIN_USERDATA;
2279 req->user_data = newval;
2280 break;
2281 default:
2282 req->flags = SET_WIN_EXTRA;
2283 req->extra_offset = offset;
2284 req->extra_size = size;
2285 set_win_data( &req->extra_value, newval, size );
2287 if ((ok = !wine_server_call_err( req )))
2289 switch(offset)
2291 case GWL_STYLE:
2292 wndPtr->dwStyle = newval;
2293 retval = reply->old_style;
2294 break;
2295 case GWL_EXSTYLE:
2296 wndPtr->dwExStyle = newval;
2297 retval = reply->old_ex_style;
2298 break;
2299 case GWLP_ID:
2300 wndPtr->wIDmenu = newval;
2301 retval = reply->old_id;
2302 break;
2303 case GWLP_HINSTANCE:
2304 wndPtr->hInstance = (HINSTANCE)newval;
2305 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2306 break;
2307 case GWLP_WNDPROC:
2308 break;
2309 case GWLP_USERDATA:
2310 wndPtr->userdata = newval;
2311 retval = reply->old_user_data;
2312 break;
2313 default:
2314 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2315 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2316 break;
2320 SERVER_END_REQ;
2321 WIN_ReleasePtr( wndPtr );
2323 if (!ok) return 0;
2325 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2327 style.styleOld = retval;
2328 style.styleNew = newval;
2329 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2330 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2333 return retval;
2337 /**********************************************************************
2338 * GetWindowWord (USER32.@)
2340 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2342 switch(offset)
2344 case GWLP_ID:
2345 case GWLP_HINSTANCE:
2346 case GWLP_HWNDPARENT:
2347 break;
2348 default:
2349 if (offset < 0)
2351 WARN("Invalid offset %d\n", offset );
2352 SetLastError( ERROR_INVALID_INDEX );
2353 return 0;
2355 break;
2357 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2361 /**********************************************************************
2362 * GetWindowLongA (USER32.@)
2364 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2366 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2370 /**********************************************************************
2371 * GetWindowLongW (USER32.@)
2373 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2375 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2379 /**********************************************************************
2380 * SetWindowWord (USER32.@)
2382 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2384 switch(offset)
2386 case GWLP_ID:
2387 case GWLP_HINSTANCE:
2388 case GWLP_HWNDPARENT:
2389 break;
2390 default:
2391 if (offset < 0)
2393 WARN("Invalid offset %d\n", offset );
2394 SetLastError( ERROR_INVALID_INDEX );
2395 return 0;
2397 break;
2399 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2403 /**********************************************************************
2404 * SetWindowLongA (USER32.@)
2406 * See SetWindowLongW.
2408 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2410 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2414 /**********************************************************************
2415 * SetWindowLongW (USER32.@) Set window attribute
2417 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2418 * value in a window's extra memory.
2420 * The _hwnd_ parameter specifies the window. is the handle to a
2421 * window that has extra memory. The _newval_ parameter contains the
2422 * new attribute or extra memory value. If positive, the _offset_
2423 * parameter is the byte-addressed location in the window's extra
2424 * memory to set. If negative, _offset_ specifies the window
2425 * attribute to set, and should be one of the following values:
2427 * GWL_EXSTYLE The window's extended window style
2429 * GWL_STYLE The window's window style.
2431 * GWLP_WNDPROC Pointer to the window's window procedure.
2433 * GWLP_HINSTANCE The window's pplication instance handle.
2435 * GWLP_ID The window's identifier.
2437 * GWLP_USERDATA The window's user-specified data.
2439 * If the window is a dialog box, the _offset_ parameter can be one of
2440 * the following values:
2442 * DWLP_DLGPROC The address of the window's dialog box procedure.
2444 * DWLP_MSGRESULT The return value of a message
2445 * that the dialog box procedure processed.
2447 * DWLP_USER Application specific information.
2449 * RETURNS
2451 * If successful, returns the previous value located at _offset_. Otherwise,
2452 * returns 0.
2454 * NOTES
2456 * Extra memory for a window class is specified by a nonzero cbWndExtra
2457 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2458 * time of class creation.
2460 * Using GWL_WNDPROC to set a new window procedure effectively creates
2461 * a window subclass. Use CallWindowProc() in the new windows procedure
2462 * to pass messages to the superclass's window procedure.
2464 * The user data is reserved for use by the application which created
2465 * the window.
2467 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2468 * instead, call the EnableWindow() function to change the window's
2469 * disabled state.
2471 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2472 * SetParent() instead.
2474 * Win95:
2475 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2476 * it sends WM_STYLECHANGING before changing the settings
2477 * and WM_STYLECHANGED afterwards.
2478 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2480 LONG WINAPI SetWindowLongW(
2481 HWND hwnd, /* [in] window to alter */
2482 INT offset, /* [in] offset, in bytes, of location to alter */
2483 LONG newval /* [in] new value of location */
2485 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2489 /*******************************************************************
2490 * GetWindowTextA (USER32.@)
2492 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2494 WCHAR *buffer;
2496 if (!lpString) return 0;
2498 if (WIN_IsCurrentProcess( hwnd ))
2499 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2501 /* when window belongs to other process, don't send a message */
2502 if (nMaxCount <= 0) return 0;
2503 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2504 get_server_window_text( hwnd, buffer, nMaxCount );
2505 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2506 lpString[nMaxCount-1] = 0;
2507 HeapFree( GetProcessHeap(), 0, buffer );
2508 return strlen(lpString);
2512 /*******************************************************************
2513 * InternalGetWindowText (USER32.@)
2515 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2517 WND *win;
2519 if (nMaxCount <= 0) return 0;
2520 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2521 if (win == WND_DESKTOP) lpString[0] = 0;
2522 else if (win != WND_OTHER_PROCESS)
2524 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2525 else lpString[0] = 0;
2526 WIN_ReleasePtr( win );
2528 else
2530 get_server_window_text( hwnd, lpString, nMaxCount );
2532 return strlenW(lpString);
2536 /*******************************************************************
2537 * GetWindowTextW (USER32.@)
2539 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2541 if (!lpString) return 0;
2543 if (WIN_IsCurrentProcess( hwnd ))
2544 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2546 /* when window belongs to other process, don't send a message */
2547 if (nMaxCount <= 0) return 0;
2548 get_server_window_text( hwnd, lpString, nMaxCount );
2549 return strlenW(lpString);
2553 /*******************************************************************
2554 * SetWindowTextA (USER32.@)
2555 * SetWindowText (USER32.@)
2557 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2559 if (is_broadcast(hwnd))
2561 SetLastError( ERROR_INVALID_PARAMETER );
2562 return FALSE;
2564 if (!WIN_IsCurrentProcess( hwnd ))
2565 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2566 debugstr_a(lpString), hwnd );
2567 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2571 /*******************************************************************
2572 * SetWindowTextW (USER32.@)
2574 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2576 if (is_broadcast(hwnd))
2578 SetLastError( ERROR_INVALID_PARAMETER );
2579 return FALSE;
2581 if (!WIN_IsCurrentProcess( hwnd ))
2582 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2583 debugstr_w(lpString), hwnd );
2584 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2588 /*******************************************************************
2589 * GetWindowTextLengthA (USER32.@)
2591 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2593 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2596 /*******************************************************************
2597 * GetWindowTextLengthW (USER32.@)
2599 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2601 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2605 /*******************************************************************
2606 * IsWindow (USER32.@)
2608 BOOL WINAPI IsWindow( HWND hwnd )
2610 WND *ptr;
2611 BOOL ret;
2613 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2614 if (ptr == WND_DESKTOP) return TRUE;
2616 if (ptr != WND_OTHER_PROCESS)
2618 WIN_ReleasePtr( ptr );
2619 return TRUE;
2622 /* check other processes */
2623 SERVER_START_REQ( get_window_info )
2625 req->handle = wine_server_user_handle( hwnd );
2626 ret = !wine_server_call_err( req );
2628 SERVER_END_REQ;
2629 return ret;
2633 /***********************************************************************
2634 * GetWindowThreadProcessId (USER32.@)
2636 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2638 WND *ptr;
2639 DWORD tid = 0;
2641 if (!(ptr = WIN_GetPtr( hwnd )))
2643 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2644 return 0;
2647 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2649 /* got a valid window */
2650 tid = ptr->tid;
2651 if (process) *process = GetCurrentProcessId();
2652 WIN_ReleasePtr( ptr );
2653 return tid;
2656 /* check other processes */
2657 SERVER_START_REQ( get_window_info )
2659 req->handle = wine_server_user_handle( hwnd );
2660 if (!wine_server_call_err( req ))
2662 tid = (DWORD)reply->tid;
2663 if (process) *process = (DWORD)reply->pid;
2666 SERVER_END_REQ;
2667 return tid;
2671 /*****************************************************************
2672 * GetParent (USER32.@)
2674 HWND WINAPI GetParent( HWND hwnd )
2676 WND *wndPtr;
2677 HWND retvalue = 0;
2679 if (!(wndPtr = WIN_GetPtr( hwnd )))
2681 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2682 return 0;
2684 if (wndPtr == WND_DESKTOP) return 0;
2685 if (wndPtr == WND_OTHER_PROCESS)
2687 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2688 if (style & (WS_POPUP | WS_CHILD))
2690 SERVER_START_REQ( get_window_tree )
2692 req->handle = wine_server_user_handle( hwnd );
2693 if (!wine_server_call_err( req ))
2695 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2696 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2699 SERVER_END_REQ;
2702 else
2704 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2705 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2706 WIN_ReleasePtr( wndPtr );
2708 return retvalue;
2712 /*****************************************************************
2713 * GetAncestor (USER32.@)
2715 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2717 WND *win;
2718 HWND *list, ret = 0;
2720 switch(type)
2722 case GA_PARENT:
2723 if (!(win = WIN_GetPtr( hwnd )))
2725 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2726 return 0;
2728 if (win == WND_DESKTOP) return 0;
2729 if (win != WND_OTHER_PROCESS)
2731 ret = win->parent;
2732 WIN_ReleasePtr( win );
2734 else /* need to query the server */
2736 SERVER_START_REQ( get_window_tree )
2738 req->handle = wine_server_user_handle( hwnd );
2739 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2741 SERVER_END_REQ;
2743 break;
2745 case GA_ROOT:
2746 if (!(list = list_window_parents( hwnd ))) return 0;
2748 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2749 else
2751 int count = 2;
2752 while (list[count]) count++;
2753 ret = list[count - 2]; /* get the one before the desktop */
2755 HeapFree( GetProcessHeap(), 0, list );
2756 break;
2758 case GA_ROOTOWNER:
2759 if (is_desktop_window( hwnd )) return 0;
2760 ret = WIN_GetFullHandle( hwnd );
2761 for (;;)
2763 HWND parent = GetParent( ret );
2764 if (!parent) break;
2765 ret = parent;
2767 break;
2769 return ret;
2773 /*****************************************************************
2774 * SetParent (USER32.@)
2776 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2778 HWND full_handle;
2779 HWND old_parent = 0;
2780 BOOL was_visible;
2781 WND *wndPtr;
2782 BOOL ret;
2784 if (is_broadcast(hwnd) || is_broadcast(parent))
2786 SetLastError(ERROR_INVALID_PARAMETER);
2787 return 0;
2790 if (!parent) parent = GetDesktopWindow();
2791 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2792 else parent = WIN_GetFullHandle( parent );
2794 if (!IsWindow( parent ))
2796 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2797 return 0;
2800 /* Some applications try to set a child as a parent */
2801 if (IsChild(hwnd, parent))
2803 SetLastError( ERROR_INVALID_PARAMETER );
2804 return 0;
2807 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2808 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2810 if (full_handle == parent)
2812 SetLastError( ERROR_INVALID_PARAMETER );
2813 return 0;
2816 /* Windows hides the window first, then shows it again
2817 * including the WM_SHOWWINDOW messages and all */
2818 was_visible = ShowWindow( hwnd, SW_HIDE );
2820 wndPtr = WIN_GetPtr( hwnd );
2821 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2823 SERVER_START_REQ( set_parent )
2825 req->handle = wine_server_user_handle( hwnd );
2826 req->parent = wine_server_user_handle( parent );
2827 if ((ret = !wine_server_call( req )))
2829 old_parent = wine_server_ptr_handle( reply->old_parent );
2830 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2834 SERVER_END_REQ;
2835 WIN_ReleasePtr( wndPtr );
2836 if (!ret) return 0;
2838 USER_Driver->pSetParent( full_handle, parent, old_parent );
2840 /* SetParent additionally needs to make hwnd the topmost window
2841 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2842 WM_WINDOWPOSCHANGED notification messages.
2844 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2845 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2846 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2847 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2849 return old_parent;
2853 /*******************************************************************
2854 * IsChild (USER32.@)
2856 BOOL WINAPI IsChild( HWND parent, HWND child )
2858 HWND *list = list_window_parents( child );
2859 int i;
2860 BOOL ret;
2862 if (!list) return FALSE;
2863 parent = WIN_GetFullHandle( parent );
2864 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2865 ret = list[i] && list[i+1];
2866 HeapFree( GetProcessHeap(), 0, list );
2867 return ret;
2871 /***********************************************************************
2872 * IsWindowVisible (USER32.@)
2874 BOOL WINAPI IsWindowVisible( HWND hwnd )
2876 HWND *list;
2877 BOOL retval = TRUE;
2878 int i;
2880 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2881 if (!(list = list_window_parents( hwnd ))) return TRUE;
2882 if (list[0])
2884 for (i = 0; list[i+1]; i++)
2885 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2886 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2888 HeapFree( GetProcessHeap(), 0, list );
2889 return retval;
2893 /***********************************************************************
2894 * WIN_IsWindowDrawable
2896 * hwnd is drawable when it is visible, all parents are not
2897 * minimized, and it is itself not minimized unless we are
2898 * trying to draw its default class icon.
2900 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2902 HWND *list;
2903 BOOL retval = TRUE;
2904 int i;
2905 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2907 if (!(style & WS_VISIBLE)) return FALSE;
2908 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2910 if (!(list = list_window_parents( hwnd ))) return TRUE;
2911 if (list[0])
2913 for (i = 0; list[i+1]; i++)
2914 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2915 break;
2916 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2918 HeapFree( GetProcessHeap(), 0, list );
2919 return retval;
2923 /*******************************************************************
2924 * GetTopWindow (USER32.@)
2926 HWND WINAPI GetTopWindow( HWND hwnd )
2928 if (!hwnd) hwnd = GetDesktopWindow();
2929 return GetWindow( hwnd, GW_CHILD );
2933 /*******************************************************************
2934 * GetWindow (USER32.@)
2936 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2938 HWND retval = 0;
2940 if (rel == GW_OWNER) /* this one may be available locally */
2942 WND *wndPtr = WIN_GetPtr( hwnd );
2943 if (!wndPtr)
2945 SetLastError( ERROR_INVALID_HANDLE );
2946 return 0;
2948 if (wndPtr == WND_DESKTOP) return 0;
2949 if (wndPtr != WND_OTHER_PROCESS)
2951 retval = wndPtr->owner;
2952 WIN_ReleasePtr( wndPtr );
2953 return retval;
2955 /* else fall through to server call */
2958 SERVER_START_REQ( get_window_tree )
2960 req->handle = wine_server_user_handle( hwnd );
2961 if (!wine_server_call_err( req ))
2963 switch(rel)
2965 case GW_HWNDFIRST:
2966 retval = wine_server_ptr_handle( reply->first_sibling );
2967 break;
2968 case GW_HWNDLAST:
2969 retval = wine_server_ptr_handle( reply->last_sibling );
2970 break;
2971 case GW_HWNDNEXT:
2972 retval = wine_server_ptr_handle( reply->next_sibling );
2973 break;
2974 case GW_HWNDPREV:
2975 retval = wine_server_ptr_handle( reply->prev_sibling );
2976 break;
2977 case GW_OWNER:
2978 retval = wine_server_ptr_handle( reply->owner );
2979 break;
2980 case GW_CHILD:
2981 retval = wine_server_ptr_handle( reply->first_child );
2982 break;
2986 SERVER_END_REQ;
2987 return retval;
2991 /*******************************************************************
2992 * ShowOwnedPopups (USER32.@)
2994 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2996 int count = 0;
2997 WND *pWnd;
2998 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3000 if (!win_array) return TRUE;
3002 while (win_array[count]) count++;
3003 while (--count >= 0)
3005 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3006 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3007 if (pWnd == WND_OTHER_PROCESS) continue;
3008 if (fShow)
3010 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3012 WIN_ReleasePtr( pWnd );
3013 /* In Windows, ShowOwnedPopups(TRUE) generates
3014 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3015 * regardless of the state of the owner
3017 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3018 continue;
3021 else
3023 if (pWnd->dwStyle & WS_VISIBLE)
3025 WIN_ReleasePtr( pWnd );
3026 /* In Windows, ShowOwnedPopups(FALSE) generates
3027 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3028 * regardless of the state of the owner
3030 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3031 continue;
3034 WIN_ReleasePtr( pWnd );
3036 HeapFree( GetProcessHeap(), 0, win_array );
3037 return TRUE;
3041 /*******************************************************************
3042 * GetLastActivePopup (USER32.@)
3044 HWND WINAPI GetLastActivePopup( HWND hwnd )
3046 HWND retval = hwnd;
3048 SERVER_START_REQ( get_window_info )
3050 req->handle = wine_server_user_handle( hwnd );
3051 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3053 SERVER_END_REQ;
3054 return retval;
3058 /*******************************************************************
3059 * WIN_ListChildren
3061 * Build an array of the children of a given window. The array must be
3062 * freed with HeapFree. Returns NULL when no windows are found.
3064 HWND *WIN_ListChildren( HWND hwnd )
3066 if (!hwnd)
3068 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3069 return NULL;
3071 return list_window_children( 0, hwnd, NULL, 0 );
3075 /*******************************************************************
3076 * EnumWindows (USER32.@)
3078 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3080 HWND *list;
3081 BOOL ret = TRUE;
3082 int i;
3084 USER_CheckNotLock();
3086 /* We have to build a list of all windows first, to avoid */
3087 /* unpleasant side-effects, for instance if the callback */
3088 /* function changes the Z-order of the windows. */
3090 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3092 /* Now call the callback function for every window */
3094 for (i = 0; list[i]; i++)
3096 /* Make sure that the window still exists */
3097 if (!IsWindow( list[i] )) continue;
3098 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3100 HeapFree( GetProcessHeap(), 0, list );
3101 return ret;
3105 /**********************************************************************
3106 * EnumThreadWindows (USER32.@)
3108 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3110 HWND *list;
3111 int i;
3112 BOOL ret = TRUE;
3114 USER_CheckNotLock();
3116 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3118 /* Now call the callback function for every window */
3120 for (i = 0; list[i]; i++)
3121 if (!(ret = func( list[i], lParam ))) break;
3122 HeapFree( GetProcessHeap(), 0, list );
3123 return ret;
3127 /***********************************************************************
3128 * EnumDesktopWindows (USER32.@)
3130 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3132 HWND *list;
3133 int i;
3135 USER_CheckNotLock();
3137 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3139 for (i = 0; list[i]; i++)
3140 if (!func( list[i], lparam )) break;
3141 HeapFree( GetProcessHeap(), 0, list );
3142 return TRUE;
3146 /**********************************************************************
3147 * WIN_EnumChildWindows
3149 * Helper function for EnumChildWindows().
3151 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3153 HWND *childList;
3154 BOOL ret = FALSE;
3156 for ( ; *list; list++)
3158 /* Make sure that the window still exists */
3159 if (!IsWindow( *list )) continue;
3160 /* Build children list first */
3161 childList = WIN_ListChildren( *list );
3163 ret = func( *list, lParam );
3165 if (childList)
3167 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3168 HeapFree( GetProcessHeap(), 0, childList );
3170 if (!ret) return FALSE;
3172 return TRUE;
3176 /**********************************************************************
3177 * EnumChildWindows (USER32.@)
3179 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3181 HWND *list;
3182 BOOL ret;
3184 USER_CheckNotLock();
3186 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3187 ret = WIN_EnumChildWindows( list, func, lParam );
3188 HeapFree( GetProcessHeap(), 0, list );
3189 return ret;
3193 /*******************************************************************
3194 * AnyPopup (USER32.@)
3196 BOOL WINAPI AnyPopup(void)
3198 int i;
3199 BOOL retvalue;
3200 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3202 if (!list) return FALSE;
3203 for (i = 0; list[i]; i++)
3205 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3207 retvalue = (list[i] != 0);
3208 HeapFree( GetProcessHeap(), 0, list );
3209 return retvalue;
3213 /*******************************************************************
3214 * FlashWindow (USER32.@)
3216 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3218 WND *wndPtr;
3220 TRACE("%p\n", hWnd);
3222 if (IsIconic( hWnd ))
3224 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3226 wndPtr = WIN_GetPtr(hWnd);
3227 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3228 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3230 wndPtr->flags |= WIN_NCACTIVATED;
3232 else
3234 wndPtr->flags &= ~WIN_NCACTIVATED;
3236 WIN_ReleasePtr( wndPtr );
3237 return TRUE;
3239 else
3241 WPARAM wparam;
3243 wndPtr = WIN_GetPtr(hWnd);
3244 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3245 hWnd = wndPtr->obj.handle; /* make it a full handle */
3247 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3248 else wparam = (hWnd == GetForegroundWindow());
3250 WIN_ReleasePtr( wndPtr );
3251 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3252 return wparam;
3256 /*******************************************************************
3257 * FlashWindowEx (USER32.@)
3259 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3261 FIXME("%p\n", pfwi);
3262 return TRUE;
3265 /*******************************************************************
3266 * GetWindowContextHelpId (USER32.@)
3268 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3270 DWORD retval;
3271 WND *wnd = WIN_GetPtr( hwnd );
3272 if (!wnd || wnd == WND_DESKTOP) return 0;
3273 if (wnd == WND_OTHER_PROCESS)
3275 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3276 return 0;
3278 retval = wnd->helpContext;
3279 WIN_ReleasePtr( wnd );
3280 return retval;
3284 /*******************************************************************
3285 * SetWindowContextHelpId (USER32.@)
3287 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3289 WND *wnd = WIN_GetPtr( hwnd );
3290 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3291 if (wnd == WND_OTHER_PROCESS)
3293 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3294 return 0;
3296 wnd->helpContext = id;
3297 WIN_ReleasePtr( wnd );
3298 return TRUE;
3302 /*******************************************************************
3303 * DragDetect (USER32.@)
3305 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3307 MSG msg;
3308 RECT rect;
3309 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3310 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3312 rect.left = pt.x - wDragWidth;
3313 rect.right = pt.x + wDragWidth;
3315 rect.top = pt.y - wDragHeight;
3316 rect.bottom = pt.y + wDragHeight;
3318 SetCapture(hWnd);
3320 while(1)
3322 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3324 if( msg.message == WM_LBUTTONUP )
3326 ReleaseCapture();
3327 return 0;
3329 if( msg.message == WM_MOUSEMOVE )
3331 POINT tmp;
3332 tmp.x = (short)LOWORD(msg.lParam);
3333 tmp.y = (short)HIWORD(msg.lParam);
3334 if( !PtInRect( &rect, tmp ))
3336 ReleaseCapture();
3337 return 1;
3341 WaitMessage();
3343 return 0;
3346 /******************************************************************************
3347 * GetWindowModuleFileNameA (USER32.@)
3349 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3351 WND *win;
3352 HINSTANCE hinst;
3354 TRACE( "%p, %p, %u\n", hwnd, module, size );
3356 win = WIN_GetPtr( hwnd );
3357 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3359 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3360 return 0;
3362 hinst = win->hInstance;
3363 WIN_ReleasePtr( win );
3365 return GetModuleFileNameA( hinst, module, size );
3368 /******************************************************************************
3369 * GetWindowModuleFileNameW (USER32.@)
3371 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3373 WND *win;
3374 HINSTANCE hinst;
3376 TRACE( "%p, %p, %u\n", hwnd, module, size );
3378 win = WIN_GetPtr( hwnd );
3379 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3381 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3382 return 0;
3384 hinst = win->hInstance;
3385 WIN_ReleasePtr( win );
3387 return GetModuleFileNameW( hinst, module, size );
3390 /******************************************************************************
3391 * GetWindowInfo (USER32.@)
3393 * Note: tests show that Windows doesn't check cbSize of the structure.
3395 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3397 if (!pwi) return FALSE;
3398 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3400 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3401 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3402 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3404 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3405 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3407 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3408 pwi->wCreatorVersion = 0x0400;
3410 return TRUE;
3413 /******************************************************************************
3414 * SwitchDesktop (USER32.@)
3416 * NOTES: Sets the current input or interactive desktop.
3418 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3420 FIXME("(hwnd %p) stub!\n", hDesktop);
3421 return TRUE;
3424 /*****************************************************************************
3425 * SetLayeredWindowAttributes (USER32.@)
3427 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3429 BOOL ret;
3431 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3433 SERVER_START_REQ( set_window_layered_info )
3435 req->handle = wine_server_user_handle( hwnd );
3436 req->color_key = key;
3437 req->alpha = alpha;
3438 req->flags = flags;
3439 ret = !wine_server_call_err( req );
3441 SERVER_END_REQ;
3443 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3445 return ret;
3449 /*****************************************************************************
3450 * GetLayeredWindowAttributes (USER32.@)
3452 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3454 BOOL ret;
3456 SERVER_START_REQ( get_window_layered_info )
3458 req->handle = wine_server_user_handle( hwnd );
3459 if ((ret = !wine_server_call_err( req )))
3461 if (key) *key = reply->color_key;
3462 if (alpha) *alpha = reply->alpha;
3463 if (flags) *flags = reply->flags;
3466 SERVER_END_REQ;
3468 return ret;
3472 /*****************************************************************************
3473 * UpdateLayeredWindowIndirect (USER32.@)
3475 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3477 BYTE alpha = 0xff;
3479 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3480 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3482 SetLastError( ERROR_INVALID_PARAMETER );
3483 return FALSE;
3486 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3488 int x = 0, y = 0, cx = 0, cy = 0;
3489 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3491 if (info->pptDst)
3493 x = info->pptDst->x;
3494 y = info->pptDst->y;
3495 flags &= ~SWP_NOMOVE;
3497 if (info->psize)
3499 cx = info->psize->cx;
3500 cy = info->psize->cy;
3501 flags &= ~SWP_NOSIZE;
3503 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3504 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3507 if (info->hdcSrc)
3509 HDC hdc = GetWindowDC( hwnd );
3511 if (hdc)
3513 int x = 0, y = 0;
3514 RECT rect;
3516 GetWindowRect( hwnd, &rect );
3517 OffsetRect( &rect, -rect.left, -rect.top);
3518 if (info->pptSrc)
3520 x = info->pptSrc->x;
3521 y = info->pptSrc->y;
3524 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3526 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3527 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3528 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3530 ReleaseDC( hwnd, hdc );
3534 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3535 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3536 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3537 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3538 return TRUE;
3542 /*****************************************************************************
3543 * UpdateLayeredWindow (USER32.@)
3545 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3546 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3547 DWORD dwFlags)
3549 UPDATELAYEREDWINDOWINFO info;
3551 info.cbSize = sizeof(info);
3552 info.hdcDst = hdcDst;
3553 info.pptDst = pptDst;
3554 info.psize = psize;
3555 info.hdcSrc = hdcSrc;
3556 info.pptSrc = pptSrc;
3557 info.crKey = crKey;
3558 info.pblend = pblend;
3559 info.dwFlags = dwFlags;
3560 info.prcDirty = NULL;
3561 return UpdateLayeredWindowIndirect( hwnd, &info );
3565 /******************************************************************************
3566 * GetProcessDefaultLayout [USER32.@]
3568 * Gets the default layout for parentless windows.
3570 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3572 if (!layout)
3574 SetLastError( ERROR_NOACCESS );
3575 return FALSE;
3577 if (process_layout == ~0u)
3579 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3580 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3581 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3582 '\\','%','0','4','x','%','0','4','x',
3583 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3584 WCHAR *str, buffer[MAX_PATH];
3585 DWORD i, len, version_layout = 0;
3586 DWORD user_lang = GetUserDefaultLangID();
3587 DWORD *languages;
3588 void *data = NULL;
3590 GetModuleFileNameW( 0, buffer, MAX_PATH );
3591 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3592 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3593 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3594 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3596 len /= sizeof(DWORD);
3597 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3598 if (i == len) /* try neutral language */
3599 for (i = 0; i < len; i++)
3600 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3601 if (i == len) i = 0; /* default to the first one */
3603 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3604 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3605 TRACE( "found description %s\n", debugstr_w( str ));
3606 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3608 done:
3609 HeapFree( GetProcessHeap(), 0, data );
3610 process_layout = version_layout;
3612 *layout = process_layout;
3613 return TRUE;
3617 /******************************************************************************
3618 * SetProcessDefaultLayout [USER32.@]
3620 * Sets the default layout for parentless windows.
3622 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3624 process_layout = layout;
3625 return TRUE;
3629 /* 64bit versions */
3631 #ifdef GetWindowLongPtrW
3632 #undef GetWindowLongPtrW
3633 #endif
3635 #ifdef GetWindowLongPtrA
3636 #undef GetWindowLongPtrA
3637 #endif
3639 #ifdef SetWindowLongPtrW
3640 #undef SetWindowLongPtrW
3641 #endif
3643 #ifdef SetWindowLongPtrA
3644 #undef SetWindowLongPtrA
3645 #endif
3647 /*****************************************************************************
3648 * GetWindowLongPtrW (USER32.@)
3650 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3652 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3655 /*****************************************************************************
3656 * GetWindowLongPtrA (USER32.@)
3658 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3660 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3663 /*****************************************************************************
3664 * SetWindowLongPtrW (USER32.@)
3666 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3668 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3671 /*****************************************************************************
3672 * SetWindowLongPtrA (USER32.@)
3674 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3676 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );