urlmon: Improve IUri support for mk: URIs.
[wine/multimedia.git] / dlls / user32 / win.c
blobee4427884e287b9a7afdff611fd10cbecd1cf66f
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->dwExStyle & WS_EX_LAYOUTRTL)
714 mirror_rect( &parent->rectClient, &window_rect );
715 mirror_rect( &parent->rectClient, &client_rect );
717 WIN_ReleasePtr( parent );
719 break;
720 case COORDS_SCREEN:
721 while (win->parent)
723 WND *parent = WIN_GetPtr( win->parent );
724 if (parent == WND_DESKTOP) break;
725 if (!parent || parent == WND_OTHER_PROCESS)
727 WIN_ReleasePtr( win );
728 goto other_process;
730 WIN_ReleasePtr( win );
731 win = parent;
732 OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
733 OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
735 break;
737 if (rectWindow) *rectWindow = window_rect;
738 if (rectClient) *rectClient = client_rect;
739 WIN_ReleasePtr( win );
740 return TRUE;
743 other_process:
744 SERVER_START_REQ( get_window_rectangles )
746 req->handle = wine_server_user_handle( hwnd );
747 req->relative = relative;
748 if ((ret = !wine_server_call_err( req )))
750 if (rectWindow)
752 rectWindow->left = reply->window.left;
753 rectWindow->top = reply->window.top;
754 rectWindow->right = reply->window.right;
755 rectWindow->bottom = reply->window.bottom;
757 if (rectClient)
759 rectClient->left = reply->client.left;
760 rectClient->top = reply->client.top;
761 rectClient->right = reply->client.right;
762 rectClient->bottom = reply->client.bottom;
766 SERVER_END_REQ;
767 return ret;
771 /***********************************************************************
772 * WIN_DestroyWindow
774 * Destroy storage associated to a window. "Internals" p.358
776 LRESULT WIN_DestroyWindow( HWND hwnd )
778 WND *wndPtr;
779 HWND *list;
780 HMENU menu = 0, sys_menu;
781 HWND icon_title;
783 TRACE("%p\n", hwnd );
785 /* free child windows */
786 if ((list = WIN_ListChildren( hwnd )))
788 int i;
789 for (i = 0; list[i]; i++)
791 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
792 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
794 HeapFree( GetProcessHeap(), 0, list );
797 /* Unlink now so we won't bother with the children later on */
798 SERVER_START_REQ( set_parent )
800 req->handle = wine_server_user_handle( hwnd );
801 req->parent = 0;
802 wine_server_call( req );
804 SERVER_END_REQ;
807 * Send the WM_NCDESTROY to the window being destroyed.
809 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
811 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
813 /* free resources associated with the window */
815 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
816 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
817 menu = (HMENU)wndPtr->wIDmenu;
818 sys_menu = wndPtr->hSysMenu;
819 free_dce( wndPtr->dce, hwnd );
820 wndPtr->dce = NULL;
821 icon_title = wndPtr->icon_title;
822 HeapFree( GetProcessHeap(), 0, wndPtr->text );
823 wndPtr->text = NULL;
824 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
825 wndPtr->pScroll = NULL;
826 WIN_ReleasePtr( wndPtr );
828 if (icon_title) DestroyWindow( icon_title );
829 if (menu) DestroyMenu( menu );
830 if (sys_menu) DestroyMenu( sys_menu );
832 USER_Driver->pDestroyWindow( hwnd );
834 free_window_handle( hwnd );
835 return 0;
839 /***********************************************************************
840 * destroy_thread_window
842 * Destroy a window upon exit of its thread.
844 static void destroy_thread_window( HWND hwnd )
846 WND *wndPtr;
847 HWND *list;
848 HMENU menu = 0, sys_menu = 0;
849 WORD index;
851 /* free child windows */
853 if ((list = WIN_ListChildren( hwnd )))
855 int i;
856 for (i = 0; list[i]; i++)
858 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
859 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
861 HeapFree( GetProcessHeap(), 0, list );
864 /* destroy the client-side storage */
866 index = USER_HANDLE_TO_INDEX(hwnd);
867 if (index >= NB_USER_HANDLES) return;
868 USER_Lock();
869 if ((wndPtr = user_handles[index]))
871 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
872 sys_menu = wndPtr->hSysMenu;
873 free_dce( wndPtr->dce, hwnd );
874 InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
876 USER_Unlock();
878 HeapFree( GetProcessHeap(), 0, wndPtr );
879 if (menu) DestroyMenu( menu );
880 if (sys_menu) DestroyMenu( sys_menu );
884 /***********************************************************************
885 * destroy_thread_child_windows
887 * Destroy child windows upon exit of its thread.
889 static void destroy_thread_child_windows( HWND hwnd )
891 HWND *list;
892 int i;
894 if (WIN_IsCurrentThread( hwnd ))
896 destroy_thread_window( hwnd );
898 else if ((list = WIN_ListChildren( hwnd )))
900 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
901 HeapFree( GetProcessHeap(), 0, list );
906 /***********************************************************************
907 * WIN_DestroyThreadWindows
909 * Destroy all children of 'wnd' owned by the current thread.
911 void WIN_DestroyThreadWindows( HWND hwnd )
913 HWND *list;
914 int i;
916 if (!(list = WIN_ListChildren( hwnd ))) return;
918 /* reset owners of top-level windows */
919 for (i = 0; list[i]; i++)
921 if (!WIN_IsCurrentThread( list[i] ))
923 HWND owner = GetWindow( list[i], GW_OWNER );
924 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
928 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
929 HeapFree( GetProcessHeap(), 0, list );
933 /***********************************************************************
934 * WIN_FixCoordinates
936 * Fix the coordinates - Helper for WIN_CreateWindowEx.
937 * returns default show mode in sw.
939 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
941 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
942 POINT pos[2];
944 if (cs->dwExStyle & WS_EX_MDICHILD)
946 UINT id = 0;
948 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
949 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
951 TRACE("MDI child id %04x\n", id);
954 if (cs->style & (WS_CHILD | WS_POPUP))
956 if (cs->dwExStyle & WS_EX_MDICHILD)
958 if (IS_DEFAULT(cs->x))
960 cs->x = pos[0].x;
961 cs->y = pos[0].y;
963 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
964 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
966 else
968 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
969 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
972 else /* overlapped window */
974 HMONITOR monitor;
975 MONITORINFO mon_info;
976 STARTUPINFOW info;
978 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
980 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
981 mon_info.cbSize = sizeof(mon_info);
982 GetMonitorInfoW( monitor, &mon_info );
983 GetStartupInfoW( &info );
985 if (IS_DEFAULT(cs->x))
987 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
988 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
989 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
992 if (IS_DEFAULT(cs->cx))
994 if (info.dwFlags & STARTF_USESIZE)
996 cs->cx = info.dwXSize;
997 cs->cy = info.dwYSize;
999 else
1001 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1002 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1005 /* neither x nor cx are default. Check the y values .
1006 * In the trace we see Outlook and Outlook Express using
1007 * cy set to CW_USEDEFAULT when opening the address book.
1009 else if (IS_DEFAULT(cs->cy))
1011 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1012 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1015 #undef IS_DEFAULT
1018 /***********************************************************************
1019 * dump_window_styles
1021 static void dump_window_styles( DWORD style, DWORD exstyle )
1023 TRACE( "style:" );
1024 if(style & WS_POPUP) TRACE(" WS_POPUP");
1025 if(style & WS_CHILD) TRACE(" WS_CHILD");
1026 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1027 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1028 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1029 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1030 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1031 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1032 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1033 else
1035 if(style & WS_BORDER) TRACE(" WS_BORDER");
1036 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1038 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1039 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1040 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1041 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1042 if (style & WS_CHILD)
1044 if(style & WS_GROUP) TRACE(" WS_GROUP");
1045 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1047 else
1049 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1050 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1053 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1054 #define DUMPED_STYLES \
1055 (WS_POPUP | \
1056 WS_CHILD | \
1057 WS_MINIMIZE | \
1058 WS_VISIBLE | \
1059 WS_DISABLED | \
1060 WS_CLIPSIBLINGS | \
1061 WS_CLIPCHILDREN | \
1062 WS_MAXIMIZE | \
1063 WS_BORDER | \
1064 WS_DLGFRAME | \
1065 WS_VSCROLL | \
1066 WS_HSCROLL | \
1067 WS_SYSMENU | \
1068 WS_THICKFRAME | \
1069 WS_GROUP | \
1070 WS_TABSTOP | \
1071 WS_MINIMIZEBOX | \
1072 WS_MAXIMIZEBOX)
1074 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1075 TRACE("\n");
1076 #undef DUMPED_STYLES
1078 TRACE( "exstyle:" );
1079 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1080 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1081 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1082 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1083 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1084 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1085 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1086 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1087 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1088 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1089 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1090 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1091 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1092 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1093 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1094 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1095 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1096 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1097 if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1099 #define DUMPED_EX_STYLES \
1100 (WS_EX_DLGMODALFRAME | \
1101 WS_EX_DRAGDETECT | \
1102 WS_EX_NOPARENTNOTIFY | \
1103 WS_EX_TOPMOST | \
1104 WS_EX_ACCEPTFILES | \
1105 WS_EX_TRANSPARENT | \
1106 WS_EX_MDICHILD | \
1107 WS_EX_TOOLWINDOW | \
1108 WS_EX_WINDOWEDGE | \
1109 WS_EX_CLIENTEDGE | \
1110 WS_EX_CONTEXTHELP | \
1111 WS_EX_RIGHT | \
1112 WS_EX_RTLREADING | \
1113 WS_EX_LEFTSCROLLBAR | \
1114 WS_EX_CONTROLPARENT | \
1115 WS_EX_STATICEDGE | \
1116 WS_EX_APPWINDOW | \
1117 WS_EX_LAYERED | \
1118 WS_EX_LAYOUTRTL)
1120 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1121 TRACE("\n");
1122 #undef DUMPED_EX_STYLES
1126 /***********************************************************************
1127 * WIN_CreateWindowEx
1129 * Implementation of CreateWindowEx().
1131 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1133 INT cx, cy, style, sw = SW_SHOW;
1134 LRESULT result;
1135 RECT rect;
1136 WND *wndPtr;
1137 HWND hwnd, parent, owner, top_child = 0;
1138 MDICREATESTRUCTW mdi_cs;
1139 CBT_CREATEWNDW cbtc;
1140 CREATESTRUCTW cbcs;
1142 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1143 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1144 debugstr_w(className),
1145 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1146 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1147 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1149 /* Fix the styles for MDI children */
1150 if (cs->dwExStyle & WS_EX_MDICHILD)
1152 UINT flags = 0;
1154 wndPtr = WIN_GetPtr(cs->hwndParent);
1155 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1157 flags = wndPtr->flags;
1158 WIN_ReleasePtr(wndPtr);
1161 if (!(flags & WIN_ISMDICLIENT))
1163 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1164 return 0;
1167 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1168 * MDICREATESTRUCT members have the originally passed values.
1170 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1171 * have the same layout.
1173 mdi_cs.szClass = cs->lpszClass;
1174 mdi_cs.szTitle = cs->lpszName;
1175 mdi_cs.hOwner = cs->hInstance;
1176 mdi_cs.x = cs->x;
1177 mdi_cs.y = cs->y;
1178 mdi_cs.cx = cs->cx;
1179 mdi_cs.cy = cs->cy;
1180 mdi_cs.style = cs->style;
1181 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1183 cs->lpCreateParams = &mdi_cs;
1185 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1187 if (cs->style & WS_POPUP)
1189 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1190 return 0;
1192 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1194 else
1196 cs->style &= ~WS_POPUP;
1197 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1198 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1201 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1203 if (top_child)
1205 /* Restore current maximized child */
1206 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1208 TRACE("Restoring current maximized child %p\n", top_child);
1209 if (cs->style & WS_MAXIMIZE)
1211 /* if the new window is maximized don't bother repainting */
1212 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1213 ShowWindow( top_child, SW_SHOWNORMAL );
1214 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1216 else ShowWindow( top_child, SW_SHOWNORMAL );
1221 /* Find the parent window */
1223 parent = cs->hwndParent;
1224 owner = 0;
1226 if (cs->hwndParent == HWND_MESSAGE)
1228 cs->hwndParent = parent = get_hwnd_message_parent();
1230 else if (cs->hwndParent)
1232 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1234 parent = GetDesktopWindow();
1235 owner = cs->hwndParent;
1237 else
1239 DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1240 if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1241 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1244 else
1246 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1248 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1250 WARN("No parent for child window\n" );
1251 SetLastError(ERROR_TLW_WITH_WSCHILD);
1252 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1254 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1255 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1256 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1258 DWORD layout;
1259 GetProcessDefaultLayout( &layout );
1260 if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1261 parent = GetDesktopWindow();
1265 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1267 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1268 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1269 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1270 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1271 else
1272 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1274 /* Create the window structure */
1276 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1277 return 0;
1278 hwnd = wndPtr->obj.handle;
1280 /* Fill the window structure */
1282 wndPtr->tid = GetCurrentThreadId();
1283 wndPtr->hInstance = cs->hInstance;
1284 wndPtr->text = NULL;
1285 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1286 wndPtr->dwExStyle = cs->dwExStyle;
1287 wndPtr->wIDmenu = 0;
1288 wndPtr->helpContext = 0;
1289 wndPtr->pScroll = NULL;
1290 wndPtr->userdata = 0;
1291 wndPtr->hIcon = 0;
1292 wndPtr->hIconSmall = 0;
1293 wndPtr->hSysMenu = 0;
1295 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1296 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1298 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1301 * Correct the window styles.
1303 * It affects only the style loaded into the WIN structure.
1306 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1308 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1309 if (!(wndPtr->dwStyle & WS_POPUP))
1310 wndPtr->dwStyle |= WS_CAPTION;
1314 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1315 * why does the user get to set it?
1318 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1319 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1320 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1321 else
1322 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1324 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1325 wndPtr->flags |= WIN_NEED_SIZE;
1327 SERVER_START_REQ( set_window_info )
1329 req->handle = wine_server_user_handle( hwnd );
1330 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1331 req->style = wndPtr->dwStyle;
1332 req->ex_style = wndPtr->dwExStyle;
1333 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1334 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1335 req->extra_offset = -1;
1336 wine_server_call( req );
1338 SERVER_END_REQ;
1340 /* Set the window menu */
1342 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1344 if (cs->hMenu)
1346 if (!MENU_SetMenu(hwnd, cs->hMenu))
1348 WIN_ReleasePtr( wndPtr );
1349 free_window_handle( hwnd );
1350 return 0;
1353 else
1355 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1356 if (menuName)
1358 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1359 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1363 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1365 /* call the WH_CBT hook */
1367 /* the window style passed to the hook must be the real window style,
1368 * rather than just the window style that the caller to CreateWindowEx
1369 * passed in, so we have to copy the original CREATESTRUCT and get the
1370 * the real style. */
1371 cbcs = *cs;
1372 cbcs.style = wndPtr->dwStyle;
1373 cbtc.lpcs = &cbcs;
1374 cbtc.hwndInsertAfter = HWND_TOP;
1375 WIN_ReleasePtr( wndPtr );
1376 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1378 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1380 cx = cs->cx;
1381 cy = cs->cy;
1382 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1384 POINT maxSize, maxPos, minTrack, maxTrack;
1385 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1386 if (maxTrack.x < cx) cx = maxTrack.x;
1387 if (maxTrack.y < cy) cy = maxTrack.y;
1388 if (minTrack.x > cx) cx = minTrack.x;
1389 if (minTrack.y > cy) cy = minTrack.y;
1392 if (cx < 0) cx = 0;
1393 if (cy < 0) cy = 0;
1394 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1395 /* check for wraparound */
1396 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1397 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1398 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1400 /* send WM_NCCREATE */
1402 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1403 if (unicode)
1404 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1405 else
1406 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1407 if (!result)
1409 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1410 goto failed;
1413 /* send WM_NCCALCSIZE */
1415 if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1417 /* yes, even if the CBT hook was called with HWND_TOP */
1418 HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1419 RECT client_rect = rect;
1421 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1422 MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1423 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1424 MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1425 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1427 else return 0;
1429 /* send WM_CREATE */
1431 if (unicode)
1432 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1433 else
1434 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1435 if (result == -1) goto failed;
1437 /* call the driver */
1439 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1441 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1443 /* send the size messages */
1445 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1446 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1447 if (!(wndPtr->flags & WIN_NEED_SIZE))
1449 WIN_ReleasePtr( wndPtr );
1450 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1451 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1452 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1453 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1455 else WIN_ReleasePtr( wndPtr );
1457 /* Show the window, maximizing or minimizing if needed */
1459 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1460 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1462 RECT newPos;
1463 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1465 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1466 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1467 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1468 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1469 newPos.bottom - newPos.top, swFlag );
1472 /* Notify the parent window only */
1474 send_parent_notify( hwnd, WM_CREATE );
1475 if (!IsWindow( hwnd )) return 0;
1477 if (cs->style & WS_VISIBLE)
1479 if (cs->style & WS_MAXIMIZE)
1480 sw = SW_SHOW;
1481 else if (cs->style & WS_MINIMIZE)
1482 sw = SW_SHOWMINIMIZED;
1484 ShowWindow( hwnd, sw );
1485 if (cs->dwExStyle & WS_EX_MDICHILD)
1487 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1488 /* ShowWindow won't activate child windows */
1489 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1493 /* Call WH_SHELL hook */
1495 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1496 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1498 TRACE("created window %p\n", hwnd);
1499 return hwnd;
1501 failed:
1502 WIN_DestroyWindow( hwnd );
1503 return 0;
1507 /***********************************************************************
1508 * CreateWindowExA (USER32.@)
1510 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1511 LPCSTR windowName, DWORD style, INT x,
1512 INT y, INT width, INT height,
1513 HWND parent, HMENU menu,
1514 HINSTANCE instance, LPVOID data )
1516 CREATESTRUCTA cs;
1518 cs.lpCreateParams = data;
1519 cs.hInstance = instance;
1520 cs.hMenu = menu;
1521 cs.hwndParent = parent;
1522 cs.x = x;
1523 cs.y = y;
1524 cs.cx = width;
1525 cs.cy = height;
1526 cs.style = style;
1527 cs.lpszName = windowName;
1528 cs.lpszClass = className;
1529 cs.dwExStyle = exStyle;
1531 if (!IS_INTRESOURCE(className))
1533 WCHAR bufferW[256];
1534 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1535 return 0;
1536 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1538 /* Note: we rely on the fact that CREATESTRUCTA and */
1539 /* CREATESTRUCTW have the same layout. */
1540 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1544 /***********************************************************************
1545 * CreateWindowExW (USER32.@)
1547 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1548 LPCWSTR windowName, DWORD style, INT x,
1549 INT y, INT width, INT height,
1550 HWND parent, HMENU menu,
1551 HINSTANCE instance, LPVOID data )
1553 CREATESTRUCTW cs;
1555 cs.lpCreateParams = data;
1556 cs.hInstance = instance;
1557 cs.hMenu = menu;
1558 cs.hwndParent = parent;
1559 cs.x = x;
1560 cs.y = y;
1561 cs.cx = width;
1562 cs.cy = height;
1563 cs.style = style;
1564 cs.lpszName = windowName;
1565 cs.lpszClass = className;
1566 cs.dwExStyle = exStyle;
1568 return wow_handlers.create_window( &cs, className, instance, TRUE );
1572 /***********************************************************************
1573 * WIN_SendDestroyMsg
1575 static void WIN_SendDestroyMsg( HWND hwnd )
1577 GUITHREADINFO info;
1579 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1581 if (hwnd == info.hwndCaret) DestroyCaret();
1582 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1586 * Send the WM_DESTROY to the window.
1588 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1591 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1592 * make sure that the window still exists when we come back.
1594 if (IsWindow(hwnd))
1596 HWND* pWndArray;
1597 int i;
1599 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1601 for (i = 0; pWndArray[i]; i++)
1603 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1605 HeapFree( GetProcessHeap(), 0, pWndArray );
1607 else
1608 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1612 /***********************************************************************
1613 * DestroyWindow (USER32.@)
1615 BOOL WINAPI DestroyWindow( HWND hwnd )
1617 BOOL is_child;
1619 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1621 SetLastError( ERROR_ACCESS_DENIED );
1622 return FALSE;
1625 TRACE("(%p)\n", hwnd);
1627 /* Call hooks */
1629 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1631 if (MENU_IsMenuActive() == hwnd)
1632 EndMenu();
1634 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1636 if (is_child)
1638 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1639 send_parent_notify( hwnd, WM_DESTROY );
1641 else if (!GetWindow( hwnd, GW_OWNER ))
1643 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1644 /* FIXME: clean up palette - see "Internals" p.352 */
1647 if (!IsWindow(hwnd)) return TRUE;
1649 /* Hide the window */
1650 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1652 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1653 if (is_child)
1654 ShowWindow( hwnd, SW_HIDE );
1655 else
1656 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1657 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1660 if (!IsWindow(hwnd)) return TRUE;
1662 /* Recursively destroy owned windows */
1664 if (!is_child)
1666 for (;;)
1668 int i, got_one = 0;
1669 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1670 if (list)
1672 for (i = 0; list[i]; i++)
1674 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1675 if (WIN_IsCurrentThread( list[i] ))
1677 DestroyWindow( list[i] );
1678 got_one = 1;
1679 continue;
1681 WIN_SetOwner( list[i], 0 );
1683 HeapFree( GetProcessHeap(), 0, list );
1685 if (!got_one) break;
1689 /* Send destroy messages */
1691 WIN_SendDestroyMsg( hwnd );
1692 if (!IsWindow( hwnd )) return TRUE;
1694 if (GetClipboardOwner() == hwnd)
1695 CLIPBOARD_ReleaseOwner();
1697 /* Destroy the window storage */
1699 WIN_DestroyWindow( hwnd );
1700 return TRUE;
1704 /***********************************************************************
1705 * CloseWindow (USER32.@)
1707 BOOL WINAPI CloseWindow( HWND hwnd )
1709 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1710 ShowWindow( hwnd, SW_MINIMIZE );
1711 return TRUE;
1715 /***********************************************************************
1716 * OpenIcon (USER32.@)
1718 BOOL WINAPI OpenIcon( HWND hwnd )
1720 if (!IsIconic( hwnd )) return FALSE;
1721 ShowWindow( hwnd, SW_SHOWNORMAL );
1722 return TRUE;
1726 /***********************************************************************
1727 * FindWindowExW (USER32.@)
1729 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1731 HWND *list = NULL;
1732 HWND retvalue = 0;
1733 int i = 0, len = 0;
1734 WCHAR *buffer = NULL;
1736 if (!parent && child) parent = GetDesktopWindow();
1737 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1739 if (title)
1741 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1742 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1745 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1747 if (child)
1749 child = WIN_GetFullHandle( child );
1750 while (list[i] && list[i] != child) i++;
1751 if (!list[i]) goto done;
1752 i++; /* start from next window */
1755 if (title)
1757 while (list[i])
1759 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1760 i++;
1763 retvalue = list[i];
1765 done:
1766 HeapFree( GetProcessHeap(), 0, list );
1767 HeapFree( GetProcessHeap(), 0, buffer );
1768 return retvalue;
1773 /***********************************************************************
1774 * FindWindowA (USER32.@)
1776 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1778 HWND ret = FindWindowExA( 0, 0, className, title );
1779 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1780 return ret;
1784 /***********************************************************************
1785 * FindWindowExA (USER32.@)
1787 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1789 LPWSTR titleW = NULL;
1790 HWND hwnd = 0;
1792 if (title)
1794 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1795 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1796 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1799 if (!IS_INTRESOURCE(className))
1801 WCHAR classW[256];
1802 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1803 hwnd = FindWindowExW( parent, child, classW, titleW );
1805 else
1807 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1810 HeapFree( GetProcessHeap(), 0, titleW );
1811 return hwnd;
1815 /***********************************************************************
1816 * FindWindowW (USER32.@)
1818 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1820 return FindWindowExW( 0, 0, className, title );
1824 /**********************************************************************
1825 * GetDesktopWindow (USER32.@)
1827 HWND WINAPI GetDesktopWindow(void)
1829 struct user_thread_info *thread_info = get_user_thread_info();
1831 if (thread_info->top_window) return thread_info->top_window;
1833 SERVER_START_REQ( get_desktop_window )
1835 req->force = 0;
1836 if (!wine_server_call( req ))
1838 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1839 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1842 SERVER_END_REQ;
1844 if (!thread_info->top_window)
1846 USEROBJECTFLAGS flags;
1847 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1848 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1850 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1851 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1852 STARTUPINFOW si;
1853 PROCESS_INFORMATION pi;
1854 WCHAR windir[MAX_PATH];
1855 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1856 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1857 void *redir;
1859 memset( &si, 0, sizeof(si) );
1860 si.cb = sizeof(si);
1861 si.dwFlags = STARTF_USESTDHANDLES;
1862 si.hStdInput = 0;
1863 si.hStdOutput = 0;
1864 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1866 GetSystemDirectoryW( windir, MAX_PATH );
1867 strcpyW( app, windir );
1868 strcatW( app, explorer );
1869 strcpyW( cmdline, app );
1870 strcatW( cmdline, args );
1872 Wow64DisableWow64FsRedirection( &redir );
1873 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1874 NULL, windir, &si, &pi ))
1876 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1877 WaitForInputIdle( pi.hProcess, 10000 );
1878 CloseHandle( pi.hThread );
1879 CloseHandle( pi.hProcess );
1881 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1882 Wow64RevertWow64FsRedirection( redir );
1884 else TRACE( "not starting explorer since winstation is not visible\n" );
1886 SERVER_START_REQ( get_desktop_window )
1888 req->force = 1;
1889 if (!wine_server_call( req ))
1891 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1892 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1895 SERVER_END_REQ;
1898 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1899 ERR( "failed to create desktop window\n" );
1901 return thread_info->top_window;
1905 /*******************************************************************
1906 * EnableWindow (USER32.@)
1908 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1910 BOOL retvalue;
1911 HWND full_handle;
1913 if (is_broadcast(hwnd))
1915 SetLastError( ERROR_INVALID_PARAMETER );
1916 return FALSE;
1919 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1920 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1922 hwnd = full_handle;
1924 TRACE("( %p, %d )\n", hwnd, enable);
1926 retvalue = !IsWindowEnabled( hwnd );
1928 if (enable && retvalue)
1930 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1931 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1933 else if (!enable && !retvalue)
1935 HWND capture_wnd;
1937 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1939 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1941 if (hwnd == GetFocus())
1942 SetFocus( 0 ); /* A disabled window can't have the focus */
1944 capture_wnd = GetCapture();
1945 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1946 ReleaseCapture(); /* A disabled window can't capture the mouse */
1948 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1950 return retvalue;
1954 /***********************************************************************
1955 * IsWindowEnabled (USER32.@)
1957 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1959 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1963 /***********************************************************************
1964 * IsWindowUnicode (USER32.@)
1966 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1968 WND * wndPtr;
1969 BOOL retvalue = FALSE;
1971 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1973 if (wndPtr == WND_DESKTOP) return TRUE;
1975 if (wndPtr != WND_OTHER_PROCESS)
1977 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1978 WIN_ReleasePtr( wndPtr );
1980 else
1982 SERVER_START_REQ( get_window_info )
1984 req->handle = wine_server_user_handle( hwnd );
1985 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1987 SERVER_END_REQ;
1989 return retvalue;
1993 /**********************************************************************
1994 * WIN_GetWindowLong
1996 * Helper function for GetWindowLong().
1998 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2000 LONG_PTR retvalue = 0;
2001 WND *wndPtr;
2003 if (offset == GWLP_HWNDPARENT)
2005 HWND parent = GetAncestor( hwnd, GA_PARENT );
2006 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2007 return (ULONG_PTR)parent;
2010 if (!(wndPtr = WIN_GetPtr( hwnd )))
2012 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2013 return 0;
2016 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2018 if (offset == GWLP_WNDPROC)
2020 SetLastError( ERROR_ACCESS_DENIED );
2021 return 0;
2023 SERVER_START_REQ( set_window_info )
2025 req->handle = wine_server_user_handle( hwnd );
2026 req->flags = 0; /* don't set anything, just retrieve */
2027 req->extra_offset = (offset >= 0) ? offset : -1;
2028 req->extra_size = (offset >= 0) ? size : 0;
2029 if (!wine_server_call_err( req ))
2031 switch(offset)
2033 case GWL_STYLE: retvalue = reply->old_style; break;
2034 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2035 case GWLP_ID: retvalue = reply->old_id; break;
2036 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2037 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2038 default:
2039 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2040 else SetLastError( ERROR_INVALID_INDEX );
2041 break;
2045 SERVER_END_REQ;
2046 return retvalue;
2049 /* now we have a valid wndPtr */
2051 if (offset >= 0)
2053 if (offset > (int)(wndPtr->cbWndExtra - size))
2055 WARN("Invalid offset %d\n", offset );
2056 WIN_ReleasePtr( wndPtr );
2057 SetLastError( ERROR_INVALID_INDEX );
2058 return 0;
2060 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2062 /* Special case for dialog window procedure */
2063 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2064 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2065 WIN_ReleasePtr( wndPtr );
2066 return retvalue;
2069 switch(offset)
2071 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2072 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2073 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2074 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2075 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2076 case GWLP_WNDPROC:
2077 /* This looks like a hack only for the edit control (see tests). This makes these controls
2078 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2079 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2081 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2082 retvalue = (ULONG_PTR)wndPtr->winproc;
2083 else
2084 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2085 break;
2086 default:
2087 WARN("Unknown offset %d\n", offset );
2088 SetLastError( ERROR_INVALID_INDEX );
2089 break;
2091 WIN_ReleasePtr(wndPtr);
2092 return retvalue;
2096 /**********************************************************************
2097 * WIN_SetWindowLong
2099 * Helper function for SetWindowLong().
2101 * 0 is the failure code. However, in the case of failure SetLastError
2102 * must be set to distinguish between a 0 return value and a failure.
2104 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2106 STYLESTRUCT style;
2107 BOOL ok;
2108 LONG_PTR retval = 0;
2109 WND *wndPtr;
2111 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2113 if (is_broadcast(hwnd))
2115 SetLastError( ERROR_INVALID_PARAMETER );
2116 return FALSE;
2119 if (!(wndPtr = WIN_GetPtr( hwnd )))
2121 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2122 return 0;
2124 if (wndPtr == WND_DESKTOP)
2126 /* can't change anything on the desktop window */
2127 SetLastError( ERROR_ACCESS_DENIED );
2128 return 0;
2130 if (wndPtr == WND_OTHER_PROCESS)
2132 if (offset == GWLP_WNDPROC)
2134 SetLastError( ERROR_ACCESS_DENIED );
2135 return 0;
2137 if (offset > 32767 || offset < -32767)
2139 SetLastError( ERROR_INVALID_INDEX );
2140 return 0;
2142 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2145 /* first some special cases */
2146 switch( offset )
2148 case GWL_STYLE:
2149 style.styleOld = wndPtr->dwStyle;
2150 style.styleNew = newval;
2151 WIN_ReleasePtr( wndPtr );
2152 SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2153 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2154 newval = style.styleNew;
2155 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2156 if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2157 break;
2158 case GWL_EXSTYLE:
2159 style.styleOld = wndPtr->dwExStyle;
2160 style.styleNew = newval;
2161 WIN_ReleasePtr( wndPtr );
2162 SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2163 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2164 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2165 newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2166 /* WS_EX_WINDOWEDGE depends on some other styles */
2167 if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2168 newval |= WS_EX_WINDOWEDGE;
2169 else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2170 newval &= ~WS_EX_WINDOWEDGE;
2171 break;
2172 case GWLP_HWNDPARENT:
2173 if (wndPtr->parent == GetDesktopWindow())
2175 WIN_ReleasePtr( wndPtr );
2176 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2178 else
2180 WIN_ReleasePtr( wndPtr );
2181 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2183 case GWLP_WNDPROC:
2185 WNDPROC proc;
2186 UINT old_flags = wndPtr->flags;
2187 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2188 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2189 if (proc) wndPtr->winproc = proc;
2190 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2191 else wndPtr->flags &= ~WIN_ISUNICODE;
2192 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2194 WIN_ReleasePtr( wndPtr );
2195 return retval;
2197 /* update is_unicode flag on the server side */
2198 break;
2200 case GWLP_ID:
2201 case GWLP_HINSTANCE:
2202 case GWLP_USERDATA:
2203 break;
2204 case DWLP_DLGPROC:
2205 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2206 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2208 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2209 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2210 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2211 WIN_ReleasePtr( wndPtr );
2212 return retval;
2214 /* fall through */
2215 default:
2216 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2218 WARN("Invalid offset %d\n", offset );
2219 WIN_ReleasePtr( wndPtr );
2220 SetLastError( ERROR_INVALID_INDEX );
2221 return 0;
2223 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2225 /* already set to the same value */
2226 WIN_ReleasePtr( wndPtr );
2227 return newval;
2229 break;
2232 SERVER_START_REQ( set_window_info )
2234 req->handle = wine_server_user_handle( hwnd );
2235 req->extra_offset = -1;
2236 switch(offset)
2238 case GWL_STYLE:
2239 req->flags = SET_WIN_STYLE;
2240 req->style = newval;
2241 break;
2242 case GWL_EXSTYLE:
2243 req->flags = SET_WIN_EXSTYLE;
2244 req->ex_style = newval;
2245 break;
2246 case GWLP_ID:
2247 req->flags = SET_WIN_ID;
2248 req->id = newval;
2249 break;
2250 case GWLP_HINSTANCE:
2251 req->flags = SET_WIN_INSTANCE;
2252 req->instance = wine_server_client_ptr( (void *)newval );
2253 break;
2254 case GWLP_WNDPROC:
2255 req->flags = SET_WIN_UNICODE;
2256 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2257 break;
2258 case GWLP_USERDATA:
2259 req->flags = SET_WIN_USERDATA;
2260 req->user_data = newval;
2261 break;
2262 default:
2263 req->flags = SET_WIN_EXTRA;
2264 req->extra_offset = offset;
2265 req->extra_size = size;
2266 set_win_data( &req->extra_value, newval, size );
2268 if ((ok = !wine_server_call_err( req )))
2270 switch(offset)
2272 case GWL_STYLE:
2273 wndPtr->dwStyle = newval;
2274 retval = reply->old_style;
2275 break;
2276 case GWL_EXSTYLE:
2277 wndPtr->dwExStyle = newval;
2278 retval = reply->old_ex_style;
2279 break;
2280 case GWLP_ID:
2281 wndPtr->wIDmenu = newval;
2282 retval = reply->old_id;
2283 break;
2284 case GWLP_HINSTANCE:
2285 wndPtr->hInstance = (HINSTANCE)newval;
2286 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2287 break;
2288 case GWLP_WNDPROC:
2289 break;
2290 case GWLP_USERDATA:
2291 wndPtr->userdata = newval;
2292 retval = reply->old_user_data;
2293 break;
2294 default:
2295 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2296 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2297 break;
2301 SERVER_END_REQ;
2302 WIN_ReleasePtr( wndPtr );
2304 if (!ok) return 0;
2306 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2308 style.styleOld = retval;
2309 style.styleNew = newval;
2310 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2311 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2314 return retval;
2318 /**********************************************************************
2319 * GetWindowWord (USER32.@)
2321 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2323 switch(offset)
2325 case GWLP_ID:
2326 case GWLP_HINSTANCE:
2327 case GWLP_HWNDPARENT:
2328 break;
2329 default:
2330 if (offset < 0)
2332 WARN("Invalid offset %d\n", offset );
2333 SetLastError( ERROR_INVALID_INDEX );
2334 return 0;
2336 break;
2338 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2342 /**********************************************************************
2343 * GetWindowLongA (USER32.@)
2345 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2347 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2351 /**********************************************************************
2352 * GetWindowLongW (USER32.@)
2354 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2356 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2360 /**********************************************************************
2361 * SetWindowWord (USER32.@)
2363 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2365 switch(offset)
2367 case GWLP_ID:
2368 case GWLP_HINSTANCE:
2369 case GWLP_HWNDPARENT:
2370 break;
2371 default:
2372 if (offset < 0)
2374 WARN("Invalid offset %d\n", offset );
2375 SetLastError( ERROR_INVALID_INDEX );
2376 return 0;
2378 break;
2380 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2384 /**********************************************************************
2385 * SetWindowLongA (USER32.@)
2387 * See SetWindowLongW.
2389 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2391 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2395 /**********************************************************************
2396 * SetWindowLongW (USER32.@) Set window attribute
2398 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2399 * value in a window's extra memory.
2401 * The _hwnd_ parameter specifies the window. is the handle to a
2402 * window that has extra memory. The _newval_ parameter contains the
2403 * new attribute or extra memory value. If positive, the _offset_
2404 * parameter is the byte-addressed location in the window's extra
2405 * memory to set. If negative, _offset_ specifies the window
2406 * attribute to set, and should be one of the following values:
2408 * GWL_EXSTYLE The window's extended window style
2410 * GWL_STYLE The window's window style.
2412 * GWLP_WNDPROC Pointer to the window's window procedure.
2414 * GWLP_HINSTANCE The window's pplication instance handle.
2416 * GWLP_ID The window's identifier.
2418 * GWLP_USERDATA The window's user-specified data.
2420 * If the window is a dialog box, the _offset_ parameter can be one of
2421 * the following values:
2423 * DWLP_DLGPROC The address of the window's dialog box procedure.
2425 * DWLP_MSGRESULT The return value of a message
2426 * that the dialog box procedure processed.
2428 * DWLP_USER Application specific information.
2430 * RETURNS
2432 * If successful, returns the previous value located at _offset_. Otherwise,
2433 * returns 0.
2435 * NOTES
2437 * Extra memory for a window class is specified by a nonzero cbWndExtra
2438 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2439 * time of class creation.
2441 * Using GWL_WNDPROC to set a new window procedure effectively creates
2442 * a window subclass. Use CallWindowProc() in the new windows procedure
2443 * to pass messages to the superclass's window procedure.
2445 * The user data is reserved for use by the application which created
2446 * the window.
2448 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2449 * instead, call the EnableWindow() function to change the window's
2450 * disabled state.
2452 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2453 * SetParent() instead.
2455 * Win95:
2456 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2457 * it sends WM_STYLECHANGING before changing the settings
2458 * and WM_STYLECHANGED afterwards.
2459 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2461 LONG WINAPI SetWindowLongW(
2462 HWND hwnd, /* [in] window to alter */
2463 INT offset, /* [in] offset, in bytes, of location to alter */
2464 LONG newval /* [in] new value of location */
2466 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2470 /*******************************************************************
2471 * GetWindowTextA (USER32.@)
2473 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2475 WCHAR *buffer;
2477 if (!lpString) return 0;
2479 if (WIN_IsCurrentProcess( hwnd ))
2480 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2482 /* when window belongs to other process, don't send a message */
2483 if (nMaxCount <= 0) return 0;
2484 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2485 get_server_window_text( hwnd, buffer, nMaxCount );
2486 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2487 lpString[nMaxCount-1] = 0;
2488 HeapFree( GetProcessHeap(), 0, buffer );
2489 return strlen(lpString);
2493 /*******************************************************************
2494 * InternalGetWindowText (USER32.@)
2496 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2498 WND *win;
2500 if (nMaxCount <= 0) return 0;
2501 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2502 if (win == WND_DESKTOP) lpString[0] = 0;
2503 else if (win != WND_OTHER_PROCESS)
2505 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2506 else lpString[0] = 0;
2507 WIN_ReleasePtr( win );
2509 else
2511 get_server_window_text( hwnd, lpString, nMaxCount );
2513 return strlenW(lpString);
2517 /*******************************************************************
2518 * GetWindowTextW (USER32.@)
2520 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2522 if (!lpString) return 0;
2524 if (WIN_IsCurrentProcess( hwnd ))
2525 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2527 /* when window belongs to other process, don't send a message */
2528 if (nMaxCount <= 0) return 0;
2529 get_server_window_text( hwnd, lpString, nMaxCount );
2530 return strlenW(lpString);
2534 /*******************************************************************
2535 * SetWindowTextA (USER32.@)
2536 * SetWindowText (USER32.@)
2538 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2540 if (is_broadcast(hwnd))
2542 SetLastError( ERROR_INVALID_PARAMETER );
2543 return FALSE;
2545 if (!WIN_IsCurrentProcess( hwnd ))
2546 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2547 debugstr_a(lpString), hwnd );
2548 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2552 /*******************************************************************
2553 * SetWindowTextW (USER32.@)
2555 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2557 if (is_broadcast(hwnd))
2559 SetLastError( ERROR_INVALID_PARAMETER );
2560 return FALSE;
2562 if (!WIN_IsCurrentProcess( hwnd ))
2563 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2564 debugstr_w(lpString), hwnd );
2565 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2569 /*******************************************************************
2570 * GetWindowTextLengthA (USER32.@)
2572 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2574 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2577 /*******************************************************************
2578 * GetWindowTextLengthW (USER32.@)
2580 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2582 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2586 /*******************************************************************
2587 * IsWindow (USER32.@)
2589 BOOL WINAPI IsWindow( HWND hwnd )
2591 WND *ptr;
2592 BOOL ret;
2594 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2595 if (ptr == WND_DESKTOP) return TRUE;
2597 if (ptr != WND_OTHER_PROCESS)
2599 WIN_ReleasePtr( ptr );
2600 return TRUE;
2603 /* check other processes */
2604 SERVER_START_REQ( get_window_info )
2606 req->handle = wine_server_user_handle( hwnd );
2607 ret = !wine_server_call_err( req );
2609 SERVER_END_REQ;
2610 return ret;
2614 /***********************************************************************
2615 * GetWindowThreadProcessId (USER32.@)
2617 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2619 WND *ptr;
2620 DWORD tid = 0;
2622 if (!(ptr = WIN_GetPtr( hwnd )))
2624 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2625 return 0;
2628 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2630 /* got a valid window */
2631 tid = ptr->tid;
2632 if (process) *process = GetCurrentProcessId();
2633 WIN_ReleasePtr( ptr );
2634 return tid;
2637 /* check other processes */
2638 SERVER_START_REQ( get_window_info )
2640 req->handle = wine_server_user_handle( hwnd );
2641 if (!wine_server_call_err( req ))
2643 tid = (DWORD)reply->tid;
2644 if (process) *process = (DWORD)reply->pid;
2647 SERVER_END_REQ;
2648 return tid;
2652 /*****************************************************************
2653 * GetParent (USER32.@)
2655 HWND WINAPI GetParent( HWND hwnd )
2657 WND *wndPtr;
2658 HWND retvalue = 0;
2660 if (!(wndPtr = WIN_GetPtr( hwnd )))
2662 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2663 return 0;
2665 if (wndPtr == WND_DESKTOP) return 0;
2666 if (wndPtr == WND_OTHER_PROCESS)
2668 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2669 if (style & (WS_POPUP | WS_CHILD))
2671 SERVER_START_REQ( get_window_tree )
2673 req->handle = wine_server_user_handle( hwnd );
2674 if (!wine_server_call_err( req ))
2676 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2677 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2680 SERVER_END_REQ;
2683 else
2685 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2686 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2687 WIN_ReleasePtr( wndPtr );
2689 return retvalue;
2693 /*****************************************************************
2694 * GetAncestor (USER32.@)
2696 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2698 WND *win;
2699 HWND *list, ret = 0;
2701 switch(type)
2703 case GA_PARENT:
2704 if (!(win = WIN_GetPtr( hwnd )))
2706 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2707 return 0;
2709 if (win == WND_DESKTOP) return 0;
2710 if (win != WND_OTHER_PROCESS)
2712 ret = win->parent;
2713 WIN_ReleasePtr( win );
2715 else /* need to query the server */
2717 SERVER_START_REQ( get_window_tree )
2719 req->handle = wine_server_user_handle( hwnd );
2720 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2722 SERVER_END_REQ;
2724 break;
2726 case GA_ROOT:
2727 if (!(list = list_window_parents( hwnd ))) return 0;
2729 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2730 else
2732 int count = 2;
2733 while (list[count]) count++;
2734 ret = list[count - 2]; /* get the one before the desktop */
2736 HeapFree( GetProcessHeap(), 0, list );
2737 break;
2739 case GA_ROOTOWNER:
2740 if (is_desktop_window( hwnd )) return 0;
2741 ret = WIN_GetFullHandle( hwnd );
2742 for (;;)
2744 HWND parent = GetParent( ret );
2745 if (!parent) break;
2746 ret = parent;
2748 break;
2750 return ret;
2754 /*****************************************************************
2755 * SetParent (USER32.@)
2757 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2759 HWND full_handle;
2760 HWND old_parent = 0;
2761 BOOL was_visible;
2762 WND *wndPtr;
2763 BOOL ret;
2765 if (is_broadcast(hwnd) || is_broadcast(parent))
2767 SetLastError(ERROR_INVALID_PARAMETER);
2768 return 0;
2771 if (!parent) parent = GetDesktopWindow();
2772 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2773 else parent = WIN_GetFullHandle( parent );
2775 if (!IsWindow( parent ))
2777 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2778 return 0;
2781 /* Some applications try to set a child as a parent */
2782 if (IsChild(hwnd, parent))
2784 SetLastError( ERROR_INVALID_PARAMETER );
2785 return 0;
2788 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2789 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2791 if (full_handle == parent)
2793 SetLastError( ERROR_INVALID_PARAMETER );
2794 return 0;
2797 /* Windows hides the window first, then shows it again
2798 * including the WM_SHOWWINDOW messages and all */
2799 was_visible = ShowWindow( hwnd, SW_HIDE );
2801 wndPtr = WIN_GetPtr( hwnd );
2802 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2804 SERVER_START_REQ( set_parent )
2806 req->handle = wine_server_user_handle( hwnd );
2807 req->parent = wine_server_user_handle( parent );
2808 if ((ret = !wine_server_call( req )))
2810 old_parent = wine_server_ptr_handle( reply->old_parent );
2811 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2815 SERVER_END_REQ;
2816 WIN_ReleasePtr( wndPtr );
2817 if (!ret) return 0;
2819 USER_Driver->pSetParent( full_handle, parent, old_parent );
2821 /* SetParent additionally needs to make hwnd the topmost window
2822 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2823 WM_WINDOWPOSCHANGED notification messages.
2825 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2826 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2827 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2828 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2830 return old_parent;
2834 /*******************************************************************
2835 * IsChild (USER32.@)
2837 BOOL WINAPI IsChild( HWND parent, HWND child )
2839 HWND *list = list_window_parents( child );
2840 int i;
2841 BOOL ret;
2843 if (!list) return FALSE;
2844 parent = WIN_GetFullHandle( parent );
2845 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2846 ret = list[i] && list[i+1];
2847 HeapFree( GetProcessHeap(), 0, list );
2848 return ret;
2852 /***********************************************************************
2853 * IsWindowVisible (USER32.@)
2855 BOOL WINAPI IsWindowVisible( HWND hwnd )
2857 HWND *list;
2858 BOOL retval = TRUE;
2859 int i;
2861 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2862 if (!(list = list_window_parents( hwnd ))) return TRUE;
2863 if (list[0])
2865 for (i = 0; list[i+1]; i++)
2866 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2867 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2869 HeapFree( GetProcessHeap(), 0, list );
2870 return retval;
2874 /***********************************************************************
2875 * WIN_IsWindowDrawable
2877 * hwnd is drawable when it is visible, all parents are not
2878 * minimized, and it is itself not minimized unless we are
2879 * trying to draw its default class icon.
2881 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2883 HWND *list;
2884 BOOL retval = TRUE;
2885 int i;
2886 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2888 if (!(style & WS_VISIBLE)) return FALSE;
2889 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2891 if (!(list = list_window_parents( hwnd ))) return TRUE;
2892 if (list[0])
2894 for (i = 0; list[i+1]; i++)
2895 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2896 break;
2897 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2899 HeapFree( GetProcessHeap(), 0, list );
2900 return retval;
2904 /*******************************************************************
2905 * GetTopWindow (USER32.@)
2907 HWND WINAPI GetTopWindow( HWND hwnd )
2909 if (!hwnd) hwnd = GetDesktopWindow();
2910 return GetWindow( hwnd, GW_CHILD );
2914 /*******************************************************************
2915 * GetWindow (USER32.@)
2917 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2919 HWND retval = 0;
2921 if (rel == GW_OWNER) /* this one may be available locally */
2923 WND *wndPtr = WIN_GetPtr( hwnd );
2924 if (!wndPtr)
2926 SetLastError( ERROR_INVALID_HANDLE );
2927 return 0;
2929 if (wndPtr == WND_DESKTOP) return 0;
2930 if (wndPtr != WND_OTHER_PROCESS)
2932 retval = wndPtr->owner;
2933 WIN_ReleasePtr( wndPtr );
2934 return retval;
2936 /* else fall through to server call */
2939 SERVER_START_REQ( get_window_tree )
2941 req->handle = wine_server_user_handle( hwnd );
2942 if (!wine_server_call_err( req ))
2944 switch(rel)
2946 case GW_HWNDFIRST:
2947 retval = wine_server_ptr_handle( reply->first_sibling );
2948 break;
2949 case GW_HWNDLAST:
2950 retval = wine_server_ptr_handle( reply->last_sibling );
2951 break;
2952 case GW_HWNDNEXT:
2953 retval = wine_server_ptr_handle( reply->next_sibling );
2954 break;
2955 case GW_HWNDPREV:
2956 retval = wine_server_ptr_handle( reply->prev_sibling );
2957 break;
2958 case GW_OWNER:
2959 retval = wine_server_ptr_handle( reply->owner );
2960 break;
2961 case GW_CHILD:
2962 retval = wine_server_ptr_handle( reply->first_child );
2963 break;
2967 SERVER_END_REQ;
2968 return retval;
2972 /*******************************************************************
2973 * ShowOwnedPopups (USER32.@)
2975 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2977 int count = 0;
2978 WND *pWnd;
2979 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2981 if (!win_array) return TRUE;
2983 while (win_array[count]) count++;
2984 while (--count >= 0)
2986 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2987 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2988 if (pWnd == WND_OTHER_PROCESS) continue;
2989 if (fShow)
2991 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2993 WIN_ReleasePtr( pWnd );
2994 /* In Windows, ShowOwnedPopups(TRUE) generates
2995 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2996 * regardless of the state of the owner
2998 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2999 continue;
3002 else
3004 if (pWnd->dwStyle & WS_VISIBLE)
3006 WIN_ReleasePtr( pWnd );
3007 /* In Windows, ShowOwnedPopups(FALSE) generates
3008 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3009 * regardless of the state of the owner
3011 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3012 continue;
3015 WIN_ReleasePtr( pWnd );
3017 HeapFree( GetProcessHeap(), 0, win_array );
3018 return TRUE;
3022 /*******************************************************************
3023 * GetLastActivePopup (USER32.@)
3025 HWND WINAPI GetLastActivePopup( HWND hwnd )
3027 HWND retval = hwnd;
3029 SERVER_START_REQ( get_window_info )
3031 req->handle = wine_server_user_handle( hwnd );
3032 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3034 SERVER_END_REQ;
3035 return retval;
3039 /*******************************************************************
3040 * WIN_ListChildren
3042 * Build an array of the children of a given window. The array must be
3043 * freed with HeapFree. Returns NULL when no windows are found.
3045 HWND *WIN_ListChildren( HWND hwnd )
3047 if (!hwnd)
3049 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3050 return NULL;
3052 return list_window_children( 0, hwnd, NULL, 0 );
3056 /*******************************************************************
3057 * EnumWindows (USER32.@)
3059 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3061 HWND *list;
3062 BOOL ret = TRUE;
3063 int i;
3065 USER_CheckNotLock();
3067 /* We have to build a list of all windows first, to avoid */
3068 /* unpleasant side-effects, for instance if the callback */
3069 /* function changes the Z-order of the windows. */
3071 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3073 /* Now call the callback function for every window */
3075 for (i = 0; list[i]; i++)
3077 /* Make sure that the window still exists */
3078 if (!IsWindow( list[i] )) continue;
3079 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3081 HeapFree( GetProcessHeap(), 0, list );
3082 return ret;
3086 /**********************************************************************
3087 * EnumThreadWindows (USER32.@)
3089 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3091 HWND *list;
3092 int i;
3093 BOOL ret = TRUE;
3095 USER_CheckNotLock();
3097 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3099 /* Now call the callback function for every window */
3101 for (i = 0; list[i]; i++)
3102 if (!(ret = func( list[i], lParam ))) break;
3103 HeapFree( GetProcessHeap(), 0, list );
3104 return ret;
3108 /***********************************************************************
3109 * EnumDesktopWindows (USER32.@)
3111 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3113 HWND *list;
3114 int i;
3116 USER_CheckNotLock();
3118 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3120 for (i = 0; list[i]; i++)
3121 if (!func( list[i], lparam )) break;
3122 HeapFree( GetProcessHeap(), 0, list );
3123 return TRUE;
3127 /**********************************************************************
3128 * WIN_EnumChildWindows
3130 * Helper function for EnumChildWindows().
3132 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3134 HWND *childList;
3135 BOOL ret = FALSE;
3137 for ( ; *list; list++)
3139 /* Make sure that the window still exists */
3140 if (!IsWindow( *list )) continue;
3141 /* Build children list first */
3142 childList = WIN_ListChildren( *list );
3144 ret = func( *list, lParam );
3146 if (childList)
3148 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3149 HeapFree( GetProcessHeap(), 0, childList );
3151 if (!ret) return FALSE;
3153 return TRUE;
3157 /**********************************************************************
3158 * EnumChildWindows (USER32.@)
3160 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3162 HWND *list;
3163 BOOL ret;
3165 USER_CheckNotLock();
3167 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3168 ret = WIN_EnumChildWindows( list, func, lParam );
3169 HeapFree( GetProcessHeap(), 0, list );
3170 return ret;
3174 /*******************************************************************
3175 * AnyPopup (USER32.@)
3177 BOOL WINAPI AnyPopup(void)
3179 int i;
3180 BOOL retvalue;
3181 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3183 if (!list) return FALSE;
3184 for (i = 0; list[i]; i++)
3186 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3188 retvalue = (list[i] != 0);
3189 HeapFree( GetProcessHeap(), 0, list );
3190 return retvalue;
3194 /*******************************************************************
3195 * FlashWindow (USER32.@)
3197 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3199 WND *wndPtr;
3201 TRACE("%p\n", hWnd);
3203 if (IsIconic( hWnd ))
3205 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3207 wndPtr = WIN_GetPtr(hWnd);
3208 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3209 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3211 wndPtr->flags |= WIN_NCACTIVATED;
3213 else
3215 wndPtr->flags &= ~WIN_NCACTIVATED;
3217 WIN_ReleasePtr( wndPtr );
3218 return TRUE;
3220 else
3222 WPARAM wparam;
3224 wndPtr = WIN_GetPtr(hWnd);
3225 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3226 hWnd = wndPtr->obj.handle; /* make it a full handle */
3228 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3229 else wparam = (hWnd == GetForegroundWindow());
3231 WIN_ReleasePtr( wndPtr );
3232 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3233 return wparam;
3237 /*******************************************************************
3238 * FlashWindowEx (USER32.@)
3240 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3242 FIXME("%p\n", pfwi);
3243 return TRUE;
3246 /*******************************************************************
3247 * GetWindowContextHelpId (USER32.@)
3249 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3251 DWORD retval;
3252 WND *wnd = WIN_GetPtr( hwnd );
3253 if (!wnd || wnd == WND_DESKTOP) return 0;
3254 if (wnd == WND_OTHER_PROCESS)
3256 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3257 return 0;
3259 retval = wnd->helpContext;
3260 WIN_ReleasePtr( wnd );
3261 return retval;
3265 /*******************************************************************
3266 * SetWindowContextHelpId (USER32.@)
3268 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3270 WND *wnd = WIN_GetPtr( hwnd );
3271 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3272 if (wnd == WND_OTHER_PROCESS)
3274 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3275 return 0;
3277 wnd->helpContext = id;
3278 WIN_ReleasePtr( wnd );
3279 return TRUE;
3283 /*******************************************************************
3284 * DragDetect (USER32.@)
3286 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3288 MSG msg;
3289 RECT rect;
3290 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3291 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3293 rect.left = pt.x - wDragWidth;
3294 rect.right = pt.x + wDragWidth;
3296 rect.top = pt.y - wDragHeight;
3297 rect.bottom = pt.y + wDragHeight;
3299 SetCapture(hWnd);
3301 while(1)
3303 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3305 if( msg.message == WM_LBUTTONUP )
3307 ReleaseCapture();
3308 return 0;
3310 if( msg.message == WM_MOUSEMOVE )
3312 POINT tmp;
3313 tmp.x = (short)LOWORD(msg.lParam);
3314 tmp.y = (short)HIWORD(msg.lParam);
3315 if( !PtInRect( &rect, tmp ))
3317 ReleaseCapture();
3318 return 1;
3322 WaitMessage();
3324 return 0;
3327 /******************************************************************************
3328 * GetWindowModuleFileNameA (USER32.@)
3330 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3332 WND *win;
3333 HINSTANCE hinst;
3335 TRACE( "%p, %p, %u\n", hwnd, module, size );
3337 win = WIN_GetPtr( hwnd );
3338 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3340 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3341 return 0;
3343 hinst = win->hInstance;
3344 WIN_ReleasePtr( win );
3346 return GetModuleFileNameA( hinst, module, size );
3349 /******************************************************************************
3350 * GetWindowModuleFileNameW (USER32.@)
3352 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3354 WND *win;
3355 HINSTANCE hinst;
3357 TRACE( "%p, %p, %u\n", hwnd, module, size );
3359 win = WIN_GetPtr( hwnd );
3360 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3362 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3363 return 0;
3365 hinst = win->hInstance;
3366 WIN_ReleasePtr( win );
3368 return GetModuleFileNameW( hinst, module, size );
3371 /******************************************************************************
3372 * GetWindowInfo (USER32.@)
3374 * Note: tests show that Windows doesn't check cbSize of the structure.
3376 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3378 if (!pwi) return FALSE;
3379 if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3381 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3382 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3383 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3385 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3386 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3388 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3389 pwi->wCreatorVersion = 0x0400;
3391 return TRUE;
3394 /******************************************************************************
3395 * SwitchDesktop (USER32.@)
3397 * NOTES: Sets the current input or interactive desktop.
3399 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3401 FIXME("(hwnd %p) stub!\n", hDesktop);
3402 return TRUE;
3405 /*****************************************************************************
3406 * SetLayeredWindowAttributes (USER32.@)
3408 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3410 BOOL ret;
3412 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3414 SERVER_START_REQ( set_window_layered_info )
3416 req->handle = wine_server_user_handle( hwnd );
3417 req->color_key = key;
3418 req->alpha = alpha;
3419 req->flags = flags;
3420 ret = !wine_server_call_err( req );
3422 SERVER_END_REQ;
3424 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3426 return ret;
3430 /*****************************************************************************
3431 * GetLayeredWindowAttributes (USER32.@)
3433 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3435 BOOL ret;
3437 SERVER_START_REQ( get_window_layered_info )
3439 req->handle = wine_server_user_handle( hwnd );
3440 if ((ret = !wine_server_call_err( req )))
3442 if (key) *key = reply->color_key;
3443 if (alpha) *alpha = reply->alpha;
3444 if (flags) *flags = reply->flags;
3447 SERVER_END_REQ;
3449 return ret;
3453 /*****************************************************************************
3454 * UpdateLayeredWindowIndirect (USER32.@)
3456 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3458 BYTE alpha = 0xff;
3460 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3461 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3463 SetLastError( ERROR_INVALID_PARAMETER );
3464 return FALSE;
3467 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3469 int x = 0, y = 0, cx = 0, cy = 0;
3470 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3472 if (info->pptDst)
3474 x = info->pptDst->x;
3475 y = info->pptDst->y;
3476 flags &= ~SWP_NOMOVE;
3478 if (info->psize)
3480 cx = info->psize->cx;
3481 cy = info->psize->cy;
3482 flags &= ~SWP_NOSIZE;
3484 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3485 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3488 if (info->hdcSrc)
3490 HDC hdc = GetWindowDC( hwnd );
3492 if (hdc)
3494 int x = 0, y = 0;
3495 RECT rect;
3497 GetWindowRect( hwnd, &rect );
3498 OffsetRect( &rect, -rect.left, -rect.top);
3499 if (info->pptSrc)
3501 x = info->pptSrc->x;
3502 y = info->pptSrc->y;
3505 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3507 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3508 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3509 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3511 ReleaseDC( hwnd, hdc );
3515 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3516 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3517 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3518 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3519 return TRUE;
3523 /*****************************************************************************
3524 * UpdateLayeredWindow (USER32.@)
3526 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3527 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3528 DWORD dwFlags)
3530 UPDATELAYEREDWINDOWINFO info;
3532 info.cbSize = sizeof(info);
3533 info.hdcDst = hdcDst;
3534 info.pptDst = pptDst;
3535 info.psize = psize;
3536 info.hdcSrc = hdcSrc;
3537 info.pptSrc = pptSrc;
3538 info.crKey = crKey;
3539 info.pblend = pblend;
3540 info.dwFlags = dwFlags;
3541 info.prcDirty = NULL;
3542 return UpdateLayeredWindowIndirect( hwnd, &info );
3546 /******************************************************************************
3547 * GetProcessDefaultLayout [USER32.@]
3549 * Gets the default layout for parentless windows.
3551 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3553 if (!layout)
3555 SetLastError( ERROR_NOACCESS );
3556 return FALSE;
3558 if (process_layout == ~0u)
3560 static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3561 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3562 static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3563 '\\','%','0','4','x','%','0','4','x',
3564 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3565 WCHAR *str, buffer[MAX_PATH];
3566 DWORD i, len, version_layout = 0;
3567 DWORD user_lang = GetUserDefaultLangID();
3568 DWORD *languages;
3569 void *data = NULL;
3571 GetModuleFileNameW( 0, buffer, MAX_PATH );
3572 if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3573 if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3574 if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3575 if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3577 len /= sizeof(DWORD);
3578 for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3579 if (i == len) /* try neutral language */
3580 for (i = 0; i < len; i++)
3581 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3582 if (i == len) i = 0; /* default to the first one */
3584 sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3585 if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3586 TRACE( "found description %s\n", debugstr_w( str ));
3587 if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3589 done:
3590 HeapFree( GetProcessHeap(), 0, data );
3591 process_layout = version_layout;
3593 *layout = process_layout;
3594 return TRUE;
3598 /******************************************************************************
3599 * SetProcessDefaultLayout [USER32.@]
3601 * Sets the default layout for parentless windows.
3603 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3605 process_layout = layout;
3606 return TRUE;
3610 /* 64bit versions */
3612 #ifdef GetWindowLongPtrW
3613 #undef GetWindowLongPtrW
3614 #endif
3616 #ifdef GetWindowLongPtrA
3617 #undef GetWindowLongPtrA
3618 #endif
3620 #ifdef SetWindowLongPtrW
3621 #undef SetWindowLongPtrW
3622 #endif
3624 #ifdef SetWindowLongPtrA
3625 #undef SetWindowLongPtrA
3626 #endif
3628 /*****************************************************************************
3629 * GetWindowLongPtrW (USER32.@)
3631 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3633 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3636 /*****************************************************************************
3637 * GetWindowLongPtrA (USER32.@)
3639 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3641 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3644 /*****************************************************************************
3645 * SetWindowLongPtrW (USER32.@)
3647 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3649 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3652 /*****************************************************************************
3653 * SetWindowLongPtrA (USER32.@)
3655 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3657 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );