user32: Move Get/SetWindowLong16 implementation to wnd16.c.
[wine/multimedia.git] / dlls / user32 / win.c
blobbb19a4edb6c74e035404a1a7af90a2c6293727be
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 "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "user_private.h"
37 #include "controls.h"
38 #include "winerror.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
43 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
44 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
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 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 USER_Unlock();
153 /***********************************************************************
154 * free_user_handle
156 void *free_user_handle( HANDLE handle, enum user_obj_type type )
158 struct user_object *ptr;
159 WORD index = USER_HANDLE_TO_INDEX( handle );
161 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
163 SERVER_START_REQ( free_user_handle )
165 req->handle = wine_server_user_handle( handle );
166 if (!wine_server_call( req )) user_handles[index] = NULL;
167 else ptr = NULL;
169 SERVER_END_REQ;
170 release_user_handle_ptr( ptr );
172 return ptr;
176 /***********************************************************************
177 * create_window_handle
179 * Create a window handle with the server.
181 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
182 HINSTANCE instance, BOOL unicode )
184 WORD index;
185 WND *win;
186 HWND handle = 0, full_parent = 0, full_owner = 0;
187 struct tagCLASS *class = NULL;
188 int extra_bytes = 0;
190 /* if 16-bit instance, map to module handle */
191 if (instance && !HIWORD(instance))
192 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
194 SERVER_START_REQ( create_window )
196 req->parent = wine_server_user_handle( parent );
197 req->owner = wine_server_user_handle( owner );
198 req->instance = wine_server_client_ptr( instance );
199 if (!(req->atom = get_int_atom_value( name )) && name)
200 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
201 if (!wine_server_call_err( req ))
203 handle = wine_server_ptr_handle( reply->handle );
204 full_parent = wine_server_ptr_handle( reply->parent );
205 full_owner = wine_server_ptr_handle( reply->owner );
206 extra_bytes = reply->extra;
207 class = wine_server_get_ptr( reply->class_ptr );
210 SERVER_END_REQ;
212 if (!handle)
214 WARN( "error %d creating window\n", GetLastError() );
215 return NULL;
218 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
219 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
221 SERVER_START_REQ( destroy_window )
223 req->handle = wine_server_user_handle( handle );
224 wine_server_call( req );
226 SERVER_END_REQ;
227 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
228 return NULL;
231 if (!parent) /* if parent is 0 we don't have a desktop window yet */
233 struct user_thread_info *thread_info = get_user_thread_info();
235 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
237 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
238 else assert( full_parent == thread_info->top_window );
239 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
240 ERR( "failed to create desktop window\n" );
242 else /* HWND_MESSAGE parent */
244 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
248 USER_Lock();
250 index = USER_HANDLE_TO_INDEX(handle);
251 assert( index < NB_USER_HANDLES );
252 user_handles[index] = win;
253 win->obj.handle = handle;
254 win->obj.type = USER_WINDOW;
255 win->parent = full_parent;
256 win->owner = full_owner;
257 win->class = class;
258 win->winproc = get_class_winproc( class );
259 win->cbWndExtra = extra_bytes;
260 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
261 return win;
265 /***********************************************************************
266 * free_window_handle
268 * Free a window handle.
270 static void free_window_handle( HWND hwnd )
272 struct user_object *ptr;
273 WORD index = USER_HANDLE_TO_INDEX(hwnd);
275 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
277 SERVER_START_REQ( destroy_window )
279 req->handle = wine_server_user_handle( hwnd );
280 if (!wine_server_call_err( req )) user_handles[index] = NULL;
281 else ptr = NULL;
283 SERVER_END_REQ;
284 release_user_handle_ptr( ptr );
285 HeapFree( GetProcessHeap(), 0, ptr );
290 /*******************************************************************
291 * list_window_children
293 * Build an array of the children of a given window. The array must be
294 * freed with HeapFree. Returns NULL when no windows are found.
296 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
298 HWND *list;
299 int i, size = 128;
300 ATOM atom = get_int_atom_value( class );
302 /* empty class is not the same as NULL class */
303 if (!atom && class && !class[0]) return NULL;
305 for (;;)
307 int count = 0;
309 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
311 SERVER_START_REQ( get_window_children )
313 req->desktop = wine_server_obj_handle( desktop );
314 req->parent = wine_server_user_handle( hwnd );
315 req->tid = tid;
316 req->atom = atom;
317 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
318 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
319 if (!wine_server_call( req )) count = reply->count;
321 SERVER_END_REQ;
322 if (count && count < size)
324 /* start from the end since HWND is potentially larger than user_handle_t */
325 for (i = count - 1; i >= 0; i--)
326 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
327 list[count] = 0;
328 return list;
330 HeapFree( GetProcessHeap(), 0, list );
331 if (!count) break;
332 size = count + 1; /* restart with a large enough buffer */
334 return NULL;
338 /*******************************************************************
339 * list_window_parents
341 * Build an array of all parents of a given window, starting with
342 * the immediate parent. The array must be freed with HeapFree.
344 static HWND *list_window_parents( HWND hwnd )
346 WND *win;
347 HWND current, *list;
348 int i, pos = 0, size = 16, count = 0;
350 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
352 current = hwnd;
353 for (;;)
355 if (!(win = WIN_GetPtr( current ))) goto empty;
356 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
357 if (win == WND_DESKTOP)
359 if (!pos) goto empty;
360 list[pos] = 0;
361 return list;
363 list[pos] = current = win->parent;
364 WIN_ReleasePtr( win );
365 if (!current) return list;
366 if (++pos == size - 1)
368 /* need to grow the list */
369 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
370 if (!new_list) goto empty;
371 list = new_list;
372 size += 16;
376 /* at least one parent belongs to another process, have to query the server */
378 for (;;)
380 count = 0;
381 SERVER_START_REQ( get_window_parents )
383 req->handle = wine_server_user_handle( hwnd );
384 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
385 if (!wine_server_call( req )) count = reply->count;
387 SERVER_END_REQ;
388 if (!count) goto empty;
389 if (size > count)
391 /* start from the end since HWND is potentially larger than user_handle_t */
392 for (i = count - 1; i >= 0; i--)
393 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
394 list[count] = 0;
395 return list;
397 HeapFree( GetProcessHeap(), 0, list );
398 size = count + 1;
399 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
402 empty:
403 HeapFree( GetProcessHeap(), 0, list );
404 return NULL;
408 /*******************************************************************
409 * send_parent_notify
411 static void send_parent_notify( HWND hwnd, UINT msg )
413 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
414 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
416 HWND parent = GetParent(hwnd);
417 if (parent && parent != GetDesktopWindow())
418 SendMessageW( parent, WM_PARENTNOTIFY,
419 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
424 /*******************************************************************
425 * get_server_window_text
427 * Retrieve the window text from the server.
429 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
431 size_t len = 0;
433 SERVER_START_REQ( get_window_text )
435 req->handle = wine_server_user_handle( hwnd );
436 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
437 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
439 SERVER_END_REQ;
440 text[len / sizeof(WCHAR)] = 0;
444 /*******************************************************************
445 * get_hwnd_message_parent
447 * Return the parent for HWND_MESSAGE windows.
449 HWND get_hwnd_message_parent(void)
451 struct user_thread_info *thread_info = get_user_thread_info();
453 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
454 return thread_info->msg_window;
458 /*******************************************************************
459 * is_desktop_window
461 * Check if window is the desktop or the HWND_MESSAGE top parent.
463 BOOL is_desktop_window( HWND hwnd )
465 struct user_thread_info *thread_info = get_user_thread_info();
467 if (!hwnd) return FALSE;
468 if (hwnd == thread_info->top_window) return TRUE;
469 if (hwnd == thread_info->msg_window) return TRUE;
471 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
473 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
474 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
476 return FALSE;
480 /***********************************************************************
481 * WIN_GetPtr
483 * Return a pointer to the WND structure if local to the process,
484 * or WND_OTHER_PROCESS if handle may be valid in other process.
485 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
487 WND *WIN_GetPtr( HWND hwnd )
489 WND *ptr;
491 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
493 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
495 return ptr;
499 /***********************************************************************
500 * WIN_IsCurrentProcess
502 * Check whether a given window belongs to the current process (and return the full handle).
504 HWND WIN_IsCurrentProcess( HWND hwnd )
506 WND *ptr;
507 HWND ret;
509 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
510 ret = ptr->obj.handle;
511 WIN_ReleasePtr( ptr );
512 return ret;
516 /***********************************************************************
517 * WIN_IsCurrentThread
519 * Check whether a given window belongs to the current thread (and return the full handle).
521 HWND WIN_IsCurrentThread( HWND hwnd )
523 WND *ptr;
524 HWND ret = 0;
526 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
527 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
528 WIN_ReleasePtr( ptr );
529 return ret;
533 /***********************************************************************
534 * WIN_Handle32
536 * Convert a 16-bit window handle to a full 32-bit handle.
538 HWND WIN_Handle32( HWND16 hwnd16 )
540 WND *ptr;
541 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
543 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
544 /* do sign extension for -2 and -3 */
545 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
547 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
549 if (ptr == WND_DESKTOP)
551 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
552 else return get_hwnd_message_parent();
555 if (ptr != WND_OTHER_PROCESS)
557 hwnd = ptr->obj.handle;
558 WIN_ReleasePtr( ptr );
560 else /* may belong to another process */
562 SERVER_START_REQ( get_window_info )
564 req->handle = wine_server_user_handle( hwnd );
565 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
567 SERVER_END_REQ;
569 return hwnd;
573 /***********************************************************************
574 * WIN_SetOwner
576 * Change the owner of a window.
578 HWND WIN_SetOwner( HWND hwnd, HWND owner )
580 WND *win = WIN_GetPtr( hwnd );
581 HWND ret = 0;
583 if (!win || win == WND_DESKTOP) return 0;
584 if (win == WND_OTHER_PROCESS)
586 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
587 return 0;
589 SERVER_START_REQ( set_window_owner )
591 req->handle = wine_server_user_handle( hwnd );
592 req->owner = wine_server_user_handle( owner );
593 if (!wine_server_call( req ))
595 win->owner = wine_server_ptr_handle( reply->full_owner );
596 ret = wine_server_ptr_handle( reply->prev_owner );
599 SERVER_END_REQ;
600 WIN_ReleasePtr( win );
601 return ret;
605 /***********************************************************************
606 * WIN_SetStyle
608 * Change the style of a window.
610 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
612 BOOL ok;
613 STYLESTRUCT style;
614 WND *win = WIN_GetPtr( hwnd );
616 if (!win || win == WND_DESKTOP) return 0;
617 if (win == WND_OTHER_PROCESS)
619 if (IsWindow(hwnd))
620 ERR( "cannot set style %x/%x on other process window %p\n",
621 set_bits, clear_bits, hwnd );
622 return 0;
624 style.styleOld = win->dwStyle;
625 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
626 if (style.styleNew == style.styleOld)
628 WIN_ReleasePtr( win );
629 return style.styleNew;
631 SERVER_START_REQ( set_window_info )
633 req->handle = wine_server_user_handle( hwnd );
634 req->flags = SET_WIN_STYLE;
635 req->style = style.styleNew;
636 req->extra_offset = -1;
637 if ((ok = !wine_server_call( req )))
639 style.styleOld = reply->old_style;
640 win->dwStyle = style.styleNew;
643 SERVER_END_REQ;
644 WIN_ReleasePtr( win );
645 if (ok)
647 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
648 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
650 return style.styleOld;
654 /***********************************************************************
655 * WIN_GetRectangles
657 * Get the window and client rectangles.
659 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
661 WND *win = WIN_GetPtr( hwnd );
662 BOOL ret = TRUE;
664 if (!win)
666 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
667 return FALSE;
669 if (win == WND_DESKTOP)
671 RECT rect;
672 rect.left = rect.top = 0;
673 if (hwnd == get_hwnd_message_parent())
675 rect.right = 100;
676 rect.bottom = 100;
678 else
680 rect.right = GetSystemMetrics(SM_CXSCREEN);
681 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
683 if (rectWindow) *rectWindow = rect;
684 if (rectClient) *rectClient = rect;
686 else if (win == WND_OTHER_PROCESS)
688 SERVER_START_REQ( get_window_rectangles )
690 req->handle = wine_server_user_handle( hwnd );
691 if ((ret = !wine_server_call_err( req )))
693 if (rectWindow)
695 rectWindow->left = reply->window.left;
696 rectWindow->top = reply->window.top;
697 rectWindow->right = reply->window.right;
698 rectWindow->bottom = reply->window.bottom;
700 if (rectClient)
702 rectClient->left = reply->client.left;
703 rectClient->top = reply->client.top;
704 rectClient->right = reply->client.right;
705 rectClient->bottom = reply->client.bottom;
709 SERVER_END_REQ;
711 else
713 if (rectWindow) *rectWindow = win->rectWindow;
714 if (rectClient) *rectClient = win->rectClient;
715 WIN_ReleasePtr( win );
717 return ret;
721 /***********************************************************************
722 * WIN_DestroyWindow
724 * Destroy storage associated to a window. "Internals" p.358
726 LRESULT WIN_DestroyWindow( HWND hwnd )
728 WND *wndPtr;
729 HWND *list;
730 HMENU menu = 0, sys_menu;
731 HWND icon_title;
733 TRACE("%p\n", hwnd );
735 /* free child windows */
736 if ((list = WIN_ListChildren( hwnd )))
738 int i;
739 for (i = 0; list[i]; i++)
741 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
742 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
744 HeapFree( GetProcessHeap(), 0, list );
747 /* Unlink now so we won't bother with the children later on */
748 SERVER_START_REQ( set_parent )
750 req->handle = wine_server_user_handle( hwnd );
751 req->parent = 0;
752 wine_server_call( req );
754 SERVER_END_REQ;
757 * Send the WM_NCDESTROY to the window being destroyed.
759 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
761 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
763 /* free resources associated with the window */
765 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
766 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
767 menu = (HMENU)wndPtr->wIDmenu;
768 sys_menu = wndPtr->hSysMenu;
769 free_dce( wndPtr->dce, hwnd );
770 wndPtr->dce = NULL;
771 icon_title = wndPtr->icon_title;
772 HeapFree( GetProcessHeap(), 0, wndPtr->text );
773 wndPtr->text = NULL;
774 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
775 wndPtr->pScroll = NULL;
776 WIN_ReleasePtr( wndPtr );
778 if (icon_title) DestroyWindow( icon_title );
779 if (menu) DestroyMenu( menu );
780 if (sys_menu) DestroyMenu( sys_menu );
782 USER_Driver->pDestroyWindow( hwnd );
784 free_window_handle( hwnd );
785 return 0;
789 /***********************************************************************
790 * destroy_thread_window
792 * Destroy a window upon exit of its thread.
794 static void destroy_thread_window( HWND hwnd )
796 WND *wndPtr;
797 HWND *list;
798 HMENU menu = 0, sys_menu = 0;
799 WORD index;
801 /* free child windows */
803 if ((list = WIN_ListChildren( hwnd )))
805 int i;
806 for (i = 0; list[i]; i++)
808 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
809 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
811 HeapFree( GetProcessHeap(), 0, list );
814 /* destroy the client-side storage */
816 index = USER_HANDLE_TO_INDEX(hwnd);
817 if (index >= NB_USER_HANDLES) return;
818 USER_Lock();
819 if ((wndPtr = user_handles[index]))
821 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
822 sys_menu = wndPtr->hSysMenu;
823 free_dce( wndPtr->dce, hwnd );
824 user_handles[index] = NULL;
826 USER_Unlock();
828 HeapFree( GetProcessHeap(), 0, wndPtr );
829 if (menu) DestroyMenu( menu );
830 if (sys_menu) DestroyMenu( sys_menu );
834 /***********************************************************************
835 * destroy_thread_child_windows
837 * Destroy child windows upon exit of its thread.
839 static void destroy_thread_child_windows( HWND hwnd )
841 HWND *list;
842 int i;
844 if (WIN_IsCurrentThread( hwnd ))
846 destroy_thread_window( hwnd );
848 else if ((list = WIN_ListChildren( hwnd )))
850 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
851 HeapFree( GetProcessHeap(), 0, list );
856 /***********************************************************************
857 * WIN_DestroyThreadWindows
859 * Destroy all children of 'wnd' owned by the current thread.
861 void WIN_DestroyThreadWindows( HWND hwnd )
863 HWND *list;
864 int i;
866 if (!(list = WIN_ListChildren( hwnd ))) return;
868 /* reset owners of top-level windows */
869 for (i = 0; list[i]; i++)
871 if (!WIN_IsCurrentThread( list[i] ))
873 HWND owner = GetWindow( list[i], GW_OWNER );
874 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
878 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
879 HeapFree( GetProcessHeap(), 0, list );
883 /***********************************************************************
884 * WIN_FixCoordinates
886 * Fix the coordinates - Helper for WIN_CreateWindowEx.
887 * returns default show mode in sw.
889 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
891 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
892 POINT pos[2];
894 if (cs->dwExStyle & WS_EX_MDICHILD)
896 UINT id = 0;
898 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
899 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
901 TRACE("MDI child id %04x\n", id);
904 if (cs->style & (WS_CHILD | WS_POPUP))
906 if (cs->dwExStyle & WS_EX_MDICHILD)
908 if (IS_DEFAULT(cs->x))
910 cs->x = pos[0].x;
911 cs->y = pos[0].y;
913 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
914 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
916 else
918 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
919 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
922 else /* overlapped window */
924 HMONITOR monitor;
925 MONITORINFO mon_info;
926 STARTUPINFOW info;
928 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
930 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
931 mon_info.cbSize = sizeof(mon_info);
932 GetMonitorInfoW( monitor, &mon_info );
933 GetStartupInfoW( &info );
935 if (IS_DEFAULT(cs->x))
937 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
938 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
939 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
942 if (IS_DEFAULT(cs->cx))
944 if (info.dwFlags & STARTF_USESIZE)
946 cs->cx = info.dwXSize;
947 cs->cy = info.dwYSize;
949 else
951 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
952 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
955 /* neither x nor cx are default. Check the y values .
956 * In the trace we see Outlook and Outlook Express using
957 * cy set to CW_USEDEFAULT when opening the address book.
959 else if (IS_DEFAULT(cs->cy))
961 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
962 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
965 #undef IS_DEFAULT
968 /***********************************************************************
969 * dump_window_styles
971 static void dump_window_styles( DWORD style, DWORD exstyle )
973 TRACE( "style:" );
974 if(style & WS_POPUP) TRACE(" WS_POPUP");
975 if(style & WS_CHILD) TRACE(" WS_CHILD");
976 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
977 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
978 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
979 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
980 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
981 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
982 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
983 else
985 if(style & WS_BORDER) TRACE(" WS_BORDER");
986 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
988 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
989 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
990 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
991 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
992 if (style & WS_CHILD)
994 if(style & WS_GROUP) TRACE(" WS_GROUP");
995 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
997 else
999 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1000 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1003 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1004 #define DUMPED_STYLES \
1005 (WS_POPUP | \
1006 WS_CHILD | \
1007 WS_MINIMIZE | \
1008 WS_VISIBLE | \
1009 WS_DISABLED | \
1010 WS_CLIPSIBLINGS | \
1011 WS_CLIPCHILDREN | \
1012 WS_MAXIMIZE | \
1013 WS_BORDER | \
1014 WS_DLGFRAME | \
1015 WS_VSCROLL | \
1016 WS_HSCROLL | \
1017 WS_SYSMENU | \
1018 WS_THICKFRAME | \
1019 WS_GROUP | \
1020 WS_TABSTOP | \
1021 WS_MINIMIZEBOX | \
1022 WS_MAXIMIZEBOX)
1024 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1025 TRACE("\n");
1026 #undef DUMPED_STYLES
1028 TRACE( "exstyle:" );
1029 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1030 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1031 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1032 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1033 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1034 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1035 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1036 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1037 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1038 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1039 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1040 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1041 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1042 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1043 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1044 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1045 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1046 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1048 #define DUMPED_EX_STYLES \
1049 (WS_EX_DLGMODALFRAME | \
1050 WS_EX_DRAGDETECT | \
1051 WS_EX_NOPARENTNOTIFY | \
1052 WS_EX_TOPMOST | \
1053 WS_EX_ACCEPTFILES | \
1054 WS_EX_TRANSPARENT | \
1055 WS_EX_MDICHILD | \
1056 WS_EX_TOOLWINDOW | \
1057 WS_EX_WINDOWEDGE | \
1058 WS_EX_CLIENTEDGE | \
1059 WS_EX_CONTEXTHELP | \
1060 WS_EX_RIGHT | \
1061 WS_EX_RTLREADING | \
1062 WS_EX_LEFTSCROLLBAR | \
1063 WS_EX_CONTROLPARENT | \
1064 WS_EX_STATICEDGE | \
1065 WS_EX_APPWINDOW | \
1066 WS_EX_LAYERED)
1068 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1069 TRACE("\n");
1070 #undef DUMPED_EX_STYLES
1074 /***********************************************************************
1075 * WIN_CreateWindowEx
1077 * Implementation of CreateWindowEx().
1079 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
1081 INT cx, cy, style, sw = SW_SHOW;
1082 LRESULT result;
1083 RECT rect;
1084 WND *wndPtr;
1085 HWND hwnd, parent, owner, top_child = 0;
1086 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
1087 MDICREATESTRUCTA mdi_cs;
1088 CBT_CREATEWNDA cbtc;
1089 CREATESTRUCTA cbcs;
1091 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1092 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1093 debugstr_w(className),
1094 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1095 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1096 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1098 /* Fix the styles for MDI children */
1099 if (cs->dwExStyle & WS_EX_MDICHILD)
1101 UINT flags = 0;
1103 wndPtr = WIN_GetPtr(cs->hwndParent);
1104 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1106 flags = wndPtr->flags;
1107 WIN_ReleasePtr(wndPtr);
1110 if (!(flags & WIN_ISMDICLIENT))
1112 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1113 return 0;
1116 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1117 * MDICREATESTRUCT members have the originally passed values.
1119 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1120 * have the same layout.
1122 mdi_cs.szClass = cs->lpszClass;
1123 mdi_cs.szTitle = cs->lpszName;
1124 mdi_cs.hOwner = cs->hInstance;
1125 mdi_cs.x = cs->x;
1126 mdi_cs.y = cs->y;
1127 mdi_cs.cx = cs->cx;
1128 mdi_cs.cy = cs->cy;
1129 mdi_cs.style = cs->style;
1130 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1132 cs->lpCreateParams = &mdi_cs;
1134 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1136 if (cs->style & WS_POPUP)
1138 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1139 return 0;
1141 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1143 else
1145 cs->style &= ~WS_POPUP;
1146 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1147 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1150 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1152 if (top_child)
1154 /* Restore current maximized child */
1155 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1157 TRACE("Restoring current maximized child %p\n", top_child);
1158 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1159 ShowWindow( top_child, SW_SHOWNORMAL );
1160 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1165 /* Find the parent window */
1167 parent = cs->hwndParent;
1168 owner = 0;
1170 if (cs->hwndParent == HWND_MESSAGE)
1172 cs->hwndParent = parent = get_hwnd_message_parent();
1174 else if (cs->hwndParent)
1176 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1178 parent = GetDesktopWindow();
1179 owner = cs->hwndParent;
1182 else
1184 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1186 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1188 WARN("No parent for child window\n" );
1189 SetLastError(ERROR_TLW_WITH_WSCHILD);
1190 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1192 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1193 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1194 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1195 parent = GetDesktopWindow();
1198 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1200 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1201 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1202 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1203 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1204 else
1205 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1207 /* Create the window structure */
1209 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1210 return 0;
1211 hwnd = wndPtr->obj.handle;
1213 /* Fill the window structure */
1215 wndPtr->tid = GetCurrentThreadId();
1216 wndPtr->hInstance = cs->hInstance;
1217 wndPtr->text = NULL;
1218 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1219 wndPtr->dwExStyle = cs->dwExStyle;
1220 wndPtr->wIDmenu = 0;
1221 wndPtr->helpContext = 0;
1222 wndPtr->pScroll = NULL;
1223 wndPtr->userdata = 0;
1224 wndPtr->hIcon = 0;
1225 wndPtr->hIconSmall = 0;
1226 wndPtr->hSysMenu = 0;
1227 wndPtr->flags |= (flags & WIN_ISWIN32);
1229 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1230 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1232 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1235 * Correct the window styles.
1237 * It affects only the style loaded into the WIN structure.
1240 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1242 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1243 if (!(wndPtr->dwStyle & WS_POPUP))
1244 wndPtr->dwStyle |= WS_CAPTION;
1248 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1249 * why does the user get to set it?
1252 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1253 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1254 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1255 else
1256 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1258 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1259 wndPtr->flags |= WIN_NEED_SIZE;
1261 SERVER_START_REQ( set_window_info )
1263 req->handle = wine_server_user_handle( hwnd );
1264 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1265 req->style = wndPtr->dwStyle;
1266 req->ex_style = wndPtr->dwExStyle;
1267 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1268 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1269 req->extra_offset = -1;
1270 wine_server_call( req );
1272 SERVER_END_REQ;
1274 /* Set the window menu */
1276 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1278 if (cs->hMenu)
1280 if (!MENU_SetMenu(hwnd, cs->hMenu))
1282 WIN_ReleasePtr( wndPtr );
1283 free_window_handle( hwnd );
1284 return 0;
1287 else
1289 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1290 if (menuName)
1292 if (!cs->hInstance || HIWORD(cs->hInstance))
1293 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1294 else
1295 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1297 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1301 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1303 /* call the WH_CBT hook */
1305 /* the window style passed to the hook must be the real window style,
1306 * rather than just the window style that the caller to CreateWindowEx
1307 * passed in, so we have to copy the original CREATESTRUCT and get the
1308 * the real style. */
1309 cbcs = *cs;
1310 cbcs.style = wndPtr->dwStyle;
1311 cbtc.lpcs = &cbcs;
1312 cbtc.hwndInsertAfter = HWND_TOP;
1313 WIN_ReleasePtr( wndPtr );
1314 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1316 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1318 cx = cs->cx;
1319 cy = cs->cy;
1320 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1322 POINT maxSize, maxPos, minTrack, maxTrack;
1323 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1324 if (maxTrack.x < cx) cx = maxTrack.x;
1325 if (maxTrack.y < cy) cy = maxTrack.y;
1326 if (minTrack.x > cx) cx = minTrack.x;
1327 if (minTrack.y > cy) cy = minTrack.y;
1330 if (cx < 0) cx = 0;
1331 if (cy < 0) cy = 0;
1332 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1333 /* check for wraparound */
1334 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1335 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1336 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1338 /* send WM_NCCREATE */
1340 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1341 if (unicode)
1342 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1343 else
1344 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1345 if (!result)
1347 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1348 goto failed;
1351 /* send WM_NCCALCSIZE */
1353 if ((wndPtr = WIN_GetPtr(hwnd)))
1355 /* yes, even if the CBT hook was called with HWND_TOP */
1356 POINT pt;
1357 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1358 RECT window_rect = wndPtr->rectWindow;
1359 RECT client_rect = window_rect;
1360 WIN_ReleasePtr( wndPtr );
1362 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1363 pt.x = pt.y = 0;
1364 MapWindowPoints( parent, 0, &pt, 1 );
1365 OffsetRect( &client_rect, pt.x, pt.y );
1366 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1367 OffsetRect( &client_rect, -pt.x, -pt.y );
1368 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1370 else return 0;
1372 /* send WM_CREATE */
1374 if (unicode)
1375 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1376 else
1377 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1378 if (result == -1) goto failed;
1380 /* call the driver */
1382 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1384 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1386 /* send the size messages */
1388 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1389 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1390 if (!(wndPtr->flags & WIN_NEED_SIZE))
1392 rect = wndPtr->rectClient;
1393 WIN_ReleasePtr( wndPtr );
1394 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1395 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1396 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1398 else WIN_ReleasePtr( wndPtr );
1400 /* Show the window, maximizing or minimizing if needed */
1402 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1403 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1405 RECT newPos;
1406 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1408 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1409 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1410 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1411 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1412 newPos.bottom - newPos.top, swFlag );
1415 /* Notify the parent window only */
1417 send_parent_notify( hwnd, WM_CREATE );
1418 if (!IsWindow( hwnd )) return 0;
1420 if (cs->style & WS_VISIBLE)
1422 if (cs->style & WS_MAXIMIZE)
1423 sw = SW_SHOW;
1424 else if (cs->style & WS_MINIMIZE)
1425 sw = SW_SHOWMINIMIZED;
1427 ShowWindow( hwnd, sw );
1428 if (cs->dwExStyle & WS_EX_MDICHILD)
1430 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1431 /* ShowWindow won't activate child windows */
1432 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1436 /* Call WH_SHELL hook */
1438 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1439 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1441 TRACE("created window %p\n", hwnd);
1442 return hwnd;
1444 failed:
1445 WIN_DestroyWindow( hwnd );
1446 return 0;
1450 /***********************************************************************
1451 * CreateWindow (USER.41)
1453 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1454 DWORD style, INT16 x, INT16 y, INT16 width,
1455 INT16 height, HWND16 parent, HMENU16 menu,
1456 HINSTANCE16 instance, LPVOID data )
1458 return CreateWindowEx16( 0, className, windowName, style,
1459 x, y, width, height, parent, menu, instance, data );
1463 /***********************************************************************
1464 * CreateWindowEx (USER.452)
1466 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1467 LPCSTR windowName, DWORD style, INT16 x,
1468 INT16 y, INT16 width, INT16 height,
1469 HWND16 parent, HMENU16 menu,
1470 HINSTANCE16 instance, LPVOID data )
1472 CREATESTRUCTA cs;
1473 char buffer[256];
1475 /* Fix the coordinates */
1477 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1478 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1479 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1480 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1482 /* Create the window */
1484 cs.lpCreateParams = data;
1485 cs.hInstance = HINSTANCE_32(instance);
1486 cs.hMenu = HMENU_32(menu);
1487 cs.hwndParent = WIN_Handle32( parent );
1488 cs.style = style;
1489 cs.lpszName = windowName;
1490 cs.lpszClass = className;
1491 cs.dwExStyle = exStyle;
1493 if (!IS_INTRESOURCE(className))
1495 WCHAR bufferW[256];
1497 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1498 return 0;
1499 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1501 else
1503 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1505 ERR( "bad atom %x\n", LOWORD(className));
1506 return 0;
1508 cs.lpszClass = buffer;
1509 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1514 /***********************************************************************
1515 * CreateWindowExA (USER32.@)
1517 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1518 LPCSTR windowName, DWORD style, INT x,
1519 INT y, INT width, INT height,
1520 HWND parent, HMENU menu,
1521 HINSTANCE instance, LPVOID data )
1523 CREATESTRUCTA cs;
1525 cs.lpCreateParams = data;
1526 cs.hInstance = instance;
1527 cs.hMenu = menu;
1528 cs.hwndParent = parent;
1529 cs.x = x;
1530 cs.y = y;
1531 cs.cx = width;
1532 cs.cy = height;
1533 cs.style = style;
1534 cs.lpszName = windowName;
1535 cs.lpszClass = className;
1536 cs.dwExStyle = exStyle;
1538 if (!IS_INTRESOURCE(className))
1540 WCHAR bufferW[256];
1541 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1542 return 0;
1543 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1545 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1549 /***********************************************************************
1550 * CreateWindowExW (USER32.@)
1552 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1553 LPCWSTR windowName, DWORD style, INT x,
1554 INT y, INT width, INT height,
1555 HWND parent, HMENU menu,
1556 HINSTANCE instance, LPVOID data )
1558 CREATESTRUCTW cs;
1560 cs.lpCreateParams = data;
1561 cs.hInstance = instance;
1562 cs.hMenu = menu;
1563 cs.hwndParent = parent;
1564 cs.x = x;
1565 cs.y = y;
1566 cs.cx = width;
1567 cs.cy = height;
1568 cs.style = style;
1569 cs.lpszName = windowName;
1570 cs.lpszClass = className;
1571 cs.dwExStyle = exStyle;
1573 /* Note: we rely on the fact that CREATESTRUCTA and */
1574 /* CREATESTRUCTW have the same layout. */
1575 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1579 /***********************************************************************
1580 * WIN_SendDestroyMsg
1582 static void WIN_SendDestroyMsg( HWND hwnd )
1584 GUITHREADINFO info;
1586 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1588 if (hwnd == info.hwndCaret) DestroyCaret();
1589 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1593 * Send the WM_DESTROY to the window.
1595 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1598 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1599 * make sure that the window still exists when we come back.
1601 if (IsWindow(hwnd))
1603 HWND* pWndArray;
1604 int i;
1606 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1608 for (i = 0; pWndArray[i]; i++)
1610 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1612 HeapFree( GetProcessHeap(), 0, pWndArray );
1614 else
1615 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1619 /***********************************************************************
1620 * DestroyWindow (USER32.@)
1622 BOOL WINAPI DestroyWindow( HWND hwnd )
1624 BOOL is_child;
1626 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1628 SetLastError( ERROR_ACCESS_DENIED );
1629 return FALSE;
1632 TRACE("(%p)\n", hwnd);
1634 /* Call hooks */
1636 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1638 if (MENU_IsMenuActive() == hwnd)
1639 EndMenu();
1641 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1643 if (is_child)
1645 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1646 send_parent_notify( hwnd, WM_DESTROY );
1648 else if (!GetWindow( hwnd, GW_OWNER ))
1650 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1651 /* FIXME: clean up palette - see "Internals" p.352 */
1654 if (!IsWindow(hwnd)) return TRUE;
1656 /* Hide the window */
1657 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1659 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1660 if (is_child)
1661 ShowWindow( hwnd, SW_HIDE );
1662 else
1663 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1664 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1667 if (!IsWindow(hwnd)) return TRUE;
1669 /* Recursively destroy owned windows */
1671 if (!is_child)
1673 for (;;)
1675 int i, got_one = 0;
1676 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1677 if (list)
1679 for (i = 0; list[i]; i++)
1681 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1682 if (WIN_IsCurrentThread( list[i] ))
1684 DestroyWindow( list[i] );
1685 got_one = 1;
1686 continue;
1688 WIN_SetOwner( list[i], 0 );
1690 HeapFree( GetProcessHeap(), 0, list );
1692 if (!got_one) break;
1696 /* Send destroy messages */
1698 WIN_SendDestroyMsg( hwnd );
1699 if (!IsWindow( hwnd )) return TRUE;
1701 if (GetClipboardOwner() == hwnd)
1702 CLIPBOARD_ReleaseOwner();
1704 /* Destroy the window storage */
1706 WIN_DestroyWindow( hwnd );
1707 return TRUE;
1711 /***********************************************************************
1712 * CloseWindow (USER32.@)
1714 BOOL WINAPI CloseWindow( HWND hwnd )
1716 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1717 ShowWindow( hwnd, SW_MINIMIZE );
1718 return TRUE;
1722 /***********************************************************************
1723 * OpenIcon (USER32.@)
1725 BOOL WINAPI OpenIcon( HWND hwnd )
1727 if (!IsIconic( hwnd )) return FALSE;
1728 ShowWindow( hwnd, SW_SHOWNORMAL );
1729 return TRUE;
1733 /***********************************************************************
1734 * FindWindowExW (USER32.@)
1736 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1738 HWND *list = NULL;
1739 HWND retvalue = 0;
1740 int i = 0, len = 0;
1741 WCHAR *buffer = NULL;
1743 if (!parent && child) parent = GetDesktopWindow();
1744 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1746 if (title)
1748 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1749 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1752 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1754 if (child)
1756 child = WIN_GetFullHandle( child );
1757 while (list[i] && list[i] != child) i++;
1758 if (!list[i]) goto done;
1759 i++; /* start from next window */
1762 if (title)
1764 while (list[i])
1766 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1767 i++;
1770 retvalue = list[i];
1772 done:
1773 HeapFree( GetProcessHeap(), 0, list );
1774 HeapFree( GetProcessHeap(), 0, buffer );
1775 return retvalue;
1780 /***********************************************************************
1781 * FindWindowA (USER32.@)
1783 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1785 HWND ret = FindWindowExA( 0, 0, className, title );
1786 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1787 return ret;
1791 /***********************************************************************
1792 * FindWindowExA (USER32.@)
1794 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1796 LPWSTR titleW = NULL;
1797 HWND hwnd = 0;
1799 if (title)
1801 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1802 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1803 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1806 if (!IS_INTRESOURCE(className))
1808 WCHAR classW[256];
1809 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1810 hwnd = FindWindowExW( parent, child, classW, titleW );
1812 else
1814 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1817 HeapFree( GetProcessHeap(), 0, titleW );
1818 return hwnd;
1822 /***********************************************************************
1823 * FindWindowW (USER32.@)
1825 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1827 return FindWindowExW( 0, 0, className, title );
1831 /**********************************************************************
1832 * GetDesktopWindow (USER32.@)
1834 HWND WINAPI GetDesktopWindow(void)
1836 struct user_thread_info *thread_info = get_user_thread_info();
1838 if (thread_info->top_window) return thread_info->top_window;
1840 SERVER_START_REQ( get_desktop_window )
1842 req->force = 0;
1843 if (!wine_server_call( req ))
1845 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1846 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1849 SERVER_END_REQ;
1851 if (!thread_info->top_window)
1853 USEROBJECTFLAGS flags;
1854 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1855 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1857 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1858 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1859 STARTUPINFOW si;
1860 PROCESS_INFORMATION pi;
1861 WCHAR windir[MAX_PATH];
1862 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1863 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1865 memset( &si, 0, sizeof(si) );
1866 si.cb = sizeof(si);
1867 si.dwFlags = STARTF_USESTDHANDLES;
1868 si.hStdInput = 0;
1869 si.hStdOutput = 0;
1870 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1872 GetWindowsDirectoryW( windir, MAX_PATH );
1873 strcpyW( app, windir );
1874 strcatW( app, explorer );
1875 strcpyW( cmdline, app );
1876 strcatW( cmdline, args );
1877 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1878 NULL, windir, &si, &pi ))
1880 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1881 WaitForInputIdle( pi.hProcess, 10000 );
1882 CloseHandle( pi.hThread );
1883 CloseHandle( pi.hProcess );
1885 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1887 else TRACE( "not starting explorer since winstation is not visible\n" );
1889 SERVER_START_REQ( get_desktop_window )
1891 req->force = 1;
1892 if (!wine_server_call( req ))
1894 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1895 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1898 SERVER_END_REQ;
1901 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1902 ERR( "failed to create desktop window\n" );
1904 return thread_info->top_window;
1908 /*******************************************************************
1909 * EnableWindow (USER32.@)
1911 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1913 BOOL retvalue;
1914 HWND full_handle;
1916 if (is_broadcast(hwnd))
1918 SetLastError( ERROR_INVALID_PARAMETER );
1919 return FALSE;
1922 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1923 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1925 hwnd = full_handle;
1927 TRACE("( %p, %d )\n", hwnd, enable);
1929 retvalue = !IsWindowEnabled( hwnd );
1931 if (enable && retvalue)
1933 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1934 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1936 else if (!enable && !retvalue)
1938 HWND capture_wnd;
1940 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1942 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1944 if (hwnd == GetFocus())
1945 SetFocus( 0 ); /* A disabled window can't have the focus */
1947 capture_wnd = GetCapture();
1948 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1949 ReleaseCapture(); /* A disabled window can't capture the mouse */
1951 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1953 return retvalue;
1957 /***********************************************************************
1958 * IsWindowEnabled (USER32.@)
1960 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1962 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1966 /***********************************************************************
1967 * IsWindowUnicode (USER32.@)
1969 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1971 WND * wndPtr;
1972 BOOL retvalue = FALSE;
1974 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1976 if (wndPtr == WND_DESKTOP) return TRUE;
1978 if (wndPtr != WND_OTHER_PROCESS)
1980 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1981 WIN_ReleasePtr( wndPtr );
1983 else
1985 SERVER_START_REQ( get_window_info )
1987 req->handle = wine_server_user_handle( hwnd );
1988 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1990 SERVER_END_REQ;
1992 return retvalue;
1996 /**********************************************************************
1997 * WIN_GetWindowLong
1999 * Helper function for GetWindowLong().
2001 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2003 LONG_PTR retvalue = 0;
2004 WND *wndPtr;
2006 if (offset == GWLP_HWNDPARENT)
2008 HWND parent = GetAncestor( hwnd, GA_PARENT );
2009 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2010 return (ULONG_PTR)parent;
2013 if (!(wndPtr = WIN_GetPtr( hwnd )))
2015 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2016 return 0;
2019 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2021 if (offset == GWLP_WNDPROC)
2023 SetLastError( ERROR_ACCESS_DENIED );
2024 return 0;
2026 SERVER_START_REQ( set_window_info )
2028 req->handle = wine_server_user_handle( hwnd );
2029 req->flags = 0; /* don't set anything, just retrieve */
2030 req->extra_offset = (offset >= 0) ? offset : -1;
2031 req->extra_size = (offset >= 0) ? size : 0;
2032 if (!wine_server_call_err( req ))
2034 switch(offset)
2036 case GWL_STYLE: retvalue = reply->old_style; break;
2037 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2038 case GWLP_ID: retvalue = reply->old_id; break;
2039 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2040 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2041 default:
2042 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2043 else SetLastError( ERROR_INVALID_INDEX );
2044 break;
2048 SERVER_END_REQ;
2049 return retvalue;
2052 /* now we have a valid wndPtr */
2054 if (offset >= 0)
2056 if (offset > (int)(wndPtr->cbWndExtra - size))
2058 WARN("Invalid offset %d\n", offset );
2059 WIN_ReleasePtr( wndPtr );
2060 SetLastError( ERROR_INVALID_INDEX );
2061 return 0;
2063 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2065 /* Special case for dialog window procedure */
2066 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2067 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2068 WIN_ReleasePtr( wndPtr );
2069 return retvalue;
2072 switch(offset)
2074 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2075 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2076 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2077 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2078 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2079 case GWLP_WNDPROC:
2080 /* This looks like a hack only for the edit control (see tests). This makes these controls
2081 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2082 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2084 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2085 retvalue = (ULONG_PTR)wndPtr->winproc;
2086 else
2087 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2088 break;
2089 default:
2090 WARN("Unknown offset %d\n", offset );
2091 SetLastError( ERROR_INVALID_INDEX );
2092 break;
2094 WIN_ReleasePtr(wndPtr);
2095 return retvalue;
2099 /**********************************************************************
2100 * WIN_SetWindowLong
2102 * Helper function for SetWindowLong().
2104 * 0 is the failure code. However, in the case of failure SetLastError
2105 * must be set to distinguish between a 0 return value and a failure.
2107 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2109 STYLESTRUCT style;
2110 BOOL ok;
2111 LONG_PTR retval = 0;
2112 WND *wndPtr;
2114 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2116 if (is_broadcast(hwnd))
2118 SetLastError( ERROR_INVALID_PARAMETER );
2119 return FALSE;
2122 if (!(wndPtr = WIN_GetPtr( hwnd )))
2124 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2125 return 0;
2127 if (wndPtr == WND_DESKTOP)
2129 /* can't change anything on the desktop window */
2130 SetLastError( ERROR_ACCESS_DENIED );
2131 return 0;
2133 if (wndPtr == WND_OTHER_PROCESS)
2135 if (offset == GWLP_WNDPROC)
2137 SetLastError( ERROR_ACCESS_DENIED );
2138 return 0;
2140 if (offset > 32767 || offset < -32767)
2142 SetLastError( ERROR_INVALID_INDEX );
2143 return 0;
2145 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2148 /* first some special cases */
2149 switch( offset )
2151 case GWL_STYLE:
2152 case GWL_EXSTYLE:
2153 style.styleOld =
2154 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2155 style.styleNew = newval;
2156 WIN_ReleasePtr( wndPtr );
2157 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2158 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2159 newval = style.styleNew;
2160 break;
2161 case GWLP_HWNDPARENT:
2162 if (wndPtr->parent == GetDesktopWindow())
2164 WIN_ReleasePtr( wndPtr );
2165 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2167 else
2169 WIN_ReleasePtr( wndPtr );
2170 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2172 case GWLP_WNDPROC:
2174 WNDPROC proc;
2175 UINT old_flags = wndPtr->flags;
2176 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2177 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2178 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2179 if (proc) wndPtr->winproc = proc;
2180 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2181 else wndPtr->flags &= ~WIN_ISUNICODE;
2182 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2184 WIN_ReleasePtr( wndPtr );
2185 return retval;
2187 /* update is_unicode flag on the server side */
2188 break;
2190 case GWLP_ID:
2191 case GWLP_HINSTANCE:
2192 case GWLP_USERDATA:
2193 break;
2194 case DWLP_DLGPROC:
2195 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2196 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2198 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2199 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2200 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2201 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2202 WIN_ReleasePtr( wndPtr );
2203 return retval;
2205 /* fall through */
2206 default:
2207 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2209 WARN("Invalid offset %d\n", offset );
2210 WIN_ReleasePtr( wndPtr );
2211 SetLastError( ERROR_INVALID_INDEX );
2212 return 0;
2214 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2216 /* already set to the same value */
2217 WIN_ReleasePtr( wndPtr );
2218 return newval;
2220 break;
2223 SERVER_START_REQ( set_window_info )
2225 req->handle = wine_server_user_handle( hwnd );
2226 req->extra_offset = -1;
2227 switch(offset)
2229 case GWL_STYLE:
2230 req->flags = SET_WIN_STYLE;
2231 req->style = newval;
2232 break;
2233 case GWL_EXSTYLE:
2234 req->flags = SET_WIN_EXSTYLE;
2235 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2236 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2237 req->ex_style = newval;
2238 break;
2239 case GWLP_ID:
2240 req->flags = SET_WIN_ID;
2241 req->id = newval;
2242 break;
2243 case GWLP_HINSTANCE:
2244 req->flags = SET_WIN_INSTANCE;
2245 req->instance = wine_server_client_ptr( (void *)newval );
2246 break;
2247 case GWLP_WNDPROC:
2248 req->flags = SET_WIN_UNICODE;
2249 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2250 break;
2251 case GWLP_USERDATA:
2252 req->flags = SET_WIN_USERDATA;
2253 req->user_data = newval;
2254 break;
2255 default:
2256 req->flags = SET_WIN_EXTRA;
2257 req->extra_offset = offset;
2258 req->extra_size = size;
2259 set_win_data( &req->extra_value, newval, size );
2261 if ((ok = !wine_server_call_err( req )))
2263 switch(offset)
2265 case GWL_STYLE:
2266 wndPtr->dwStyle = newval;
2267 retval = reply->old_style;
2268 break;
2269 case GWL_EXSTYLE:
2270 wndPtr->dwExStyle = newval;
2271 retval = reply->old_ex_style;
2272 break;
2273 case GWLP_ID:
2274 wndPtr->wIDmenu = newval;
2275 retval = reply->old_id;
2276 break;
2277 case GWLP_HINSTANCE:
2278 wndPtr->hInstance = (HINSTANCE)newval;
2279 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2280 break;
2281 case GWLP_WNDPROC:
2282 break;
2283 case GWLP_USERDATA:
2284 wndPtr->userdata = newval;
2285 retval = reply->old_user_data;
2286 break;
2287 default:
2288 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2289 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2290 break;
2294 SERVER_END_REQ;
2295 WIN_ReleasePtr( wndPtr );
2297 if (!ok) return 0;
2299 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2301 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2302 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2305 return retval;
2309 /**********************************************************************
2310 * GetWindowWord (USER32.@)
2312 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2314 switch(offset)
2316 case GWLP_ID:
2317 case GWLP_HINSTANCE:
2318 case GWLP_HWNDPARENT:
2319 break;
2320 default:
2321 if (offset < 0)
2323 WARN("Invalid offset %d\n", offset );
2324 SetLastError( ERROR_INVALID_INDEX );
2325 return 0;
2327 break;
2329 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2333 /**********************************************************************
2334 * GetWindowLongA (USER32.@)
2336 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2338 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2342 /**********************************************************************
2343 * GetWindowLongW (USER32.@)
2345 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2347 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2351 /**********************************************************************
2352 * SetWindowWord (USER32.@)
2354 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2356 switch(offset)
2358 case GWLP_ID:
2359 case GWLP_HINSTANCE:
2360 case GWLP_HWNDPARENT:
2361 break;
2362 default:
2363 if (offset < 0)
2365 WARN("Invalid offset %d\n", offset );
2366 SetLastError( ERROR_INVALID_INDEX );
2367 return 0;
2369 break;
2371 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2375 /**********************************************************************
2376 * SetWindowLongA (USER32.@)
2378 * See SetWindowLongW.
2380 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2382 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2386 /**********************************************************************
2387 * SetWindowLongW (USER32.@) Set window attribute
2389 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2390 * value in a window's extra memory.
2392 * The _hwnd_ parameter specifies the window. is the handle to a
2393 * window that has extra memory. The _newval_ parameter contains the
2394 * new attribute or extra memory value. If positive, the _offset_
2395 * parameter is the byte-addressed location in the window's extra
2396 * memory to set. If negative, _offset_ specifies the window
2397 * attribute to set, and should be one of the following values:
2399 * GWL_EXSTYLE The window's extended window style
2401 * GWL_STYLE The window's window style.
2403 * GWLP_WNDPROC Pointer to the window's window procedure.
2405 * GWLP_HINSTANCE The window's pplication instance handle.
2407 * GWLP_ID The window's identifier.
2409 * GWLP_USERDATA The window's user-specified data.
2411 * If the window is a dialog box, the _offset_ parameter can be one of
2412 * the following values:
2414 * DWLP_DLGPROC The address of the window's dialog box procedure.
2416 * DWLP_MSGRESULT The return value of a message
2417 * that the dialog box procedure processed.
2419 * DWLP_USER Application specific information.
2421 * RETURNS
2423 * If successful, returns the previous value located at _offset_. Otherwise,
2424 * returns 0.
2426 * NOTES
2428 * Extra memory for a window class is specified by a nonzero cbWndExtra
2429 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2430 * time of class creation.
2432 * Using GWL_WNDPROC to set a new window procedure effectively creates
2433 * a window subclass. Use CallWindowProc() in the new windows procedure
2434 * to pass messages to the superclass's window procedure.
2436 * The user data is reserved for use by the application which created
2437 * the window.
2439 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2440 * instead, call the EnableWindow() function to change the window's
2441 * disabled state.
2443 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2444 * SetParent() instead.
2446 * Win95:
2447 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2448 * it sends WM_STYLECHANGING before changing the settings
2449 * and WM_STYLECHANGED afterwards.
2450 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2452 LONG WINAPI SetWindowLongW(
2453 HWND hwnd, /* [in] window to alter */
2454 INT offset, /* [in] offset, in bytes, of location to alter */
2455 LONG newval /* [in] new value of location */
2457 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2461 /*******************************************************************
2462 * GetWindowTextA (USER32.@)
2464 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2466 WCHAR *buffer;
2468 if (!lpString) return 0;
2470 if (WIN_IsCurrentProcess( hwnd ))
2471 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2473 /* when window belongs to other process, don't send a message */
2474 if (nMaxCount <= 0) return 0;
2475 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2476 get_server_window_text( hwnd, buffer, nMaxCount );
2477 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2478 lpString[nMaxCount-1] = 0;
2479 HeapFree( GetProcessHeap(), 0, buffer );
2480 return strlen(lpString);
2484 /*******************************************************************
2485 * InternalGetWindowText (USER32.@)
2487 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2489 WND *win;
2491 if (nMaxCount <= 0) return 0;
2492 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2493 if (win == WND_DESKTOP) lpString[0] = 0;
2494 else if (win != WND_OTHER_PROCESS)
2496 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2497 else lpString[0] = 0;
2498 WIN_ReleasePtr( win );
2500 else
2502 get_server_window_text( hwnd, lpString, nMaxCount );
2504 return strlenW(lpString);
2508 /*******************************************************************
2509 * GetWindowTextW (USER32.@)
2511 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2513 if (!lpString) return 0;
2515 if (WIN_IsCurrentProcess( hwnd ))
2516 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2518 /* when window belongs to other process, don't send a message */
2519 if (nMaxCount <= 0) return 0;
2520 get_server_window_text( hwnd, lpString, nMaxCount );
2521 return strlenW(lpString);
2525 /*******************************************************************
2526 * SetWindowTextA (USER32.@)
2527 * SetWindowText (USER32.@)
2529 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2531 if (is_broadcast(hwnd))
2533 SetLastError( ERROR_INVALID_PARAMETER );
2534 return FALSE;
2536 if (!WIN_IsCurrentProcess( hwnd ))
2537 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2538 debugstr_a(lpString), hwnd );
2539 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2543 /*******************************************************************
2544 * SetWindowTextW (USER32.@)
2546 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2548 if (is_broadcast(hwnd))
2550 SetLastError( ERROR_INVALID_PARAMETER );
2551 return FALSE;
2553 if (!WIN_IsCurrentProcess( hwnd ))
2554 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2555 debugstr_w(lpString), hwnd );
2556 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2560 /*******************************************************************
2561 * GetWindowTextLengthA (USER32.@)
2563 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2565 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2568 /*******************************************************************
2569 * GetWindowTextLengthW (USER32.@)
2571 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2573 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2577 /*******************************************************************
2578 * IsWindow (USER32.@)
2580 BOOL WINAPI IsWindow( HWND hwnd )
2582 WND *ptr;
2583 BOOL ret;
2585 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2586 if (ptr == WND_DESKTOP) return TRUE;
2588 if (ptr != WND_OTHER_PROCESS)
2590 WIN_ReleasePtr( ptr );
2591 return TRUE;
2594 /* check other processes */
2595 SERVER_START_REQ( get_window_info )
2597 req->handle = wine_server_user_handle( hwnd );
2598 ret = !wine_server_call_err( req );
2600 SERVER_END_REQ;
2601 return ret;
2605 /***********************************************************************
2606 * GetWindowThreadProcessId (USER32.@)
2608 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2610 WND *ptr;
2611 DWORD tid = 0;
2613 if (!(ptr = WIN_GetPtr( hwnd )))
2615 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2616 return 0;
2619 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2621 /* got a valid window */
2622 tid = ptr->tid;
2623 if (process) *process = GetCurrentProcessId();
2624 WIN_ReleasePtr( ptr );
2625 return tid;
2628 /* check other processes */
2629 SERVER_START_REQ( get_window_info )
2631 req->handle = wine_server_user_handle( hwnd );
2632 if (!wine_server_call_err( req ))
2634 tid = (DWORD)reply->tid;
2635 if (process) *process = (DWORD)reply->pid;
2638 SERVER_END_REQ;
2639 return tid;
2643 /*****************************************************************
2644 * GetParent (USER32.@)
2646 HWND WINAPI GetParent( HWND hwnd )
2648 WND *wndPtr;
2649 HWND retvalue = 0;
2651 if (!(wndPtr = WIN_GetPtr( hwnd )))
2653 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2654 return 0;
2656 if (wndPtr == WND_DESKTOP) return 0;
2657 if (wndPtr == WND_OTHER_PROCESS)
2659 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2660 if (style & (WS_POPUP | WS_CHILD))
2662 SERVER_START_REQ( get_window_tree )
2664 req->handle = wine_server_user_handle( hwnd );
2665 if (!wine_server_call_err( req ))
2667 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2668 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2671 SERVER_END_REQ;
2674 else
2676 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2677 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2678 WIN_ReleasePtr( wndPtr );
2680 return retvalue;
2684 /*****************************************************************
2685 * GetAncestor (USER32.@)
2687 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2689 WND *win;
2690 HWND *list, ret = 0;
2692 switch(type)
2694 case GA_PARENT:
2695 if (!(win = WIN_GetPtr( hwnd )))
2697 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2698 return 0;
2700 if (win == WND_DESKTOP) return 0;
2701 if (win != WND_OTHER_PROCESS)
2703 ret = win->parent;
2704 WIN_ReleasePtr( win );
2706 else /* need to query the server */
2708 SERVER_START_REQ( get_window_tree )
2710 req->handle = wine_server_user_handle( hwnd );
2711 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2713 SERVER_END_REQ;
2715 break;
2717 case GA_ROOT:
2718 if (!(list = list_window_parents( hwnd ))) return 0;
2720 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2721 else
2723 int count = 2;
2724 while (list[count]) count++;
2725 ret = list[count - 2]; /* get the one before the desktop */
2727 HeapFree( GetProcessHeap(), 0, list );
2728 break;
2730 case GA_ROOTOWNER:
2731 if (is_desktop_window( hwnd )) return 0;
2732 ret = WIN_GetFullHandle( hwnd );
2733 for (;;)
2735 HWND parent = GetParent( ret );
2736 if (!parent) break;
2737 ret = parent;
2739 break;
2741 return ret;
2745 /*****************************************************************
2746 * SetParent (USER32.@)
2748 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2750 HWND full_handle;
2751 HWND old_parent = 0;
2752 BOOL was_visible;
2753 WND *wndPtr;
2754 BOOL ret;
2756 if (is_broadcast(hwnd) || is_broadcast(parent))
2758 SetLastError(ERROR_INVALID_PARAMETER);
2759 return 0;
2762 if (!parent) parent = GetDesktopWindow();
2763 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2764 else parent = WIN_GetFullHandle( parent );
2766 if (!IsWindow( parent ))
2768 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2769 return 0;
2772 /* Some applications try to set a child as a parent */
2773 if (IsChild(hwnd, parent))
2775 SetLastError( ERROR_INVALID_PARAMETER );
2776 return 0;
2779 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2780 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2782 /* Windows hides the window first, then shows it again
2783 * including the WM_SHOWWINDOW messages and all */
2784 was_visible = ShowWindow( hwnd, SW_HIDE );
2786 wndPtr = WIN_GetPtr( hwnd );
2787 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2789 SERVER_START_REQ( set_parent )
2791 req->handle = wine_server_user_handle( hwnd );
2792 req->parent = wine_server_user_handle( parent );
2793 if ((ret = !wine_server_call( req )))
2795 old_parent = wine_server_ptr_handle( reply->old_parent );
2796 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2800 SERVER_END_REQ;
2801 WIN_ReleasePtr( wndPtr );
2802 if (!ret) return 0;
2804 USER_Driver->pSetParent( full_handle, parent, old_parent );
2806 /* SetParent additionally needs to make hwnd the topmost window
2807 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2808 WM_WINDOWPOSCHANGED notification messages.
2810 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2811 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2812 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2813 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2815 return old_parent;
2819 /*******************************************************************
2820 * IsChild (USER32.@)
2822 BOOL WINAPI IsChild( HWND parent, HWND child )
2824 HWND *list = list_window_parents( child );
2825 int i;
2826 BOOL ret;
2828 if (!list) return FALSE;
2829 parent = WIN_GetFullHandle( parent );
2830 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2831 ret = list[i] && list[i+1];
2832 HeapFree( GetProcessHeap(), 0, list );
2833 return ret;
2837 /***********************************************************************
2838 * IsWindowVisible (USER32.@)
2840 BOOL WINAPI IsWindowVisible( HWND hwnd )
2842 HWND *list;
2843 BOOL retval = TRUE;
2844 int i;
2846 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2847 if (!(list = list_window_parents( hwnd ))) return TRUE;
2848 if (list[0])
2850 for (i = 0; list[i+1]; i++)
2851 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2852 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2854 HeapFree( GetProcessHeap(), 0, list );
2855 return retval;
2859 /***********************************************************************
2860 * WIN_IsWindowDrawable
2862 * hwnd is drawable when it is visible, all parents are not
2863 * minimized, and it is itself not minimized unless we are
2864 * trying to draw its default class icon.
2866 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2868 HWND *list;
2869 BOOL retval = TRUE;
2870 int i;
2871 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2873 if (!(style & WS_VISIBLE)) return FALSE;
2874 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2876 if (!(list = list_window_parents( hwnd ))) return TRUE;
2877 if (list[0])
2879 for (i = 0; list[i+1]; i++)
2880 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2881 break;
2882 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2884 HeapFree( GetProcessHeap(), 0, list );
2885 return retval;
2889 /*******************************************************************
2890 * GetTopWindow (USER32.@)
2892 HWND WINAPI GetTopWindow( HWND hwnd )
2894 if (!hwnd) hwnd = GetDesktopWindow();
2895 return GetWindow( hwnd, GW_CHILD );
2899 /*******************************************************************
2900 * GetWindow (USER32.@)
2902 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2904 HWND retval = 0;
2906 if (rel == GW_OWNER) /* this one may be available locally */
2908 WND *wndPtr = WIN_GetPtr( hwnd );
2909 if (!wndPtr)
2911 SetLastError( ERROR_INVALID_HANDLE );
2912 return 0;
2914 if (wndPtr == WND_DESKTOP) return 0;
2915 if (wndPtr != WND_OTHER_PROCESS)
2917 retval = wndPtr->owner;
2918 WIN_ReleasePtr( wndPtr );
2919 return retval;
2921 /* else fall through to server call */
2924 SERVER_START_REQ( get_window_tree )
2926 req->handle = wine_server_user_handle( hwnd );
2927 if (!wine_server_call_err( req ))
2929 switch(rel)
2931 case GW_HWNDFIRST:
2932 retval = wine_server_ptr_handle( reply->first_sibling );
2933 break;
2934 case GW_HWNDLAST:
2935 retval = wine_server_ptr_handle( reply->last_sibling );
2936 break;
2937 case GW_HWNDNEXT:
2938 retval = wine_server_ptr_handle( reply->next_sibling );
2939 break;
2940 case GW_HWNDPREV:
2941 retval = wine_server_ptr_handle( reply->prev_sibling );
2942 break;
2943 case GW_OWNER:
2944 retval = wine_server_ptr_handle( reply->owner );
2945 break;
2946 case GW_CHILD:
2947 retval = wine_server_ptr_handle( reply->first_child );
2948 break;
2952 SERVER_END_REQ;
2953 return retval;
2957 /*******************************************************************
2958 * ShowOwnedPopups (USER32.@)
2960 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2962 int count = 0;
2963 WND *pWnd;
2964 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2966 if (!win_array) return TRUE;
2968 while (win_array[count]) count++;
2969 while (--count >= 0)
2971 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2972 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2973 if (pWnd == WND_OTHER_PROCESS) continue;
2974 if (fShow)
2976 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2978 WIN_ReleasePtr( pWnd );
2979 /* In Windows, ShowOwnedPopups(TRUE) generates
2980 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2981 * regardless of the state of the owner
2983 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2984 continue;
2987 else
2989 if (pWnd->dwStyle & WS_VISIBLE)
2991 WIN_ReleasePtr( pWnd );
2992 /* In Windows, ShowOwnedPopups(FALSE) generates
2993 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2994 * regardless of the state of the owner
2996 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2997 continue;
3000 WIN_ReleasePtr( pWnd );
3002 HeapFree( GetProcessHeap(), 0, win_array );
3003 return TRUE;
3007 /*******************************************************************
3008 * GetLastActivePopup (USER32.@)
3010 HWND WINAPI GetLastActivePopup( HWND hwnd )
3012 HWND retval = hwnd;
3014 SERVER_START_REQ( get_window_info )
3016 req->handle = wine_server_user_handle( hwnd );
3017 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3019 SERVER_END_REQ;
3020 return retval;
3024 /*******************************************************************
3025 * WIN_ListChildren
3027 * Build an array of the children of a given window. The array must be
3028 * freed with HeapFree. Returns NULL when no windows are found.
3030 HWND *WIN_ListChildren( HWND hwnd )
3032 if (!hwnd)
3034 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3035 return NULL;
3037 return list_window_children( 0, hwnd, NULL, 0 );
3041 /*******************************************************************
3042 * EnumWindows (USER32.@)
3044 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3046 HWND *list;
3047 BOOL ret = TRUE;
3048 int i;
3050 USER_CheckNotLock();
3052 /* We have to build a list of all windows first, to avoid */
3053 /* unpleasant side-effects, for instance if the callback */
3054 /* function changes the Z-order of the windows. */
3056 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3058 /* Now call the callback function for every window */
3060 for (i = 0; list[i]; i++)
3062 /* Make sure that the window still exists */
3063 if (!IsWindow( list[i] )) continue;
3064 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3066 HeapFree( GetProcessHeap(), 0, list );
3067 return ret;
3071 /**********************************************************************
3072 * EnumThreadWindows (USER32.@)
3074 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3076 HWND *list;
3077 int i;
3078 BOOL ret = TRUE;
3080 USER_CheckNotLock();
3082 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3084 /* Now call the callback function for every window */
3086 for (i = 0; list[i]; i++)
3087 if (!(ret = func( list[i], lParam ))) break;
3088 HeapFree( GetProcessHeap(), 0, list );
3089 return ret;
3093 /***********************************************************************
3094 * EnumDesktopWindows (USER32.@)
3096 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3098 HWND *list;
3099 int i;
3101 USER_CheckNotLock();
3103 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3105 for (i = 0; list[i]; i++)
3106 if (!func( list[i], lparam )) break;
3107 HeapFree( GetProcessHeap(), 0, list );
3108 return TRUE;
3112 /**********************************************************************
3113 * WIN_EnumChildWindows
3115 * Helper function for EnumChildWindows().
3117 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3119 HWND *childList;
3120 BOOL ret = FALSE;
3122 for ( ; *list; list++)
3124 /* Make sure that the window still exists */
3125 if (!IsWindow( *list )) continue;
3126 /* Build children list first */
3127 childList = WIN_ListChildren( *list );
3129 ret = func( *list, lParam );
3131 if (childList)
3133 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3134 HeapFree( GetProcessHeap(), 0, childList );
3136 if (!ret) return FALSE;
3138 return TRUE;
3142 /**********************************************************************
3143 * EnumChildWindows (USER32.@)
3145 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3147 HWND *list;
3148 BOOL ret;
3150 USER_CheckNotLock();
3152 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3153 ret = WIN_EnumChildWindows( list, func, lParam );
3154 HeapFree( GetProcessHeap(), 0, list );
3155 return ret;
3159 /*******************************************************************
3160 * AnyPopup (USER.52)
3162 BOOL16 WINAPI AnyPopup16(void)
3164 return AnyPopup();
3168 /*******************************************************************
3169 * AnyPopup (USER32.@)
3171 BOOL WINAPI AnyPopup(void)
3173 int i;
3174 BOOL retvalue;
3175 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3177 if (!list) return FALSE;
3178 for (i = 0; list[i]; i++)
3180 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3182 retvalue = (list[i] != 0);
3183 HeapFree( GetProcessHeap(), 0, list );
3184 return retvalue;
3188 /*******************************************************************
3189 * FlashWindow (USER32.@)
3191 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3193 WND *wndPtr;
3195 TRACE("%p\n", hWnd);
3197 if (IsIconic( hWnd ))
3199 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3201 wndPtr = WIN_GetPtr(hWnd);
3202 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3203 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3205 wndPtr->flags |= WIN_NCACTIVATED;
3207 else
3209 wndPtr->flags &= ~WIN_NCACTIVATED;
3211 WIN_ReleasePtr( wndPtr );
3212 return TRUE;
3214 else
3216 WPARAM wparam;
3218 wndPtr = WIN_GetPtr(hWnd);
3219 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3220 hWnd = wndPtr->obj.handle; /* make it a full handle */
3222 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3223 else wparam = (hWnd == GetForegroundWindow());
3225 WIN_ReleasePtr( wndPtr );
3226 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3227 return wparam;
3231 /*******************************************************************
3232 * FlashWindowEx (USER32.@)
3234 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3236 FIXME("%p\n", pfwi);
3237 return TRUE;
3240 /*******************************************************************
3241 * GetWindowContextHelpId (USER32.@)
3243 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3245 DWORD retval;
3246 WND *wnd = WIN_GetPtr( hwnd );
3247 if (!wnd || wnd == WND_DESKTOP) return 0;
3248 if (wnd == WND_OTHER_PROCESS)
3250 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3251 return 0;
3253 retval = wnd->helpContext;
3254 WIN_ReleasePtr( wnd );
3255 return retval;
3259 /*******************************************************************
3260 * SetWindowContextHelpId (USER32.@)
3262 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3264 WND *wnd = WIN_GetPtr( hwnd );
3265 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3266 if (wnd == WND_OTHER_PROCESS)
3268 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3269 return 0;
3271 wnd->helpContext = id;
3272 WIN_ReleasePtr( wnd );
3273 return TRUE;
3277 /*******************************************************************
3278 * DragDetect (USER32.@)
3280 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3282 MSG msg;
3283 RECT rect;
3284 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3285 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3287 rect.left = pt.x - wDragWidth;
3288 rect.right = pt.x + wDragWidth;
3290 rect.top = pt.y - wDragHeight;
3291 rect.bottom = pt.y + wDragHeight;
3293 SetCapture(hWnd);
3295 while(1)
3297 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3299 if( msg.message == WM_LBUTTONUP )
3301 ReleaseCapture();
3302 return 0;
3304 if( msg.message == WM_MOUSEMOVE )
3306 POINT tmp;
3307 tmp.x = (short)LOWORD(msg.lParam);
3308 tmp.y = (short)HIWORD(msg.lParam);
3309 if( !PtInRect( &rect, tmp ))
3311 ReleaseCapture();
3312 return 1;
3316 WaitMessage();
3318 return 0;
3321 /******************************************************************************
3322 * GetWindowModuleFileNameA (USER32.@)
3324 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3326 WND *win;
3327 HINSTANCE hinst;
3329 TRACE( "%p, %p, %u\n", hwnd, module, size );
3331 win = WIN_GetPtr( hwnd );
3332 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3334 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3335 return 0;
3337 hinst = win->hInstance;
3338 WIN_ReleasePtr( win );
3340 return GetModuleFileNameA( hinst, module, size );
3343 /******************************************************************************
3344 * GetWindowModuleFileNameW (USER32.@)
3346 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3348 WND *win;
3349 HINSTANCE hinst;
3351 TRACE( "%p, %p, %u\n", hwnd, module, size );
3353 win = WIN_GetPtr( hwnd );
3354 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3356 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3357 return 0;
3359 hinst = win->hInstance;
3360 WIN_ReleasePtr( win );
3362 return GetModuleFileNameW( hinst, module, size );
3365 /******************************************************************************
3366 * GetWindowInfo (USER32.@)
3368 * Note: tests show that Windows doesn't check cbSize of the structure.
3370 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3372 if (!pwi) return FALSE;
3373 if (!IsWindow(hwnd)) return FALSE;
3375 GetWindowRect(hwnd, &pwi->rcWindow);
3376 GetClientRect(hwnd, &pwi->rcClient);
3377 /* translate to screen coordinates */
3378 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3380 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3381 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3382 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3384 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3385 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3387 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3388 pwi->wCreatorVersion = 0x0400;
3390 return TRUE;
3393 /******************************************************************************
3394 * SwitchDesktop (USER32.@)
3396 * NOTES: Sets the current input or interactive desktop.
3398 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3400 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3401 return TRUE;
3404 /*****************************************************************************
3405 * SetLayeredWindowAttributes (USER32.@)
3407 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3409 BOOL ret;
3411 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3413 SERVER_START_REQ( set_window_layered_info )
3415 req->handle = wine_server_user_handle( hwnd );
3416 req->color_key = key;
3417 req->alpha = alpha;
3418 req->flags = flags;
3419 ret = !wine_server_call_err( req );
3421 SERVER_END_REQ;
3423 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3425 return ret;
3429 /*****************************************************************************
3430 * GetLayeredWindowAttributes (USER32.@)
3432 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3434 BOOL ret;
3436 SERVER_START_REQ( get_window_layered_info )
3438 req->handle = wine_server_user_handle( hwnd );
3439 if ((ret = !wine_server_call_err( req )))
3441 if (key) *key = reply->color_key;
3442 if (alpha) *alpha = reply->alpha;
3443 if (flags) *flags = reply->flags;
3446 SERVER_END_REQ;
3448 return ret;
3452 /*****************************************************************************
3453 * UpdateLayeredWindowIndirect (USER32.@)
3455 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3457 BYTE alpha = 0xff;
3459 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3461 int x = 0, y = 0, cx = 0, cy = 0;
3462 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3464 if (info->pptDst)
3466 x = info->pptDst->x;
3467 y = info->pptDst->y;
3468 flags &= ~SWP_NOMOVE;
3470 if (info->psize)
3472 cx = info->psize->cx;
3473 cy = info->psize->cy;
3474 flags &= ~SWP_NOSIZE;
3476 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3477 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3480 if (info->hdcSrc)
3482 RECT rect;
3483 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3485 if (hdc)
3487 int x = 0, y = 0;
3489 GetClientRect( hwnd, &rect );
3490 if (info->pptSrc)
3492 x = info->pptSrc->x;
3493 y = info->pptSrc->y;
3495 /* FIXME: intersect rect with info->prcDirty */
3496 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3497 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3498 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3499 ReleaseDC( hwnd, hdc );
3503 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3504 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3505 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3506 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3507 return TRUE;
3511 /*****************************************************************************
3512 * UpdateLayeredWindow (USER32.@)
3514 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3515 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3516 DWORD dwFlags)
3518 UPDATELAYEREDWINDOWINFO info;
3520 info.cbSize = sizeof(info);
3521 info.hdcDst = hdcDst;
3522 info.pptDst = pptDst;
3523 info.psize = psize;
3524 info.hdcSrc = hdcSrc;
3525 info.pptSrc = pptSrc;
3526 info.crKey = crKey;
3527 info.pblend = pblend;
3528 info.dwFlags = dwFlags;
3529 info.prcDirty = NULL;
3530 return UpdateLayeredWindowIndirect( hwnd, &info );
3533 /* 64bit versions */
3535 #ifdef GetWindowLongPtrW
3536 #undef GetWindowLongPtrW
3537 #endif
3539 #ifdef GetWindowLongPtrA
3540 #undef GetWindowLongPtrA
3541 #endif
3543 #ifdef SetWindowLongPtrW
3544 #undef SetWindowLongPtrW
3545 #endif
3547 #ifdef SetWindowLongPtrA
3548 #undef SetWindowLongPtrA
3549 #endif
3551 /*****************************************************************************
3552 * GetWindowLongPtrW (USER32.@)
3554 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3556 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3559 /*****************************************************************************
3560 * GetWindowLongPtrA (USER32.@)
3562 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3564 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3567 /*****************************************************************************
3568 * SetWindowLongPtrW (USER32.@)
3570 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3572 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3575 /*****************************************************************************
3576 * SetWindowLongPtrA (USER32.@)
3578 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3580 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );