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
22 #include "wine/port.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
36 #include "user_private.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))
54 memcpy( &ret, ptr, sizeof(ret) );
57 else if (size == sizeof(DWORD))
60 memcpy( &ret, ptr, sizeof(ret) );
66 memcpy( &ret, ptr, sizeof(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))
77 memcpy( ptr, &newval, sizeof(newval) );
79 else if (size == sizeof(DWORD))
82 memcpy( ptr, &newval, sizeof(newval) );
86 memcpy( ptr, &val, sizeof(val) );
91 static void *user_handles[NB_USER_HANDLES];
93 /***********************************************************************
94 * create_window_handle
96 * Create a window handle with the server.
98 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
99 HINSTANCE instance, BOOL unicode )
103 HWND full_parent = 0, full_owner = 0;
104 struct tagCLASS *class = NULL;
105 user_handle_t handle = 0;
108 /* if 16-bit instance, map to module handle */
109 if (instance && !HIWORD(instance))
110 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
112 SERVER_START_REQ( create_window )
114 req->parent = parent;
116 req->instance = instance;
117 if (!(req->atom = get_int_atom_value( name )) && name)
118 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
119 if (!wine_server_call_err( req ))
121 handle = reply->handle;
122 full_parent = reply->parent;
123 full_owner = reply->owner;
124 extra_bytes = reply->extra;
125 class = reply->class_ptr;
132 WARN( "error %d creating window\n", GetLastError() );
136 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
138 SERVER_START_REQ( destroy_window )
140 req->handle = handle;
141 wine_server_call( req );
144 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
148 if (!parent) /* if parent is 0 we don't have a desktop window yet */
150 struct user_thread_info *thread_info = get_user_thread_info();
152 if (!thread_info->desktop) thread_info->desktop = full_parent ? full_parent : handle;
153 else assert( full_parent == thread_info->desktop );
154 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
155 ERR( "failed to create desktop window\n" );
160 index = USER_HANDLE_TO_INDEX(handle);
161 assert( index < NB_USER_HANDLES );
162 user_handles[index] = win;
163 win->hwndSelf = handle;
164 win->parent = full_parent;
165 win->owner = full_owner;
166 win->dwMagic = WND_MAGIC;
168 win->cbWndExtra = extra_bytes;
169 SetRectEmpty( &win->rectWindow );
170 SetRectEmpty( &win->rectClient );
171 memset( win->wExtra, 0, extra_bytes );
172 CLASS_AddWindow( class, win, unicode );
177 /***********************************************************************
180 * Free a window handle.
182 static WND *free_window_handle( HWND hwnd )
185 WORD index = USER_HANDLE_TO_INDEX(hwnd);
187 if (index >= NB_USER_HANDLES) return NULL;
189 if ((ptr = user_handles[index]))
191 SERVER_START_REQ( destroy_window )
194 if (!wine_server_call_err( req ))
196 user_handles[index] = NULL;
205 HeapFree( GetProcessHeap(), 0, ptr );
210 /*******************************************************************
211 * list_window_children
213 * Build an array of the children of a given window. The array must be
214 * freed with HeapFree. Returns NULL when no windows are found.
216 static HWND *list_window_children( HWND hwnd, LPCWSTR class, DWORD tid )
225 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
227 SERVER_START_REQ( get_window_children )
231 if (!(req->atom = get_int_atom_value( class )) && class)
232 wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
233 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
234 if (!wine_server_call( req )) count = reply->count;
237 if (count && count < size)
242 HeapFree( GetProcessHeap(), 0, list );
244 size = count + 1; /* restart with a large enough buffer */
250 /*******************************************************************
251 * list_window_parents
253 * Build an array of all parents of a given window, starting with
254 * the immediate parent. The array must be freed with HeapFree.
256 static HWND *list_window_parents( HWND hwnd )
260 int pos = 0, size = 16, count = 0;
262 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
267 if (!(win = WIN_GetPtr( current ))) goto empty;
268 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
269 if (win == WND_DESKTOP)
271 if (!pos) goto empty;
275 list[pos] = current = win->parent;
276 WIN_ReleasePtr( win );
277 if (++pos == size - 1)
279 /* need to grow the list */
280 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
281 if (!new_list) goto empty;
287 /* at least one parent belongs to another process, have to query the server */
292 SERVER_START_REQ( get_window_parents )
295 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
296 if (!wine_server_call( req )) count = reply->count;
299 if (!count) goto empty;
305 HeapFree( GetProcessHeap(), 0, list );
307 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
311 HeapFree( GetProcessHeap(), 0, list );
316 /*******************************************************************
319 static void send_parent_notify( HWND hwnd, UINT msg )
321 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
322 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
324 HWND parent = GetParent(hwnd);
325 if (parent && parent != GetDesktopWindow())
326 SendMessageW( parent, WM_PARENTNOTIFY,
327 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
332 /*******************************************************************
333 * get_server_window_text
335 * Retrieve the window text from the server.
337 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
341 SERVER_START_REQ( get_window_text )
344 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
345 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
348 text[len / sizeof(WCHAR)] = 0;
352 /***********************************************************************
355 * Return a pointer to the WND structure if local to the process,
356 * or WND_OTHER_PROCESS if handle may be valid in other process.
357 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
359 WND *WIN_GetPtr( HWND hwnd )
362 WORD index = USER_HANDLE_TO_INDEX(hwnd);
364 if (index >= NB_USER_HANDLES) return NULL;
367 if ((ptr = user_handles[index]))
369 if (ptr->dwMagic == WND_MAGIC &&
370 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
374 else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
376 if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
379 else ptr = WND_OTHER_PROCESS;
385 /***********************************************************************
386 * WIN_IsCurrentProcess
388 * Check whether a given window belongs to the current process (and return the full handle).
390 HWND WIN_IsCurrentProcess( HWND hwnd )
395 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
397 WIN_ReleasePtr( ptr );
402 /***********************************************************************
403 * WIN_IsCurrentThread
405 * Check whether a given window belongs to the current thread (and return the full handle).
407 HWND WIN_IsCurrentThread( HWND hwnd )
412 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
413 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
414 WIN_ReleasePtr( ptr );
419 /***********************************************************************
422 * Convert a 16-bit window handle to a full 32-bit handle.
424 HWND WIN_Handle32( HWND16 hwnd16 )
427 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
429 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
430 /* do sign extension for -2 and -3 */
431 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
433 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
435 if (ptr == WND_DESKTOP) return GetDesktopWindow();
437 if (ptr != WND_OTHER_PROCESS)
439 hwnd = ptr->hwndSelf;
440 WIN_ReleasePtr( ptr );
442 else /* may belong to another process */
444 SERVER_START_REQ( get_window_info )
447 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
455 /***********************************************************************
458 * Change the owner of a window.
460 HWND WIN_SetOwner( HWND hwnd, HWND owner )
462 WND *win = WIN_GetPtr( hwnd );
465 if (!win || win == WND_DESKTOP) return 0;
466 if (win == WND_OTHER_PROCESS)
468 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
471 SERVER_START_REQ( set_window_owner )
475 if (!wine_server_call( req ))
477 win->owner = reply->full_owner;
478 ret = reply->prev_owner;
482 WIN_ReleasePtr( win );
487 /***********************************************************************
490 * Change the style of a window.
492 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
495 ULONG new_style, old_style = 0;
496 WND *win = WIN_GetPtr( hwnd );
498 if (!win || win == WND_DESKTOP) return 0;
499 if (win == WND_OTHER_PROCESS)
502 ERR( "cannot set style %x/%x on other process window %p\n",
503 set_bits, clear_bits, hwnd );
506 new_style = (win->dwStyle | set_bits) & ~clear_bits;
507 if (new_style == win->dwStyle)
509 WIN_ReleasePtr( win );
512 SERVER_START_REQ( set_window_info )
515 req->flags = SET_WIN_STYLE;
516 req->style = new_style;
517 req->extra_offset = -1;
518 if ((ok = !wine_server_call( req )))
520 old_style = reply->old_style;
521 win->dwStyle = new_style;
525 WIN_ReleasePtr( win );
526 if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
531 /***********************************************************************
534 * Get the window and client rectangles.
536 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
538 WND *win = WIN_GetPtr( hwnd );
541 if (!win) return FALSE;
542 if (win == WND_DESKTOP)
545 rect.left = rect.top = 0;
546 rect.right = GetSystemMetrics(SM_CXSCREEN);
547 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
548 if (rectWindow) *rectWindow = rect;
549 if (rectClient) *rectClient = rect;
551 else if (win == WND_OTHER_PROCESS)
553 SERVER_START_REQ( get_window_rectangles )
556 if ((ret = !wine_server_call( req )))
560 rectWindow->left = reply->window.left;
561 rectWindow->top = reply->window.top;
562 rectWindow->right = reply->window.right;
563 rectWindow->bottom = reply->window.bottom;
567 rectClient->left = reply->client.left;
568 rectClient->top = reply->client.top;
569 rectClient->right = reply->client.right;
570 rectClient->bottom = reply->client.bottom;
578 if (rectWindow) *rectWindow = win->rectWindow;
579 if (rectClient) *rectClient = win->rectClient;
580 WIN_ReleasePtr( win );
586 /***********************************************************************
589 * Destroy storage associated to a window. "Internals" p.358
591 LRESULT WIN_DestroyWindow( HWND hwnd )
595 HMENU menu = 0, sys_menu;
597 TRACE("%p\n", hwnd );
599 /* free child windows */
600 if ((list = WIN_ListChildren( hwnd )))
603 for (i = 0; list[i]; i++)
605 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
606 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
608 HeapFree( GetProcessHeap(), 0, list );
611 /* Unlink now so we won't bother with the children later on */
612 SERVER_START_REQ( set_parent )
616 wine_server_call( req );
621 * Send the WM_NCDESTROY to the window being destroyed.
623 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
625 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
627 WINPOS_CheckInternalPos( hwnd );
629 /* free resources associated with the window */
631 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
632 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
633 menu = (HMENU)wndPtr->wIDmenu;
634 sys_menu = wndPtr->hSysMenu;
635 WIN_ReleasePtr( wndPtr );
637 if (menu) DestroyMenu( menu );
638 if (sys_menu) DestroyMenu( sys_menu );
640 USER_Driver->pDestroyWindow( hwnd );
642 free_window_handle( hwnd );
646 /***********************************************************************
647 * WIN_DestroyThreadWindows
649 * Destroy all children of 'wnd' owned by the current thread.
651 void WIN_DestroyThreadWindows( HWND hwnd )
656 if (!(list = WIN_ListChildren( hwnd ))) return;
657 for (i = 0; list[i]; i++)
659 if (WIN_IsCurrentThread( list[i] ))
660 DestroyWindow( list[i] );
662 WIN_DestroyThreadWindows( list[i] );
664 HeapFree( GetProcessHeap(), 0, list );
668 /***********************************************************************
671 * Fix the coordinates - Helper for WIN_CreateWindowEx.
672 * returns default show mode in sw.
674 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
676 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
679 if (cs->dwExStyle & WS_EX_MDICHILD)
683 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
684 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
686 TRACE("MDI child id %04x\n", id);
689 if (cs->style & (WS_CHILD | WS_POPUP))
691 if (cs->dwExStyle & WS_EX_MDICHILD)
693 if (IS_DEFAULT(cs->x))
698 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
699 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
703 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
704 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
707 else /* overlapped window */
710 MONITORINFO mon_info;
713 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
715 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
716 mon_info.cbSize = sizeof(mon_info);
717 GetMonitorInfoW( monitor, &mon_info );
718 GetStartupInfoW( &info );
720 if (IS_DEFAULT(cs->x))
722 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
723 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
724 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
727 if (IS_DEFAULT(cs->cx))
729 if (info.dwFlags & STARTF_USESIZE)
731 cs->cx = info.dwXSize;
732 cs->cy = info.dwYSize;
736 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
737 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
740 /* neither x nor cx are default. Check the y values .
741 * In the trace we see Outlook and Outlook Express using
742 * cy set to CW_USEDEFAULT when opening the address book.
744 else if (IS_DEFAULT(cs->cy))
746 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
747 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
753 /***********************************************************************
756 static void dump_window_styles( DWORD style, DWORD exstyle )
759 if(style & WS_POPUP) TRACE(" WS_POPUP");
760 if(style & WS_CHILD) TRACE(" WS_CHILD");
761 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
762 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
763 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
764 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
765 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
766 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
767 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
770 if(style & WS_BORDER) TRACE(" WS_BORDER");
771 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
773 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
774 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
775 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
776 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
777 if (style & WS_CHILD)
779 if(style & WS_GROUP) TRACE(" WS_GROUP");
780 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
784 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
785 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
788 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
789 #define DUMPED_STYLES \
809 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
814 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
815 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
816 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
817 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
818 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
819 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
820 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
821 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
822 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
823 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
824 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
825 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
826 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
827 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
828 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
829 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
830 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
831 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
833 #define DUMPED_EX_STYLES \
834 (WS_EX_DLGMODALFRAME | \
836 WS_EX_NOPARENTNOTIFY | \
838 WS_EX_ACCEPTFILES | \
839 WS_EX_TRANSPARENT | \
844 WS_EX_CONTEXTHELP | \
847 WS_EX_LEFTSCROLLBAR | \
848 WS_EX_CONTROLPARENT | \
853 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
855 #undef DUMPED_EX_STYLES
859 /***********************************************************************
862 * Implementation of CreateWindowEx().
864 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
866 INT cx, cy, sw = SW_SHOW;
870 HWND hwnd, parent, owner, top_child = 0;
871 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
872 MDICREATESTRUCTA mdi_cs;
876 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
877 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
878 debugstr_w(className),
879 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
880 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
881 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
883 /* Fix the styles for MDI children */
884 if (cs->dwExStyle & WS_EX_MDICHILD)
888 wndPtr = WIN_GetPtr(cs->hwndParent);
889 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
891 flags = wndPtr->flags;
892 WIN_ReleasePtr(wndPtr);
895 if (!(flags & WIN_ISMDICLIENT))
897 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
901 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
902 * MDICREATESTRUCT members have the originally passed values.
904 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
905 * have the same layout.
907 mdi_cs.szClass = cs->lpszClass;
908 mdi_cs.szTitle = cs->lpszName;
909 mdi_cs.hOwner = cs->hInstance;
914 mdi_cs.style = cs->style;
915 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
917 cs->lpCreateParams = (LPVOID)&mdi_cs;
919 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
921 if (cs->style & WS_POPUP)
923 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
926 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
930 cs->style &= ~WS_POPUP;
931 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
932 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
935 top_child = GetWindow(cs->hwndParent, GW_CHILD);
939 /* Restore current maximized child */
940 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
942 TRACE("Restoring current maximized child %p\n", top_child);
943 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
944 ShowWindow( top_child, SW_SHOWNORMAL );
945 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
950 /* Find the parent window */
952 parent = cs->hwndParent;
955 if (cs->hwndParent == HWND_MESSAGE)
957 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
958 * message window (style: WS_POPUP|WS_DISABLED)
960 FIXME("Parent is HWND_MESSAGE\n");
961 parent = GetDesktopWindow();
963 else if (cs->hwndParent)
965 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
967 parent = GetDesktopWindow();
968 owner = cs->hwndParent;
973 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
975 WARN("No parent for child window\n" );
976 SetLastError(ERROR_TLW_WITH_WSCHILD);
977 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
979 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM) /* are we creating the desktop itself? */
980 parent = GetDesktopWindow();
983 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
985 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
986 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
987 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
988 cs->dwExStyle |= WS_EX_WINDOWEDGE;
990 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
992 /* Create the window structure */
994 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
996 hwnd = wndPtr->hwndSelf;
998 /* Fill the window structure */
1000 wndPtr->tid = GetCurrentThreadId();
1001 wndPtr->hInstance = cs->hInstance;
1002 wndPtr->text = NULL;
1003 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1004 wndPtr->dwExStyle = cs->dwExStyle;
1005 wndPtr->wIDmenu = 0;
1006 wndPtr->helpContext = 0;
1007 wndPtr->pVScroll = NULL;
1008 wndPtr->pHScroll = NULL;
1009 wndPtr->userdata = 0;
1011 wndPtr->hIconSmall = 0;
1012 wndPtr->hSysMenu = 0;
1013 wndPtr->flags |= (flags & WIN_ISWIN32);
1015 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1018 * Correct the window styles.
1020 * It affects only the style loaded into the WIN structure.
1023 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1025 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1026 if (!(wndPtr->dwStyle & WS_POPUP))
1027 wndPtr->dwStyle |= WS_CAPTION;
1031 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1032 * why does the user get to set it?
1035 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1036 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1037 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1039 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1041 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1042 wndPtr->flags |= WIN_NEED_SIZE;
1044 SERVER_START_REQ( set_window_info )
1047 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1048 req->style = wndPtr->dwStyle;
1049 req->ex_style = wndPtr->dwExStyle;
1050 req->instance = (void *)wndPtr->hInstance;
1051 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1052 req->extra_offset = -1;
1053 wine_server_call( req );
1057 /* Set the window menu */
1059 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1063 if (!MENU_SetMenu(hwnd, cs->hMenu))
1065 WIN_ReleasePtr( wndPtr );
1066 free_window_handle( hwnd );
1072 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1075 if (!cs->hInstance || HIWORD(cs->hInstance))
1076 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1078 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1080 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1084 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1086 /* call the WH_CBT hook */
1088 /* the window style passed to the hook must be the real window style,
1089 * rather than just the window style that the caller to CreateWindowEx
1090 * passed in, so we have to copy the original CREATESTRUCT and get the
1091 * the real style. */
1093 cbcs.style = wndPtr->dwStyle;
1095 cbtc.hwndInsertAfter = HWND_TOP;
1096 WIN_ReleasePtr( wndPtr );
1097 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1099 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1103 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1105 POINT maxSize, maxPos, minTrack, maxTrack;
1106 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1107 if (maxTrack.x < cx) cx = maxTrack.x;
1108 if (maxTrack.y < cy) cy = maxTrack.y;
1113 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1114 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1116 /* send WM_NCCREATE */
1118 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1120 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1122 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1125 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1129 /* send WM_NCCALCSIZE */
1131 if ((wndPtr = WIN_GetPtr(hwnd)))
1133 /* yes, even if the CBT hook was called with HWND_TOP */
1134 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1135 RECT window_rect = wndPtr->rectWindow;
1136 RECT client_rect = window_rect;
1137 WIN_ReleasePtr( wndPtr );
1138 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1139 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1143 /* send WM_CREATE */
1146 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1148 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1149 if (result == -1) goto failed;
1151 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1153 /* send the size messages */
1155 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1156 if (!(wndPtr->flags & WIN_NEED_SIZE))
1158 rect = wndPtr->rectClient;
1159 WIN_ReleasePtr( wndPtr );
1160 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1161 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1162 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1164 else WIN_ReleasePtr( wndPtr );
1166 /* call the driver */
1168 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1170 /* Notify the parent window only */
1172 send_parent_notify( hwnd, WM_CREATE );
1173 if (!IsWindow( hwnd )) return 0;
1175 if (cs->style & WS_VISIBLE)
1177 if (cs->style & WS_MAXIMIZE)
1179 else if (cs->style & WS_MINIMIZE)
1180 sw = SW_SHOWMINIMIZED;
1182 ShowWindow( hwnd, sw );
1183 if (cs->dwExStyle & WS_EX_MDICHILD)
1185 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1186 /* ShowWindow won't activate child windows */
1187 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1191 /* Call WH_SHELL hook */
1193 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1194 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1196 TRACE("created window %p\n", hwnd);
1200 WIN_DestroyWindow( hwnd );
1205 /***********************************************************************
1206 * CreateWindow (USER.41)
1208 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1209 DWORD style, INT16 x, INT16 y, INT16 width,
1210 INT16 height, HWND16 parent, HMENU16 menu,
1211 HINSTANCE16 instance, LPVOID data )
1213 return CreateWindowEx16( 0, className, windowName, style,
1214 x, y, width, height, parent, menu, instance, data );
1218 /***********************************************************************
1219 * CreateWindowEx (USER.452)
1221 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1222 LPCSTR windowName, DWORD style, INT16 x,
1223 INT16 y, INT16 width, INT16 height,
1224 HWND16 parent, HMENU16 menu,
1225 HINSTANCE16 instance, LPVOID data )
1230 /* Fix the coordinates */
1232 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1233 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1234 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1235 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1237 /* Create the window */
1239 cs.lpCreateParams = data;
1240 cs.hInstance = HINSTANCE_32(instance);
1241 cs.hMenu = HMENU_32(menu);
1242 cs.hwndParent = WIN_Handle32( parent );
1244 cs.lpszName = windowName;
1245 cs.lpszClass = className;
1246 cs.dwExStyle = exStyle;
1248 if (!IS_INTRESOURCE(className))
1252 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1254 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1258 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1260 ERR( "bad atom %x\n", LOWORD(className));
1263 cs.lpszClass = buffer;
1264 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1269 /***********************************************************************
1270 * CreateWindowExA (USER32.@)
1272 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1273 LPCSTR windowName, DWORD style, INT x,
1274 INT y, INT width, INT height,
1275 HWND parent, HMENU menu,
1276 HINSTANCE instance, LPVOID data )
1280 cs.lpCreateParams = data;
1281 cs.hInstance = instance;
1283 cs.hwndParent = parent;
1289 cs.lpszName = windowName;
1290 cs.lpszClass = className;
1291 cs.dwExStyle = exStyle;
1293 if (!IS_INTRESOURCE(className))
1296 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1298 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1300 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1304 /***********************************************************************
1305 * CreateWindowExW (USER32.@)
1307 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1308 LPCWSTR windowName, DWORD style, INT x,
1309 INT y, INT width, INT height,
1310 HWND parent, HMENU menu,
1311 HINSTANCE instance, LPVOID data )
1315 cs.lpCreateParams = data;
1316 cs.hInstance = instance;
1318 cs.hwndParent = parent;
1324 cs.lpszName = windowName;
1325 cs.lpszClass = className;
1326 cs.dwExStyle = exStyle;
1328 /* Note: we rely on the fact that CREATESTRUCTA and */
1329 /* CREATESTRUCTW have the same layout. */
1330 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1334 /***********************************************************************
1335 * WIN_SendDestroyMsg
1337 static void WIN_SendDestroyMsg( HWND hwnd )
1341 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1343 if (hwnd == info.hwndCaret) DestroyCaret();
1344 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1348 * Send the WM_DESTROY to the window.
1350 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1353 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1354 * make sure that the window still exists when we come back.
1361 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1363 for (i = 0; pWndArray[i]; i++)
1365 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1367 HeapFree( GetProcessHeap(), 0, pWndArray );
1370 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1374 /***********************************************************************
1375 * DestroyWindow (USER32.@)
1377 BOOL WINAPI DestroyWindow( HWND hwnd )
1381 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1383 SetLastError( ERROR_ACCESS_DENIED );
1387 TRACE("(%p)\n", hwnd);
1391 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1393 if (MENU_IsMenuActive() == hwnd)
1396 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1400 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1401 send_parent_notify( hwnd, WM_DESTROY );
1403 else if (!GetWindow( hwnd, GW_OWNER ))
1405 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1406 /* FIXME: clean up palette - see "Internals" p.352 */
1409 if (!IsWindow(hwnd)) return TRUE;
1411 /* Hide the window */
1412 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1414 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1416 ShowWindow( hwnd, SW_HIDE );
1418 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1419 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1422 if (!IsWindow(hwnd)) return TRUE;
1424 /* Recursively destroy owned windows */
1431 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1434 for (i = 0; list[i]; i++)
1436 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1437 if (WIN_IsCurrentThread( list[i] ))
1439 DestroyWindow( list[i] );
1443 WIN_SetOwner( list[i], 0 );
1445 HeapFree( GetProcessHeap(), 0, list );
1447 if (!got_one) break;
1451 /* Send destroy messages */
1453 WIN_SendDestroyMsg( hwnd );
1454 if (!IsWindow( hwnd )) return TRUE;
1456 if (GetClipboardOwner() == hwnd)
1457 CLIPBOARD_ReleaseOwner();
1459 /* Destroy the window storage */
1461 WIN_DestroyWindow( hwnd );
1466 /***********************************************************************
1467 * CloseWindow (USER32.@)
1469 BOOL WINAPI CloseWindow( HWND hwnd )
1471 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1472 ShowWindow( hwnd, SW_MINIMIZE );
1477 /***********************************************************************
1478 * OpenIcon (USER32.@)
1480 BOOL WINAPI OpenIcon( HWND hwnd )
1482 if (!IsIconic( hwnd )) return FALSE;
1483 ShowWindow( hwnd, SW_SHOWNORMAL );
1488 /***********************************************************************
1489 * FindWindowExW (USER32.@)
1491 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1496 WCHAR *buffer = NULL;
1498 if (!parent) parent = GetDesktopWindow();
1501 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1502 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1505 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1509 child = WIN_GetFullHandle( child );
1510 while (list[i] && list[i] != child) i++;
1511 if (!list[i]) goto done;
1512 i++; /* start from next window */
1519 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1526 HeapFree( GetProcessHeap(), 0, list );
1527 HeapFree( GetProcessHeap(), 0, buffer );
1533 /***********************************************************************
1534 * FindWindowA (USER32.@)
1536 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1538 HWND ret = FindWindowExA( 0, 0, className, title );
1539 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1544 /***********************************************************************
1545 * FindWindowExA (USER32.@)
1547 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1549 LPWSTR titleW = NULL;
1554 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1555 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1556 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1559 if (!IS_INTRESOURCE(className))
1562 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1563 hwnd = FindWindowExW( parent, child, classW, titleW );
1567 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1570 HeapFree( GetProcessHeap(), 0, titleW );
1575 /***********************************************************************
1576 * FindWindowW (USER32.@)
1578 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1580 return FindWindowExW( 0, 0, className, title );
1584 /**********************************************************************
1585 * GetDesktopWindow (USER32.@)
1587 HWND WINAPI GetDesktopWindow(void)
1589 struct user_thread_info *thread_info = get_user_thread_info();
1591 if (thread_info->desktop) return thread_info->desktop;
1593 SERVER_START_REQ( get_desktop_window )
1596 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1600 if (!thread_info->desktop)
1602 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1604 PROCESS_INFORMATION pi;
1605 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1607 memset( &si, 0, sizeof(si) );
1609 si.dwFlags = STARTF_USESTDHANDLES;
1612 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1614 GetSystemDirectoryW( cmdline, MAX_PATH );
1615 lstrcatW( cmdline, command_line );
1616 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1617 NULL, NULL, &si, &pi ))
1619 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1620 WaitForInputIdle( pi.hProcess, 10000 );
1621 CloseHandle( pi.hThread );
1622 CloseHandle( pi.hProcess );
1625 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1627 SERVER_START_REQ( get_desktop_window )
1630 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1635 if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1636 ERR( "failed to create desktop window\n" );
1638 return thread_info->desktop;
1642 /*******************************************************************
1643 * EnableWindow (USER32.@)
1645 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1650 if (is_broadcast(hwnd))
1652 SetLastError( ERROR_INVALID_PARAMETER );
1656 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1657 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1661 TRACE("( %p, %d )\n", hwnd, enable);
1663 retvalue = !IsWindowEnabled( hwnd );
1665 if (enable && retvalue)
1667 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1668 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1670 else if (!enable && !retvalue)
1674 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1676 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1678 if (hwnd == GetFocus())
1679 SetFocus( 0 ); /* A disabled window can't have the focus */
1681 capture_wnd = GetCapture();
1682 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1683 ReleaseCapture(); /* A disabled window can't capture the mouse */
1685 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1691 /***********************************************************************
1692 * IsWindowEnabled (USER32.@)
1694 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1696 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1700 /***********************************************************************
1701 * IsWindowUnicode (USER32.@)
1703 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1706 BOOL retvalue = FALSE;
1708 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1710 if (wndPtr == WND_DESKTOP) return TRUE;
1712 if (wndPtr != WND_OTHER_PROCESS)
1714 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1715 WIN_ReleasePtr( wndPtr );
1719 SERVER_START_REQ( get_window_info )
1722 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1730 /**********************************************************************
1733 * Helper function for GetWindowLong().
1735 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1737 LONG_PTR retvalue = 0;
1740 if (offset == GWLP_HWNDPARENT)
1742 HWND parent = GetAncestor( hwnd, GA_PARENT );
1743 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1744 return (ULONG_PTR)parent;
1747 if (!(wndPtr = WIN_GetPtr( hwnd )))
1749 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1753 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1755 if (offset == GWLP_WNDPROC)
1757 SetLastError( ERROR_ACCESS_DENIED );
1760 SERVER_START_REQ( set_window_info )
1763 req->flags = 0; /* don't set anything, just retrieve */
1764 req->extra_offset = (offset >= 0) ? offset : -1;
1765 req->extra_size = (offset >= 0) ? size : 0;
1766 if (!wine_server_call_err( req ))
1770 case GWL_STYLE: retvalue = reply->old_style; break;
1771 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1772 case GWLP_ID: retvalue = reply->old_id; break;
1773 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1774 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1776 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1777 else SetLastError( ERROR_INVALID_INDEX );
1786 /* now we have a valid wndPtr */
1790 if (offset > (int)(wndPtr->cbWndExtra - size))
1792 WARN("Invalid offset %d\n", offset );
1793 WIN_ReleasePtr( wndPtr );
1794 SetLastError( ERROR_INVALID_INDEX );
1797 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1799 /* Special case for dialog window procedure */
1800 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1801 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1802 WIN_ReleasePtr( wndPtr );
1808 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1809 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1810 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1811 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1812 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1814 /* This looks like a hack only for the edit control (see tests). This makes these controls
1815 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1816 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1818 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1819 retvalue = (ULONG_PTR)wndPtr->winproc;
1821 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1824 WARN("Unknown offset %d\n", offset );
1825 SetLastError( ERROR_INVALID_INDEX );
1828 WIN_ReleasePtr(wndPtr);
1833 /**********************************************************************
1836 * Helper function for SetWindowLong().
1838 * 0 is the failure code. However, in the case of failure SetLastError
1839 * must be set to distinguish between a 0 return value and a failure.
1841 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1845 LONG_PTR retval = 0;
1848 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1850 if (is_broadcast(hwnd))
1852 SetLastError( ERROR_INVALID_PARAMETER );
1856 if (!(wndPtr = WIN_GetPtr( hwnd )))
1858 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1861 if (wndPtr == WND_DESKTOP)
1863 /* can't change anything on the desktop window */
1864 SetLastError( ERROR_ACCESS_DENIED );
1867 if (wndPtr == WND_OTHER_PROCESS)
1869 if (offset == GWLP_WNDPROC)
1871 SetLastError( ERROR_ACCESS_DENIED );
1874 if (offset > 32767 || offset < -32767)
1876 SetLastError( ERROR_INVALID_INDEX );
1879 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1882 /* first some special cases */
1888 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1889 style.styleNew = newval;
1890 WIN_ReleasePtr( wndPtr );
1891 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1892 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1893 newval = style.styleNew;
1895 case GWLP_HWNDPARENT:
1896 if (wndPtr->parent == GetDesktopWindow())
1898 WIN_ReleasePtr( wndPtr );
1899 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1903 WIN_ReleasePtr( wndPtr );
1904 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1909 UINT old_flags = wndPtr->flags;
1910 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1911 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1912 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1913 if (proc) wndPtr->winproc = proc;
1914 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1915 else wndPtr->flags &= ~WIN_ISUNICODE;
1916 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1918 WIN_ReleasePtr( wndPtr );
1921 /* update is_unicode flag on the server side */
1925 case GWLP_HINSTANCE:
1929 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1930 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1932 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1933 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1934 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1935 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1936 WIN_ReleasePtr( wndPtr );
1941 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1943 WARN("Invalid offset %d\n", offset );
1944 WIN_ReleasePtr( wndPtr );
1945 SetLastError( ERROR_INVALID_INDEX );
1948 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1950 /* already set to the same value */
1951 WIN_ReleasePtr( wndPtr );
1957 SERVER_START_REQ( set_window_info )
1960 req->extra_offset = -1;
1964 req->flags = SET_WIN_STYLE;
1965 req->style = newval;
1968 req->flags = SET_WIN_EXSTYLE;
1969 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1970 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
1971 req->ex_style = newval;
1974 req->flags = SET_WIN_ID;
1977 case GWLP_HINSTANCE:
1978 req->flags = SET_WIN_INSTANCE;
1979 req->instance = (void *)newval;
1982 req->flags = SET_WIN_UNICODE;
1983 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1986 req->flags = SET_WIN_USERDATA;
1987 req->user_data = newval;
1990 req->flags = SET_WIN_EXTRA;
1991 req->extra_offset = offset;
1992 req->extra_size = size;
1993 set_win_data( &req->extra_value, newval, size );
1995 if ((ok = !wine_server_call_err( req )))
2000 wndPtr->dwStyle = newval;
2001 retval = reply->old_style;
2004 wndPtr->dwExStyle = newval;
2005 retval = reply->old_ex_style;
2008 wndPtr->wIDmenu = newval;
2009 retval = reply->old_id;
2011 case GWLP_HINSTANCE:
2012 wndPtr->hInstance = (HINSTANCE)newval;
2013 retval = (ULONG_PTR)reply->old_instance;
2018 wndPtr->userdata = newval;
2019 retval = reply->old_user_data;
2022 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2023 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2029 WIN_ReleasePtr( wndPtr );
2033 if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2035 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2036 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2042 /**********************************************************************
2043 * GetWindowLong (USER.135)
2045 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2049 BOOL is_winproc = (offset == GWLP_WNDPROC);
2053 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2055 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2058 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2060 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2063 * Some programs try to access last element from 16 bit
2064 * code using illegal offset value. Hopefully this is
2065 * what those programs really expect.
2067 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2069 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2070 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2075 WARN("Invalid offset %d\n", offset );
2076 WIN_ReleasePtr( wndPtr );
2077 SetLastError( ERROR_INVALID_INDEX );
2081 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2082 WIN_ReleasePtr( wndPtr );
2085 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2086 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2091 /**********************************************************************
2092 * GetWindowWord (USER32.@)
2094 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2099 case GWLP_HINSTANCE:
2100 case GWLP_HWNDPARENT:
2105 WARN("Invalid offset %d\n", offset );
2106 SetLastError( ERROR_INVALID_INDEX );
2111 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2115 /**********************************************************************
2116 * GetWindowLongA (USER32.@)
2118 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2120 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2124 /**********************************************************************
2125 * GetWindowLongW (USER32.@)
2127 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2129 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2133 /**********************************************************************
2134 * SetWindowLong (USER.136)
2136 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2139 BOOL is_winproc = (offset == GWLP_WNDPROC);
2141 if (offset == DWLP_DLGPROC)
2143 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2145 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2148 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2150 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2151 (wndPtr->flags & WIN_ISDIALOG));
2152 WIN_ReleasePtr( wndPtr );
2158 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2159 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2160 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2162 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2166 /**********************************************************************
2167 * SetWindowWord (USER32.@)
2169 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2174 case GWLP_HINSTANCE:
2175 case GWLP_HWNDPARENT:
2180 WARN("Invalid offset %d\n", offset );
2181 SetLastError( ERROR_INVALID_INDEX );
2186 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2190 /**********************************************************************
2191 * SetWindowLongA (USER32.@)
2193 * See SetWindowLongW.
2195 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2197 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2201 /**********************************************************************
2202 * SetWindowLongW (USER32.@) Set window attribute
2204 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2205 * value in a window's extra memory.
2207 * The _hwnd_ parameter specifies the window. is the handle to a
2208 * window that has extra memory. The _newval_ parameter contains the
2209 * new attribute or extra memory value. If positive, the _offset_
2210 * parameter is the byte-addressed location in the window's extra
2211 * memory to set. If negative, _offset_ specifies the window
2212 * attribute to set, and should be one of the following values:
2214 * GWL_EXSTYLE The window's extended window style
2216 * GWL_STYLE The window's window style.
2218 * GWLP_WNDPROC Pointer to the window's window procedure.
2220 * GWLP_HINSTANCE The window's pplication instance handle.
2222 * GWLP_ID The window's identifier.
2224 * GWLP_USERDATA The window's user-specified data.
2226 * If the window is a dialog box, the _offset_ parameter can be one of
2227 * the following values:
2229 * DWLP_DLGPROC The address of the window's dialog box procedure.
2231 * DWLP_MSGRESULT The return value of a message
2232 * that the dialog box procedure processed.
2234 * DWLP_USER Application specific information.
2238 * If successful, returns the previous value located at _offset_. Otherwise,
2243 * Extra memory for a window class is specified by a nonzero cbWndExtra
2244 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2245 * time of class creation.
2247 * Using GWL_WNDPROC to set a new window procedure effectively creates
2248 * a window subclass. Use CallWindowProc() in the new windows procedure
2249 * to pass messages to the superclass's window procedure.
2251 * The user data is reserved for use by the application which created
2254 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2255 * instead, call the EnableWindow() function to change the window's
2258 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2259 * SetParent() instead.
2262 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2263 * it sends WM_STYLECHANGING before changing the settings
2264 * and WM_STYLECHANGED afterwards.
2265 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2267 LONG WINAPI SetWindowLongW(
2268 HWND hwnd, /* [in] window to alter */
2269 INT offset, /* [in] offset, in bytes, of location to alter */
2270 LONG newval /* [in] new value of location */
2272 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2276 /*******************************************************************
2277 * GetWindowTextA (USER32.@)
2279 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2283 if (!lpString) return 0;
2285 if (WIN_IsCurrentProcess( hwnd ))
2286 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2288 /* when window belongs to other process, don't send a message */
2289 if (nMaxCount <= 0) return 0;
2290 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2291 get_server_window_text( hwnd, buffer, nMaxCount );
2292 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2293 lpString[nMaxCount-1] = 0;
2294 HeapFree( GetProcessHeap(), 0, buffer );
2295 return strlen(lpString);
2299 /*******************************************************************
2300 * InternalGetWindowText (USER32.@)
2302 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2306 if (nMaxCount <= 0) return 0;
2307 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2308 if (win == WND_DESKTOP) lpString[0] = 0;
2309 else if (win != WND_OTHER_PROCESS)
2311 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2312 else lpString[0] = 0;
2313 WIN_ReleasePtr( win );
2317 get_server_window_text( hwnd, lpString, nMaxCount );
2319 return strlenW(lpString);
2323 /*******************************************************************
2324 * GetWindowTextW (USER32.@)
2326 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2328 if (!lpString) return 0;
2330 if (WIN_IsCurrentProcess( hwnd ))
2331 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2333 /* when window belongs to other process, don't send a message */
2334 if (nMaxCount <= 0) return 0;
2335 get_server_window_text( hwnd, lpString, nMaxCount );
2336 return strlenW(lpString);
2340 /*******************************************************************
2341 * SetWindowTextA (USER32.@)
2342 * SetWindowText (USER32.@)
2344 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2346 if (is_broadcast(hwnd))
2348 SetLastError( ERROR_INVALID_PARAMETER );
2351 if (!WIN_IsCurrentProcess( hwnd ))
2352 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2353 debugstr_a(lpString), hwnd );
2354 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2358 /*******************************************************************
2359 * SetWindowTextW (USER32.@)
2361 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2363 if (is_broadcast(hwnd))
2365 SetLastError( ERROR_INVALID_PARAMETER );
2368 if (!WIN_IsCurrentProcess( hwnd ))
2369 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2370 debugstr_w(lpString), hwnd );
2371 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2375 /*******************************************************************
2376 * GetWindowTextLengthA (USER32.@)
2378 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2380 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2383 /*******************************************************************
2384 * GetWindowTextLengthW (USER32.@)
2386 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2388 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2392 /*******************************************************************
2393 * IsWindow (USER32.@)
2395 BOOL WINAPI IsWindow( HWND hwnd )
2400 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2401 if (ptr == WND_DESKTOP) return TRUE;
2403 if (ptr != WND_OTHER_PROCESS)
2405 WIN_ReleasePtr( ptr );
2409 /* check other processes */
2410 SERVER_START_REQ( get_window_info )
2413 ret = !wine_server_call_err( req );
2420 /***********************************************************************
2421 * GetWindowThreadProcessId (USER32.@)
2423 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2428 if (!(ptr = WIN_GetPtr( hwnd )))
2430 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2434 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2436 /* got a valid window */
2438 if (process) *process = GetCurrentProcessId();
2439 WIN_ReleasePtr( ptr );
2443 /* check other processes */
2444 SERVER_START_REQ( get_window_info )
2447 if (!wine_server_call_err( req ))
2449 tid = (DWORD)reply->tid;
2450 if (process) *process = (DWORD)reply->pid;
2458 /*****************************************************************
2459 * GetParent (USER32.@)
2461 HWND WINAPI GetParent( HWND hwnd )
2466 if (!(wndPtr = WIN_GetPtr( hwnd )))
2468 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2471 if (wndPtr == WND_DESKTOP) return 0;
2472 if (wndPtr == WND_OTHER_PROCESS)
2474 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2475 if (style & (WS_POPUP | WS_CHILD))
2477 SERVER_START_REQ( get_window_tree )
2480 if (!wine_server_call_err( req ))
2482 if (style & WS_POPUP) retvalue = reply->owner;
2483 else if (style & WS_CHILD) retvalue = reply->parent;
2491 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2492 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2493 WIN_ReleasePtr( wndPtr );
2499 /*****************************************************************
2500 * GetAncestor (USER32.@)
2502 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2505 HWND *list, ret = 0;
2510 if (!(win = WIN_GetPtr( hwnd )))
2512 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2515 if (win == WND_DESKTOP) return 0;
2516 if (win != WND_OTHER_PROCESS)
2519 WIN_ReleasePtr( win );
2521 else /* need to query the server */
2523 SERVER_START_REQ( get_window_tree )
2526 if (!wine_server_call_err( req )) ret = reply->parent;
2533 if (!(list = list_window_parents( hwnd ))) return 0;
2535 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2539 while (list[count]) count++;
2540 ret = list[count - 2]; /* get the one before the desktop */
2542 HeapFree( GetProcessHeap(), 0, list );
2546 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2549 HWND parent = GetParent( ret );
2559 /*****************************************************************
2560 * SetParent (USER32.@)
2562 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2565 HWND old_parent = 0;
2570 if (is_broadcast(hwnd) || is_broadcast(parent))
2572 SetLastError(ERROR_INVALID_PARAMETER);
2576 if (!parent) parent = GetDesktopWindow();
2577 else parent = WIN_GetFullHandle( parent );
2579 if (!IsWindow( parent ))
2581 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2585 /* Some applications try to set a child as a parent */
2586 if (IsChild(hwnd, parent))
2588 SetLastError( ERROR_INVALID_PARAMETER );
2592 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2593 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2595 /* Windows hides the window first, then shows it again
2596 * including the WM_SHOWWINDOW messages and all */
2597 was_visible = ShowWindow( hwnd, SW_HIDE );
2599 wndPtr = WIN_GetPtr( hwnd );
2600 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2602 SERVER_START_REQ( set_parent )
2605 req->parent = parent;
2606 if ((ret = !wine_server_call( req )))
2608 old_parent = reply->old_parent;
2609 wndPtr->parent = parent = reply->full_parent;
2614 WIN_ReleasePtr( wndPtr );
2617 USER_Driver->pSetParent( full_handle, parent, old_parent );
2619 /* SetParent additionally needs to make hwnd the topmost window
2620 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2621 WM_WINDOWPOSCHANGED notification messages.
2623 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2624 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2625 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2626 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2632 /*******************************************************************
2633 * IsChild (USER32.@)
2635 BOOL WINAPI IsChild( HWND parent, HWND child )
2637 HWND *list = list_window_parents( child );
2641 if (!list) return FALSE;
2642 parent = WIN_GetFullHandle( parent );
2643 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2644 ret = list[i] && list[i+1];
2645 HeapFree( GetProcessHeap(), 0, list );
2650 /***********************************************************************
2651 * IsWindowVisible (USER32.@)
2653 BOOL WINAPI IsWindowVisible( HWND hwnd )
2659 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2660 if (!(list = list_window_parents( hwnd ))) return TRUE;
2661 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2663 for (i = 0; list[i+1]; i++)
2664 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2665 retval = !list[i+1];
2667 HeapFree( GetProcessHeap(), 0, list );
2672 /***********************************************************************
2673 * WIN_IsWindowDrawable
2675 * hwnd is drawable when it is visible, all parents are not
2676 * minimized, and it is itself not minimized unless we are
2677 * trying to draw its default class icon.
2679 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2684 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2686 if (!(style & WS_VISIBLE)) return FALSE;
2687 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2689 if (!(list = list_window_parents( hwnd ))) return TRUE;
2690 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2692 for (i = 0; list[i+1]; i++)
2693 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2695 retval = !list[i+1];
2697 HeapFree( GetProcessHeap(), 0, list );
2702 /*******************************************************************
2703 * GetTopWindow (USER32.@)
2705 HWND WINAPI GetTopWindow( HWND hwnd )
2707 if (!hwnd) hwnd = GetDesktopWindow();
2708 return GetWindow( hwnd, GW_CHILD );
2712 /*******************************************************************
2713 * GetWindow (USER32.@)
2715 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2719 if (rel == GW_OWNER) /* this one may be available locally */
2721 WND *wndPtr = WIN_GetPtr( hwnd );
2724 SetLastError( ERROR_INVALID_HANDLE );
2727 if (wndPtr == WND_DESKTOP) return 0;
2728 if (wndPtr != WND_OTHER_PROCESS)
2730 retval = wndPtr->owner;
2731 WIN_ReleasePtr( wndPtr );
2734 /* else fall through to server call */
2737 SERVER_START_REQ( get_window_tree )
2740 if (!wine_server_call_err( req ))
2745 retval = reply->first_sibling;
2748 retval = reply->last_sibling;
2751 retval = reply->next_sibling;
2754 retval = reply->prev_sibling;
2757 retval = reply->owner;
2760 retval = reply->first_child;
2770 /*******************************************************************
2771 * ShowOwnedPopups (USER32.@)
2773 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2777 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2779 if (!win_array) return TRUE;
2781 while (win_array[count]) count++;
2782 while (--count >= 0)
2784 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2785 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2786 if (pWnd == WND_OTHER_PROCESS) continue;
2789 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2791 WIN_ReleasePtr( pWnd );
2792 /* In Windows, ShowOwnedPopups(TRUE) generates
2793 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2794 * regardless of the state of the owner
2796 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2802 if (pWnd->dwStyle & WS_VISIBLE)
2804 WIN_ReleasePtr( pWnd );
2805 /* In Windows, ShowOwnedPopups(FALSE) generates
2806 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2807 * regardless of the state of the owner
2809 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2813 WIN_ReleasePtr( pWnd );
2815 HeapFree( GetProcessHeap(), 0, win_array );
2820 /*******************************************************************
2821 * GetLastActivePopup (USER32.@)
2823 HWND WINAPI GetLastActivePopup( HWND hwnd )
2827 SERVER_START_REQ( get_window_info )
2830 if (!wine_server_call_err( req )) retval = reply->last_active;
2837 /*******************************************************************
2840 * Build an array of the children of a given window. The array must be
2841 * freed with HeapFree. Returns NULL when no windows are found.
2843 HWND *WIN_ListChildren( HWND hwnd )
2845 return list_window_children( hwnd, NULL, 0 );
2849 /*******************************************************************
2850 * EnumWindows (USER32.@)
2852 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2858 USER_CheckNotLock();
2860 /* We have to build a list of all windows first, to avoid */
2861 /* unpleasant side-effects, for instance if the callback */
2862 /* function changes the Z-order of the windows. */
2864 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2866 /* Now call the callback function for every window */
2868 for (i = 0; list[i]; i++)
2870 /* Make sure that the window still exists */
2871 if (!IsWindow( list[i] )) continue;
2872 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2874 HeapFree( GetProcessHeap(), 0, list );
2879 /**********************************************************************
2880 * EnumThreadWindows (USER32.@)
2882 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2887 USER_CheckNotLock();
2889 if (!(list = list_window_children( GetDesktopWindow(), NULL, id ))) return TRUE;
2891 /* Now call the callback function for every window */
2893 for (i = 0; list[i]; i++)
2894 if (!func( list[i], lParam )) break;
2895 HeapFree( GetProcessHeap(), 0, list );
2900 /**********************************************************************
2901 * WIN_EnumChildWindows
2903 * Helper function for EnumChildWindows().
2905 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2910 for ( ; *list; list++)
2912 /* Make sure that the window still exists */
2913 if (!IsWindow( *list )) continue;
2914 /* Build children list first */
2915 childList = WIN_ListChildren( *list );
2917 ret = func( *list, lParam );
2921 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2922 HeapFree( GetProcessHeap(), 0, childList );
2924 if (!ret) return FALSE;
2930 /**********************************************************************
2931 * EnumChildWindows (USER32.@)
2933 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2938 USER_CheckNotLock();
2940 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2941 ret = WIN_EnumChildWindows( list, func, lParam );
2942 HeapFree( GetProcessHeap(), 0, list );
2947 /*******************************************************************
2948 * AnyPopup (USER.52)
2950 BOOL16 WINAPI AnyPopup16(void)
2956 /*******************************************************************
2957 * AnyPopup (USER32.@)
2959 BOOL WINAPI AnyPopup(void)
2963 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2965 if (!list) return FALSE;
2966 for (i = 0; list[i]; i++)
2968 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2970 retvalue = (list[i] != 0);
2971 HeapFree( GetProcessHeap(), 0, list );
2976 /*******************************************************************
2977 * FlashWindow (USER32.@)
2979 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2983 TRACE("%p\n", hWnd);
2985 if (IsIconic( hWnd ))
2987 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2989 wndPtr = WIN_GetPtr(hWnd);
2990 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2991 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2993 wndPtr->flags |= WIN_NCACTIVATED;
2997 wndPtr->flags &= ~WIN_NCACTIVATED;
2999 WIN_ReleasePtr( wndPtr );
3006 wndPtr = WIN_GetPtr(hWnd);
3007 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3008 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3010 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3011 else wparam = (hWnd == GetForegroundWindow());
3013 WIN_ReleasePtr( wndPtr );
3014 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3019 /*******************************************************************
3020 * FlashWindowEx (USER32.@)
3022 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3024 FIXME("%p\n", pfwi);
3028 /*******************************************************************
3029 * GetWindowContextHelpId (USER32.@)
3031 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3034 WND *wnd = WIN_GetPtr( hwnd );
3035 if (!wnd || wnd == WND_DESKTOP) return 0;
3036 if (wnd == WND_OTHER_PROCESS)
3038 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3041 retval = wnd->helpContext;
3042 WIN_ReleasePtr( wnd );
3047 /*******************************************************************
3048 * SetWindowContextHelpId (USER32.@)
3050 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3052 WND *wnd = WIN_GetPtr( hwnd );
3053 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3054 if (wnd == WND_OTHER_PROCESS)
3056 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3059 wnd->helpContext = id;
3060 WIN_ReleasePtr( wnd );
3065 /*******************************************************************
3066 * DragDetect (USER32.@)
3068 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3072 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3073 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3075 rect.left = pt.x - wDragWidth;
3076 rect.right = pt.x + wDragWidth;
3078 rect.top = pt.y - wDragHeight;
3079 rect.bottom = pt.y + wDragHeight;
3085 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3087 if( msg.message == WM_LBUTTONUP )
3092 if( msg.message == WM_MOUSEMOVE )
3095 tmp.x = (short)LOWORD(msg.lParam);
3096 tmp.y = (short)HIWORD(msg.lParam);
3097 if( !PtInRect( &rect, tmp ))
3109 /******************************************************************************
3110 * GetWindowModuleFileNameA (USER32.@)
3112 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3114 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3115 hwnd, lpszFileName, cchFileNameMax);
3119 /******************************************************************************
3120 * GetWindowModuleFileNameW (USER32.@)
3122 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3124 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3125 hwnd, lpszFileName, cchFileNameMax);
3129 /******************************************************************************
3130 * GetWindowInfo (USER32.@)
3132 * Note: tests show that Windows doesn't check cbSize of the structure.
3134 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3136 if (!pwi) return FALSE;
3137 if (!IsWindow(hwnd)) return FALSE;
3139 GetWindowRect(hwnd, &pwi->rcWindow);
3140 GetClientRect(hwnd, &pwi->rcClient);
3141 /* translate to screen coordinates */
3142 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3144 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3145 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3146 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3148 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3149 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3151 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3152 pwi->wCreatorVersion = 0x0400;
3157 /******************************************************************************
3158 * SwitchDesktop (USER32.@)
3160 * NOTES: Sets the current input or interactive desktop.
3162 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3164 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3168 /*****************************************************************************
3169 * SetLayeredWindowAttributes (USER32.@)
3171 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey,
3172 BYTE bAlpha, DWORD dwFlags )
3174 FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3178 /*****************************************************************************
3179 * GetLayeredWindowAttributes (USER32.@)
3181 BOOL WINAPI GetLayeredWindowAttributes( HWND hWnd, COLORREF *prgbKey,
3182 BYTE *pbAlpha, DWORD *pdwFlags )
3184 FIXME("(%p,%p,%p,%p): stub!\n", hWnd, prgbKey, pbAlpha, pdwFlags);
3188 /*****************************************************************************
3189 * UpdateLayeredWindow (USER32.@)
3191 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3192 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3199 FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3200 hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3205 /* 64bit versions */
3207 #ifdef GetWindowLongPtrW
3208 #undef GetWindowLongPtrW
3211 #ifdef GetWindowLongPtrA
3212 #undef GetWindowLongPtrA
3215 #ifdef SetWindowLongPtrW
3216 #undef SetWindowLongPtrW
3219 #ifdef SetWindowLongPtrA
3220 #undef SetWindowLongPtrA
3223 /*****************************************************************************
3224 * GetWindowLongPtrW (USER32.@)
3226 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3228 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3231 /*****************************************************************************
3232 * GetWindowLongPtrA (USER32.@)
3234 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3236 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3239 /*****************************************************************************
3240 * SetWindowLongPtrW (USER32.@)
3242 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3244 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3247 /*****************************************************************************
3248 * SetWindowLongPtrA (USER32.@)
3250 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3252 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );