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(), HEAP_ZERO_MEMORY,
137 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
139 SERVER_START_REQ( destroy_window )
141 req->handle = handle;
142 wine_server_call( req );
145 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
149 if (!parent) /* if parent is 0 we don't have a desktop window yet */
151 struct user_thread_info *thread_info = get_user_thread_info();
153 if (!thread_info->desktop) thread_info->desktop = full_parent ? full_parent : handle;
154 else assert( full_parent == thread_info->desktop );
155 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
156 ERR( "failed to create desktop window\n" );
161 index = USER_HANDLE_TO_INDEX(handle);
162 assert( index < NB_USER_HANDLES );
163 user_handles[index] = win;
164 win->hwndSelf = handle;
165 win->parent = full_parent;
166 win->owner = full_owner;
168 win->winproc = get_class_winproc( class );
169 win->dwMagic = WND_MAGIC;
170 win->cbWndExtra = extra_bytes;
171 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
176 /***********************************************************************
179 * Free a window handle.
181 static WND *free_window_handle( HWND hwnd )
184 WORD index = USER_HANDLE_TO_INDEX(hwnd);
186 if (index >= NB_USER_HANDLES) return NULL;
188 if ((ptr = user_handles[index]))
190 SERVER_START_REQ( destroy_window )
193 if (!wine_server_call_err( req ))
195 user_handles[index] = NULL;
204 HeapFree( GetProcessHeap(), 0, ptr );
209 /*******************************************************************
210 * list_window_children
212 * Build an array of the children of a given window. The array must be
213 * freed with HeapFree. Returns NULL when no windows are found.
215 static HWND *list_window_children( HWND hwnd, LPCWSTR class, DWORD tid )
224 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
226 SERVER_START_REQ( get_window_children )
230 if (!(req->atom = get_int_atom_value( class )) && class)
231 wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
232 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
233 if (!wine_server_call( req )) count = reply->count;
236 if (count && count < size)
241 HeapFree( GetProcessHeap(), 0, list );
243 size = count + 1; /* restart with a large enough buffer */
249 /*******************************************************************
250 * list_window_parents
252 * Build an array of all parents of a given window, starting with
253 * the immediate parent. The array must be freed with HeapFree.
255 static HWND *list_window_parents( HWND hwnd )
259 int pos = 0, size = 16, count = 0;
261 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
266 if (!(win = WIN_GetPtr( current ))) goto empty;
267 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
268 if (win == WND_DESKTOP)
270 if (!pos) goto empty;
274 list[pos] = current = win->parent;
275 WIN_ReleasePtr( win );
276 if (++pos == size - 1)
278 /* need to grow the list */
279 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
280 if (!new_list) goto empty;
286 /* at least one parent belongs to another process, have to query the server */
291 SERVER_START_REQ( get_window_parents )
294 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
295 if (!wine_server_call( req )) count = reply->count;
298 if (!count) goto empty;
304 HeapFree( GetProcessHeap(), 0, list );
306 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
310 HeapFree( GetProcessHeap(), 0, list );
315 /*******************************************************************
318 static void send_parent_notify( HWND hwnd, UINT msg )
320 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
321 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
323 HWND parent = GetParent(hwnd);
324 if (parent && parent != GetDesktopWindow())
325 SendMessageW( parent, WM_PARENTNOTIFY,
326 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
331 /*******************************************************************
332 * get_server_window_text
334 * Retrieve the window text from the server.
336 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
340 SERVER_START_REQ( get_window_text )
343 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
344 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
347 text[len / sizeof(WCHAR)] = 0;
351 /***********************************************************************
354 * Return a pointer to the WND structure if local to the process,
355 * or WND_OTHER_PROCESS if handle may be valid in other process.
356 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
358 WND *WIN_GetPtr( HWND hwnd )
361 WORD index = USER_HANDLE_TO_INDEX(hwnd);
363 if (index >= NB_USER_HANDLES) return NULL;
366 if ((ptr = user_handles[index]))
368 if (ptr->dwMagic == WND_MAGIC &&
369 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
373 else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
375 if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
378 else ptr = WND_OTHER_PROCESS;
384 /***********************************************************************
385 * WIN_IsCurrentProcess
387 * Check whether a given window belongs to the current process (and return the full handle).
389 HWND WIN_IsCurrentProcess( HWND hwnd )
394 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
396 WIN_ReleasePtr( ptr );
401 /***********************************************************************
402 * WIN_IsCurrentThread
404 * Check whether a given window belongs to the current thread (and return the full handle).
406 HWND WIN_IsCurrentThread( HWND hwnd )
411 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
412 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
413 WIN_ReleasePtr( ptr );
418 /***********************************************************************
421 * Convert a 16-bit window handle to a full 32-bit handle.
423 HWND WIN_Handle32( HWND16 hwnd16 )
426 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
428 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
429 /* do sign extension for -2 and -3 */
430 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
432 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
434 if (ptr == WND_DESKTOP) return GetDesktopWindow();
436 if (ptr != WND_OTHER_PROCESS)
438 hwnd = ptr->hwndSelf;
439 WIN_ReleasePtr( ptr );
441 else /* may belong to another process */
443 SERVER_START_REQ( get_window_info )
446 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
454 /***********************************************************************
457 * Change the owner of a window.
459 HWND WIN_SetOwner( HWND hwnd, HWND owner )
461 WND *win = WIN_GetPtr( hwnd );
464 if (!win || win == WND_DESKTOP) return 0;
465 if (win == WND_OTHER_PROCESS)
467 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
470 SERVER_START_REQ( set_window_owner )
474 if (!wine_server_call( req ))
476 win->owner = reply->full_owner;
477 ret = reply->prev_owner;
481 WIN_ReleasePtr( win );
486 /***********************************************************************
489 * Change the style of a window.
491 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
494 ULONG new_style, old_style = 0;
495 WND *win = WIN_GetPtr( hwnd );
497 if (!win || win == WND_DESKTOP) return 0;
498 if (win == WND_OTHER_PROCESS)
501 ERR( "cannot set style %x/%x on other process window %p\n",
502 set_bits, clear_bits, hwnd );
505 new_style = (win->dwStyle | set_bits) & ~clear_bits;
506 if (new_style == win->dwStyle)
508 WIN_ReleasePtr( win );
511 SERVER_START_REQ( set_window_info )
514 req->flags = SET_WIN_STYLE;
515 req->style = new_style;
516 req->extra_offset = -1;
517 if ((ok = !wine_server_call( req )))
519 old_style = reply->old_style;
520 win->dwStyle = new_style;
524 WIN_ReleasePtr( win );
525 if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
530 /***********************************************************************
533 * Get the window and client rectangles.
535 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
537 WND *win = WIN_GetPtr( hwnd );
540 if (!win) return FALSE;
541 if (win == WND_DESKTOP)
544 rect.left = rect.top = 0;
545 rect.right = GetSystemMetrics(SM_CXSCREEN);
546 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
547 if (rectWindow) *rectWindow = rect;
548 if (rectClient) *rectClient = rect;
550 else if (win == WND_OTHER_PROCESS)
552 SERVER_START_REQ( get_window_rectangles )
555 if ((ret = !wine_server_call( req )))
559 rectWindow->left = reply->window.left;
560 rectWindow->top = reply->window.top;
561 rectWindow->right = reply->window.right;
562 rectWindow->bottom = reply->window.bottom;
566 rectClient->left = reply->client.left;
567 rectClient->top = reply->client.top;
568 rectClient->right = reply->client.right;
569 rectClient->bottom = reply->client.bottom;
577 if (rectWindow) *rectWindow = win->rectWindow;
578 if (rectClient) *rectClient = win->rectClient;
579 WIN_ReleasePtr( win );
585 /***********************************************************************
588 * Destroy storage associated to a window. "Internals" p.358
590 LRESULT WIN_DestroyWindow( HWND hwnd )
594 HMENU menu = 0, sys_menu;
596 TRACE("%p\n", hwnd );
598 /* free child windows */
599 if ((list = WIN_ListChildren( hwnd )))
602 for (i = 0; list[i]; i++)
604 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
605 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
607 HeapFree( GetProcessHeap(), 0, list );
610 /* Unlink now so we won't bother with the children later on */
611 SERVER_START_REQ( set_parent )
615 wine_server_call( req );
620 * Send the WM_NCDESTROY to the window being destroyed.
622 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
624 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
626 WINPOS_CheckInternalPos( hwnd );
628 /* free resources associated with the window */
630 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
631 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
632 menu = (HMENU)wndPtr->wIDmenu;
633 sys_menu = wndPtr->hSysMenu;
634 WIN_ReleasePtr( wndPtr );
636 if (menu) DestroyMenu( menu );
637 if (sys_menu) DestroyMenu( sys_menu );
639 USER_Driver->pDestroyWindow( hwnd );
641 free_window_handle( hwnd );
645 /***********************************************************************
646 * WIN_DestroyThreadWindows
648 * Destroy all children of 'wnd' owned by the current thread.
650 void WIN_DestroyThreadWindows( HWND hwnd )
655 if (!(list = WIN_ListChildren( hwnd ))) return;
656 for (i = 0; list[i]; i++)
658 if (WIN_IsCurrentThread( list[i] ))
659 DestroyWindow( list[i] );
661 WIN_DestroyThreadWindows( list[i] );
663 HeapFree( GetProcessHeap(), 0, list );
667 /***********************************************************************
670 * Fix the coordinates - Helper for WIN_CreateWindowEx.
671 * returns default show mode in sw.
673 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
675 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
678 if (cs->dwExStyle & WS_EX_MDICHILD)
682 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
683 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
685 TRACE("MDI child id %04x\n", id);
688 if (cs->style & (WS_CHILD | WS_POPUP))
690 if (cs->dwExStyle & WS_EX_MDICHILD)
692 if (IS_DEFAULT(cs->x))
697 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
698 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
702 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
703 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
706 else /* overlapped window */
709 MONITORINFO mon_info;
712 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
714 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
715 mon_info.cbSize = sizeof(mon_info);
716 GetMonitorInfoW( monitor, &mon_info );
717 GetStartupInfoW( &info );
719 if (IS_DEFAULT(cs->x))
721 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
722 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
723 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
726 if (IS_DEFAULT(cs->cx))
728 if (info.dwFlags & STARTF_USESIZE)
730 cs->cx = info.dwXSize;
731 cs->cy = info.dwYSize;
735 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
736 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
739 /* neither x nor cx are default. Check the y values .
740 * In the trace we see Outlook and Outlook Express using
741 * cy set to CW_USEDEFAULT when opening the address book.
743 else if (IS_DEFAULT(cs->cy))
745 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
746 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
752 /***********************************************************************
755 static void dump_window_styles( DWORD style, DWORD exstyle )
758 if(style & WS_POPUP) TRACE(" WS_POPUP");
759 if(style & WS_CHILD) TRACE(" WS_CHILD");
760 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
761 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
762 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
763 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
764 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
765 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
766 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
769 if(style & WS_BORDER) TRACE(" WS_BORDER");
770 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
772 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
773 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
774 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
775 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
776 if (style & WS_CHILD)
778 if(style & WS_GROUP) TRACE(" WS_GROUP");
779 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
783 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
784 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
787 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
788 #define DUMPED_STYLES \
808 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
813 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
814 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
815 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
816 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
817 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
818 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
819 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
820 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
821 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
822 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
823 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
824 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
825 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
826 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
827 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
828 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
829 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
830 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
832 #define DUMPED_EX_STYLES \
833 (WS_EX_DLGMODALFRAME | \
835 WS_EX_NOPARENTNOTIFY | \
837 WS_EX_ACCEPTFILES | \
838 WS_EX_TRANSPARENT | \
843 WS_EX_CONTEXTHELP | \
846 WS_EX_LEFTSCROLLBAR | \
847 WS_EX_CONTROLPARENT | \
852 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
854 #undef DUMPED_EX_STYLES
858 /***********************************************************************
861 * Implementation of CreateWindowEx().
863 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
865 INT cx, cy, sw = SW_SHOW;
869 HWND hwnd, parent, owner, top_child = 0;
870 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
871 MDICREATESTRUCTA mdi_cs;
875 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
876 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
877 debugstr_w(className),
878 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
879 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
880 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
882 /* Fix the styles for MDI children */
883 if (cs->dwExStyle & WS_EX_MDICHILD)
887 wndPtr = WIN_GetPtr(cs->hwndParent);
888 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
890 flags = wndPtr->flags;
891 WIN_ReleasePtr(wndPtr);
894 if (!(flags & WIN_ISMDICLIENT))
896 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
900 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
901 * MDICREATESTRUCT members have the originally passed values.
903 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
904 * have the same layout.
906 mdi_cs.szClass = cs->lpszClass;
907 mdi_cs.szTitle = cs->lpszName;
908 mdi_cs.hOwner = cs->hInstance;
913 mdi_cs.style = cs->style;
914 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
916 cs->lpCreateParams = (LPVOID)&mdi_cs;
918 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
920 if (cs->style & WS_POPUP)
922 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
925 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
929 cs->style &= ~WS_POPUP;
930 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
931 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
934 top_child = GetWindow(cs->hwndParent, GW_CHILD);
938 /* Restore current maximized child */
939 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
941 TRACE("Restoring current maximized child %p\n", top_child);
942 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
943 ShowWindow( top_child, SW_SHOWNORMAL );
944 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
949 /* Find the parent window */
951 parent = cs->hwndParent;
954 if (cs->hwndParent == HWND_MESSAGE)
956 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
957 * message window (style: WS_POPUP|WS_DISABLED)
959 FIXME("Parent is HWND_MESSAGE\n");
960 parent = GetDesktopWindow();
962 else if (cs->hwndParent)
964 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
966 parent = GetDesktopWindow();
967 owner = cs->hwndParent;
972 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
974 WARN("No parent for child window\n" );
975 SetLastError(ERROR_TLW_WITH_WSCHILD);
976 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
978 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM) /* are we creating the desktop itself? */
979 parent = GetDesktopWindow();
982 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
984 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
985 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
986 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
987 cs->dwExStyle |= WS_EX_WINDOWEDGE;
989 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
991 /* Create the window structure */
993 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
995 hwnd = wndPtr->hwndSelf;
997 /* Fill the window structure */
999 wndPtr->tid = GetCurrentThreadId();
1000 wndPtr->hInstance = cs->hInstance;
1001 wndPtr->text = NULL;
1002 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1003 wndPtr->dwExStyle = cs->dwExStyle;
1004 wndPtr->wIDmenu = 0;
1005 wndPtr->helpContext = 0;
1006 wndPtr->pVScroll = NULL;
1007 wndPtr->pHScroll = NULL;
1008 wndPtr->userdata = 0;
1010 wndPtr->hIconSmall = 0;
1011 wndPtr->hSysMenu = 0;
1012 wndPtr->flags |= (flags & WIN_ISWIN32);
1014 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1017 * Correct the window styles.
1019 * It affects only the style loaded into the WIN structure.
1022 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1024 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1025 if (!(wndPtr->dwStyle & WS_POPUP))
1026 wndPtr->dwStyle |= WS_CAPTION;
1030 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1031 * why does the user get to set it?
1034 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1035 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1036 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1038 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1040 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1041 wndPtr->flags |= WIN_NEED_SIZE;
1043 SERVER_START_REQ( set_window_info )
1046 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1047 req->style = wndPtr->dwStyle;
1048 req->ex_style = wndPtr->dwExStyle;
1049 req->instance = (void *)wndPtr->hInstance;
1050 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1051 req->extra_offset = -1;
1052 wine_server_call( req );
1056 /* Set the window menu */
1058 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1062 if (!MENU_SetMenu(hwnd, cs->hMenu))
1064 WIN_ReleasePtr( wndPtr );
1065 free_window_handle( hwnd );
1071 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1074 if (!cs->hInstance || HIWORD(cs->hInstance))
1075 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1077 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1079 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1083 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1085 /* call the WH_CBT hook */
1087 /* the window style passed to the hook must be the real window style,
1088 * rather than just the window style that the caller to CreateWindowEx
1089 * passed in, so we have to copy the original CREATESTRUCT and get the
1090 * the real style. */
1092 cbcs.style = wndPtr->dwStyle;
1094 cbtc.hwndInsertAfter = HWND_TOP;
1095 WIN_ReleasePtr( wndPtr );
1096 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1098 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1102 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1104 POINT maxSize, maxPos, minTrack, maxTrack;
1105 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1106 if (maxTrack.x < cx) cx = maxTrack.x;
1107 if (maxTrack.y < cy) cy = maxTrack.y;
1112 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1113 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1115 /* send WM_NCCREATE */
1117 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1119 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1121 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1124 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1128 /* send WM_NCCALCSIZE */
1130 if ((wndPtr = WIN_GetPtr(hwnd)))
1132 /* yes, even if the CBT hook was called with HWND_TOP */
1133 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1134 RECT window_rect = wndPtr->rectWindow;
1135 RECT client_rect = window_rect;
1136 WIN_ReleasePtr( wndPtr );
1137 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1138 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1142 /* send WM_CREATE */
1145 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1147 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1148 if (result == -1) goto failed;
1150 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1152 /* send the size messages */
1154 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1155 if (!(wndPtr->flags & WIN_NEED_SIZE))
1157 rect = wndPtr->rectClient;
1158 WIN_ReleasePtr( wndPtr );
1159 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1160 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1161 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1163 else WIN_ReleasePtr( wndPtr );
1165 /* call the driver */
1167 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1169 /* Notify the parent window only */
1171 send_parent_notify( hwnd, WM_CREATE );
1172 if (!IsWindow( hwnd )) return 0;
1174 if (cs->style & WS_VISIBLE)
1176 if (cs->style & WS_MAXIMIZE)
1178 else if (cs->style & WS_MINIMIZE)
1179 sw = SW_SHOWMINIMIZED;
1181 ShowWindow( hwnd, sw );
1182 if (cs->dwExStyle & WS_EX_MDICHILD)
1184 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1185 /* ShowWindow won't activate child windows */
1186 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1190 /* Call WH_SHELL hook */
1192 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1193 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1195 TRACE("created window %p\n", hwnd);
1199 WIN_DestroyWindow( hwnd );
1204 /***********************************************************************
1205 * CreateWindow (USER.41)
1207 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1208 DWORD style, INT16 x, INT16 y, INT16 width,
1209 INT16 height, HWND16 parent, HMENU16 menu,
1210 HINSTANCE16 instance, LPVOID data )
1212 return CreateWindowEx16( 0, className, windowName, style,
1213 x, y, width, height, parent, menu, instance, data );
1217 /***********************************************************************
1218 * CreateWindowEx (USER.452)
1220 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1221 LPCSTR windowName, DWORD style, INT16 x,
1222 INT16 y, INT16 width, INT16 height,
1223 HWND16 parent, HMENU16 menu,
1224 HINSTANCE16 instance, LPVOID data )
1229 /* Fix the coordinates */
1231 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1232 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1233 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1234 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1236 /* Create the window */
1238 cs.lpCreateParams = data;
1239 cs.hInstance = HINSTANCE_32(instance);
1240 cs.hMenu = HMENU_32(menu);
1241 cs.hwndParent = WIN_Handle32( parent );
1243 cs.lpszName = windowName;
1244 cs.lpszClass = className;
1245 cs.dwExStyle = exStyle;
1247 if (!IS_INTRESOURCE(className))
1251 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1253 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1257 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1259 ERR( "bad atom %x\n", LOWORD(className));
1262 cs.lpszClass = buffer;
1263 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1268 /***********************************************************************
1269 * CreateWindowExA (USER32.@)
1271 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1272 LPCSTR windowName, DWORD style, INT x,
1273 INT y, INT width, INT height,
1274 HWND parent, HMENU menu,
1275 HINSTANCE instance, LPVOID data )
1279 cs.lpCreateParams = data;
1280 cs.hInstance = instance;
1282 cs.hwndParent = parent;
1288 cs.lpszName = windowName;
1289 cs.lpszClass = className;
1290 cs.dwExStyle = exStyle;
1292 if (!IS_INTRESOURCE(className))
1295 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1297 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1299 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1303 /***********************************************************************
1304 * CreateWindowExW (USER32.@)
1306 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1307 LPCWSTR windowName, DWORD style, INT x,
1308 INT y, INT width, INT height,
1309 HWND parent, HMENU menu,
1310 HINSTANCE instance, LPVOID data )
1314 cs.lpCreateParams = data;
1315 cs.hInstance = instance;
1317 cs.hwndParent = parent;
1323 cs.lpszName = windowName;
1324 cs.lpszClass = className;
1325 cs.dwExStyle = exStyle;
1327 /* Note: we rely on the fact that CREATESTRUCTA and */
1328 /* CREATESTRUCTW have the same layout. */
1329 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1333 /***********************************************************************
1334 * WIN_SendDestroyMsg
1336 static void WIN_SendDestroyMsg( HWND hwnd )
1340 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1342 if (hwnd == info.hwndCaret) DestroyCaret();
1343 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1347 * Send the WM_DESTROY to the window.
1349 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1352 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1353 * make sure that the window still exists when we come back.
1360 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1362 for (i = 0; pWndArray[i]; i++)
1364 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1366 HeapFree( GetProcessHeap(), 0, pWndArray );
1369 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1373 /***********************************************************************
1374 * DestroyWindow (USER32.@)
1376 BOOL WINAPI DestroyWindow( HWND hwnd )
1380 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1382 SetLastError( ERROR_ACCESS_DENIED );
1386 TRACE("(%p)\n", hwnd);
1390 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1392 if (MENU_IsMenuActive() == hwnd)
1395 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1399 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1400 send_parent_notify( hwnd, WM_DESTROY );
1402 else if (!GetWindow( hwnd, GW_OWNER ))
1404 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1405 /* FIXME: clean up palette - see "Internals" p.352 */
1408 if (!IsWindow(hwnd)) return TRUE;
1410 /* Hide the window */
1411 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1413 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1415 ShowWindow( hwnd, SW_HIDE );
1417 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1418 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1421 if (!IsWindow(hwnd)) return TRUE;
1423 /* Recursively destroy owned windows */
1430 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1433 for (i = 0; list[i]; i++)
1435 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1436 if (WIN_IsCurrentThread( list[i] ))
1438 DestroyWindow( list[i] );
1442 WIN_SetOwner( list[i], 0 );
1444 HeapFree( GetProcessHeap(), 0, list );
1446 if (!got_one) break;
1450 /* Send destroy messages */
1452 WIN_SendDestroyMsg( hwnd );
1453 if (!IsWindow( hwnd )) return TRUE;
1455 if (GetClipboardOwner() == hwnd)
1456 CLIPBOARD_ReleaseOwner();
1458 /* Destroy the window storage */
1460 WIN_DestroyWindow( hwnd );
1465 /***********************************************************************
1466 * CloseWindow (USER32.@)
1468 BOOL WINAPI CloseWindow( HWND hwnd )
1470 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1471 ShowWindow( hwnd, SW_MINIMIZE );
1476 /***********************************************************************
1477 * OpenIcon (USER32.@)
1479 BOOL WINAPI OpenIcon( HWND hwnd )
1481 if (!IsIconic( hwnd )) return FALSE;
1482 ShowWindow( hwnd, SW_SHOWNORMAL );
1487 /***********************************************************************
1488 * FindWindowExW (USER32.@)
1490 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1495 WCHAR *buffer = NULL;
1497 if (!parent) parent = GetDesktopWindow();
1500 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1501 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1504 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1508 child = WIN_GetFullHandle( child );
1509 while (list[i] && list[i] != child) i++;
1510 if (!list[i]) goto done;
1511 i++; /* start from next window */
1518 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1525 HeapFree( GetProcessHeap(), 0, list );
1526 HeapFree( GetProcessHeap(), 0, buffer );
1532 /***********************************************************************
1533 * FindWindowA (USER32.@)
1535 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1537 HWND ret = FindWindowExA( 0, 0, className, title );
1538 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1543 /***********************************************************************
1544 * FindWindowExA (USER32.@)
1546 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1548 LPWSTR titleW = NULL;
1553 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1554 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1555 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1558 if (!IS_INTRESOURCE(className))
1561 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1562 hwnd = FindWindowExW( parent, child, classW, titleW );
1566 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1569 HeapFree( GetProcessHeap(), 0, titleW );
1574 /***********************************************************************
1575 * FindWindowW (USER32.@)
1577 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1579 return FindWindowExW( 0, 0, className, title );
1583 /**********************************************************************
1584 * GetDesktopWindow (USER32.@)
1586 HWND WINAPI GetDesktopWindow(void)
1588 struct user_thread_info *thread_info = get_user_thread_info();
1590 if (thread_info->desktop) return thread_info->desktop;
1592 SERVER_START_REQ( get_desktop_window )
1595 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1599 if (!thread_info->desktop)
1601 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1603 PROCESS_INFORMATION pi;
1604 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1606 memset( &si, 0, sizeof(si) );
1608 si.dwFlags = STARTF_USESTDHANDLES;
1611 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1613 GetSystemDirectoryW( cmdline, MAX_PATH );
1614 lstrcatW( cmdline, command_line );
1615 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1616 NULL, NULL, &si, &pi ))
1618 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1619 WaitForInputIdle( pi.hProcess, 10000 );
1620 CloseHandle( pi.hThread );
1621 CloseHandle( pi.hProcess );
1624 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1626 SERVER_START_REQ( get_desktop_window )
1629 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1634 if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1635 ERR( "failed to create desktop window\n" );
1637 return thread_info->desktop;
1641 /*******************************************************************
1642 * EnableWindow (USER32.@)
1644 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1649 if (is_broadcast(hwnd))
1651 SetLastError( ERROR_INVALID_PARAMETER );
1655 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1656 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1660 TRACE("( %p, %d )\n", hwnd, enable);
1662 retvalue = !IsWindowEnabled( hwnd );
1664 if (enable && retvalue)
1666 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1667 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1669 else if (!enable && !retvalue)
1673 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1675 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1677 if (hwnd == GetFocus())
1678 SetFocus( 0 ); /* A disabled window can't have the focus */
1680 capture_wnd = GetCapture();
1681 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1682 ReleaseCapture(); /* A disabled window can't capture the mouse */
1684 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1690 /***********************************************************************
1691 * IsWindowEnabled (USER32.@)
1693 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1695 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1699 /***********************************************************************
1700 * IsWindowUnicode (USER32.@)
1702 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1705 BOOL retvalue = FALSE;
1707 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1709 if (wndPtr == WND_DESKTOP) return TRUE;
1711 if (wndPtr != WND_OTHER_PROCESS)
1713 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1714 WIN_ReleasePtr( wndPtr );
1718 SERVER_START_REQ( get_window_info )
1721 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1729 /**********************************************************************
1732 * Helper function for GetWindowLong().
1734 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1736 LONG_PTR retvalue = 0;
1739 if (offset == GWLP_HWNDPARENT)
1741 HWND parent = GetAncestor( hwnd, GA_PARENT );
1742 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1743 return (ULONG_PTR)parent;
1746 if (!(wndPtr = WIN_GetPtr( hwnd )))
1748 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1752 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1754 if (offset == GWLP_WNDPROC)
1756 SetLastError( ERROR_ACCESS_DENIED );
1759 SERVER_START_REQ( set_window_info )
1762 req->flags = 0; /* don't set anything, just retrieve */
1763 req->extra_offset = (offset >= 0) ? offset : -1;
1764 req->extra_size = (offset >= 0) ? size : 0;
1765 if (!wine_server_call_err( req ))
1769 case GWL_STYLE: retvalue = reply->old_style; break;
1770 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1771 case GWLP_ID: retvalue = reply->old_id; break;
1772 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1773 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1775 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1776 else SetLastError( ERROR_INVALID_INDEX );
1785 /* now we have a valid wndPtr */
1789 if (offset > (int)(wndPtr->cbWndExtra - size))
1791 WARN("Invalid offset %d\n", offset );
1792 WIN_ReleasePtr( wndPtr );
1793 SetLastError( ERROR_INVALID_INDEX );
1796 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1798 /* Special case for dialog window procedure */
1799 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1800 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1801 WIN_ReleasePtr( wndPtr );
1807 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1808 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1809 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1810 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1811 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1813 /* This looks like a hack only for the edit control (see tests). This makes these controls
1814 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1815 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1817 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1818 retvalue = (ULONG_PTR)wndPtr->winproc;
1820 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1823 WARN("Unknown offset %d\n", offset );
1824 SetLastError( ERROR_INVALID_INDEX );
1827 WIN_ReleasePtr(wndPtr);
1832 /**********************************************************************
1835 * Helper function for SetWindowLong().
1837 * 0 is the failure code. However, in the case of failure SetLastError
1838 * must be set to distinguish between a 0 return value and a failure.
1840 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1844 LONG_PTR retval = 0;
1847 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1849 if (is_broadcast(hwnd))
1851 SetLastError( ERROR_INVALID_PARAMETER );
1855 if (!(wndPtr = WIN_GetPtr( hwnd )))
1857 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1860 if (wndPtr == WND_DESKTOP)
1862 /* can't change anything on the desktop window */
1863 SetLastError( ERROR_ACCESS_DENIED );
1866 if (wndPtr == WND_OTHER_PROCESS)
1868 if (offset == GWLP_WNDPROC)
1870 SetLastError( ERROR_ACCESS_DENIED );
1873 if (offset > 32767 || offset < -32767)
1875 SetLastError( ERROR_INVALID_INDEX );
1878 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1881 /* first some special cases */
1887 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1888 style.styleNew = newval;
1889 WIN_ReleasePtr( wndPtr );
1890 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1891 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1892 newval = style.styleNew;
1894 case GWLP_HWNDPARENT:
1895 if (wndPtr->parent == GetDesktopWindow())
1897 WIN_ReleasePtr( wndPtr );
1898 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1902 WIN_ReleasePtr( wndPtr );
1903 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1908 UINT old_flags = wndPtr->flags;
1909 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1910 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1911 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1912 if (proc) wndPtr->winproc = proc;
1913 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1914 else wndPtr->flags &= ~WIN_ISUNICODE;
1915 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1917 WIN_ReleasePtr( wndPtr );
1920 /* update is_unicode flag on the server side */
1924 case GWLP_HINSTANCE:
1928 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1929 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1931 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1932 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1933 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1934 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1935 WIN_ReleasePtr( wndPtr );
1940 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1942 WARN("Invalid offset %d\n", offset );
1943 WIN_ReleasePtr( wndPtr );
1944 SetLastError( ERROR_INVALID_INDEX );
1947 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1949 /* already set to the same value */
1950 WIN_ReleasePtr( wndPtr );
1956 SERVER_START_REQ( set_window_info )
1959 req->extra_offset = -1;
1963 req->flags = SET_WIN_STYLE;
1964 req->style = newval;
1967 req->flags = SET_WIN_EXSTYLE;
1968 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1969 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
1970 req->ex_style = newval;
1973 req->flags = SET_WIN_ID;
1976 case GWLP_HINSTANCE:
1977 req->flags = SET_WIN_INSTANCE;
1978 req->instance = (void *)newval;
1981 req->flags = SET_WIN_UNICODE;
1982 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1985 req->flags = SET_WIN_USERDATA;
1986 req->user_data = newval;
1989 req->flags = SET_WIN_EXTRA;
1990 req->extra_offset = offset;
1991 req->extra_size = size;
1992 set_win_data( &req->extra_value, newval, size );
1994 if ((ok = !wine_server_call_err( req )))
1999 wndPtr->dwStyle = newval;
2000 retval = reply->old_style;
2003 wndPtr->dwExStyle = newval;
2004 retval = reply->old_ex_style;
2007 wndPtr->wIDmenu = newval;
2008 retval = reply->old_id;
2010 case GWLP_HINSTANCE:
2011 wndPtr->hInstance = (HINSTANCE)newval;
2012 retval = (ULONG_PTR)reply->old_instance;
2017 wndPtr->userdata = newval;
2018 retval = reply->old_user_data;
2021 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2022 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2028 WIN_ReleasePtr( wndPtr );
2032 if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2034 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2035 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2041 /**********************************************************************
2042 * GetWindowLong (USER.135)
2044 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2048 BOOL is_winproc = (offset == GWLP_WNDPROC);
2052 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2054 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2057 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2059 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2062 * Some programs try to access last element from 16 bit
2063 * code using illegal offset value. Hopefully this is
2064 * what those programs really expect.
2066 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2068 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2069 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2074 WARN("Invalid offset %d\n", offset );
2075 WIN_ReleasePtr( wndPtr );
2076 SetLastError( ERROR_INVALID_INDEX );
2080 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2081 WIN_ReleasePtr( wndPtr );
2084 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2085 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2090 /**********************************************************************
2091 * GetWindowWord (USER32.@)
2093 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2098 case GWLP_HINSTANCE:
2099 case GWLP_HWNDPARENT:
2104 WARN("Invalid offset %d\n", offset );
2105 SetLastError( ERROR_INVALID_INDEX );
2110 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2114 /**********************************************************************
2115 * GetWindowLongA (USER32.@)
2117 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2119 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2123 /**********************************************************************
2124 * GetWindowLongW (USER32.@)
2126 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2128 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2132 /**********************************************************************
2133 * SetWindowLong (USER.136)
2135 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2138 BOOL is_winproc = (offset == GWLP_WNDPROC);
2140 if (offset == DWLP_DLGPROC)
2142 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2144 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2147 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2149 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2150 (wndPtr->flags & WIN_ISDIALOG));
2151 WIN_ReleasePtr( wndPtr );
2157 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2158 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2159 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2161 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2165 /**********************************************************************
2166 * SetWindowWord (USER32.@)
2168 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2173 case GWLP_HINSTANCE:
2174 case GWLP_HWNDPARENT:
2179 WARN("Invalid offset %d\n", offset );
2180 SetLastError( ERROR_INVALID_INDEX );
2185 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2189 /**********************************************************************
2190 * SetWindowLongA (USER32.@)
2192 * See SetWindowLongW.
2194 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2196 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2200 /**********************************************************************
2201 * SetWindowLongW (USER32.@) Set window attribute
2203 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2204 * value in a window's extra memory.
2206 * The _hwnd_ parameter specifies the window. is the handle to a
2207 * window that has extra memory. The _newval_ parameter contains the
2208 * new attribute or extra memory value. If positive, the _offset_
2209 * parameter is the byte-addressed location in the window's extra
2210 * memory to set. If negative, _offset_ specifies the window
2211 * attribute to set, and should be one of the following values:
2213 * GWL_EXSTYLE The window's extended window style
2215 * GWL_STYLE The window's window style.
2217 * GWLP_WNDPROC Pointer to the window's window procedure.
2219 * GWLP_HINSTANCE The window's pplication instance handle.
2221 * GWLP_ID The window's identifier.
2223 * GWLP_USERDATA The window's user-specified data.
2225 * If the window is a dialog box, the _offset_ parameter can be one of
2226 * the following values:
2228 * DWLP_DLGPROC The address of the window's dialog box procedure.
2230 * DWLP_MSGRESULT The return value of a message
2231 * that the dialog box procedure processed.
2233 * DWLP_USER Application specific information.
2237 * If successful, returns the previous value located at _offset_. Otherwise,
2242 * Extra memory for a window class is specified by a nonzero cbWndExtra
2243 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2244 * time of class creation.
2246 * Using GWL_WNDPROC to set a new window procedure effectively creates
2247 * a window subclass. Use CallWindowProc() in the new windows procedure
2248 * to pass messages to the superclass's window procedure.
2250 * The user data is reserved for use by the application which created
2253 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2254 * instead, call the EnableWindow() function to change the window's
2257 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2258 * SetParent() instead.
2261 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2262 * it sends WM_STYLECHANGING before changing the settings
2263 * and WM_STYLECHANGED afterwards.
2264 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2266 LONG WINAPI SetWindowLongW(
2267 HWND hwnd, /* [in] window to alter */
2268 INT offset, /* [in] offset, in bytes, of location to alter */
2269 LONG newval /* [in] new value of location */
2271 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2275 /*******************************************************************
2276 * GetWindowTextA (USER32.@)
2278 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2282 if (!lpString) return 0;
2284 if (WIN_IsCurrentProcess( hwnd ))
2285 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2287 /* when window belongs to other process, don't send a message */
2288 if (nMaxCount <= 0) return 0;
2289 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2290 get_server_window_text( hwnd, buffer, nMaxCount );
2291 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2292 lpString[nMaxCount-1] = 0;
2293 HeapFree( GetProcessHeap(), 0, buffer );
2294 return strlen(lpString);
2298 /*******************************************************************
2299 * InternalGetWindowText (USER32.@)
2301 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2305 if (nMaxCount <= 0) return 0;
2306 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2307 if (win == WND_DESKTOP) lpString[0] = 0;
2308 else if (win != WND_OTHER_PROCESS)
2310 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2311 else lpString[0] = 0;
2312 WIN_ReleasePtr( win );
2316 get_server_window_text( hwnd, lpString, nMaxCount );
2318 return strlenW(lpString);
2322 /*******************************************************************
2323 * GetWindowTextW (USER32.@)
2325 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2327 if (!lpString) return 0;
2329 if (WIN_IsCurrentProcess( hwnd ))
2330 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2332 /* when window belongs to other process, don't send a message */
2333 if (nMaxCount <= 0) return 0;
2334 get_server_window_text( hwnd, lpString, nMaxCount );
2335 return strlenW(lpString);
2339 /*******************************************************************
2340 * SetWindowTextA (USER32.@)
2341 * SetWindowText (USER32.@)
2343 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2345 if (is_broadcast(hwnd))
2347 SetLastError( ERROR_INVALID_PARAMETER );
2350 if (!WIN_IsCurrentProcess( hwnd ))
2351 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2352 debugstr_a(lpString), hwnd );
2353 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2357 /*******************************************************************
2358 * SetWindowTextW (USER32.@)
2360 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2362 if (is_broadcast(hwnd))
2364 SetLastError( ERROR_INVALID_PARAMETER );
2367 if (!WIN_IsCurrentProcess( hwnd ))
2368 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2369 debugstr_w(lpString), hwnd );
2370 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2374 /*******************************************************************
2375 * GetWindowTextLengthA (USER32.@)
2377 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2379 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2382 /*******************************************************************
2383 * GetWindowTextLengthW (USER32.@)
2385 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2387 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2391 /*******************************************************************
2392 * IsWindow (USER32.@)
2394 BOOL WINAPI IsWindow( HWND hwnd )
2399 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2400 if (ptr == WND_DESKTOP) return TRUE;
2402 if (ptr != WND_OTHER_PROCESS)
2404 WIN_ReleasePtr( ptr );
2408 /* check other processes */
2409 SERVER_START_REQ( get_window_info )
2412 ret = !wine_server_call_err( req );
2419 /***********************************************************************
2420 * GetWindowThreadProcessId (USER32.@)
2422 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2427 if (!(ptr = WIN_GetPtr( hwnd )))
2429 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2433 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2435 /* got a valid window */
2437 if (process) *process = GetCurrentProcessId();
2438 WIN_ReleasePtr( ptr );
2442 /* check other processes */
2443 SERVER_START_REQ( get_window_info )
2446 if (!wine_server_call_err( req ))
2448 tid = (DWORD)reply->tid;
2449 if (process) *process = (DWORD)reply->pid;
2457 /*****************************************************************
2458 * GetParent (USER32.@)
2460 HWND WINAPI GetParent( HWND hwnd )
2465 if (!(wndPtr = WIN_GetPtr( hwnd )))
2467 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2470 if (wndPtr == WND_DESKTOP) return 0;
2471 if (wndPtr == WND_OTHER_PROCESS)
2473 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2474 if (style & (WS_POPUP | WS_CHILD))
2476 SERVER_START_REQ( get_window_tree )
2479 if (!wine_server_call_err( req ))
2481 if (style & WS_POPUP) retvalue = reply->owner;
2482 else if (style & WS_CHILD) retvalue = reply->parent;
2490 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2491 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2492 WIN_ReleasePtr( wndPtr );
2498 /*****************************************************************
2499 * GetAncestor (USER32.@)
2501 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2504 HWND *list, ret = 0;
2509 if (!(win = WIN_GetPtr( hwnd )))
2511 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2514 if (win == WND_DESKTOP) return 0;
2515 if (win != WND_OTHER_PROCESS)
2518 WIN_ReleasePtr( win );
2520 else /* need to query the server */
2522 SERVER_START_REQ( get_window_tree )
2525 if (!wine_server_call_err( req )) ret = reply->parent;
2532 if (!(list = list_window_parents( hwnd ))) return 0;
2534 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2538 while (list[count]) count++;
2539 ret = list[count - 2]; /* get the one before the desktop */
2541 HeapFree( GetProcessHeap(), 0, list );
2545 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2548 HWND parent = GetParent( ret );
2558 /*****************************************************************
2559 * SetParent (USER32.@)
2561 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2564 HWND old_parent = 0;
2569 if (is_broadcast(hwnd) || is_broadcast(parent))
2571 SetLastError(ERROR_INVALID_PARAMETER);
2575 if (!parent) parent = GetDesktopWindow();
2576 else parent = WIN_GetFullHandle( parent );
2578 if (!IsWindow( parent ))
2580 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2584 /* Some applications try to set a child as a parent */
2585 if (IsChild(hwnd, parent))
2587 SetLastError( ERROR_INVALID_PARAMETER );
2591 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2592 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2594 /* Windows hides the window first, then shows it again
2595 * including the WM_SHOWWINDOW messages and all */
2596 was_visible = ShowWindow( hwnd, SW_HIDE );
2598 wndPtr = WIN_GetPtr( hwnd );
2599 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2601 SERVER_START_REQ( set_parent )
2604 req->parent = parent;
2605 if ((ret = !wine_server_call( req )))
2607 old_parent = reply->old_parent;
2608 wndPtr->parent = parent = reply->full_parent;
2613 WIN_ReleasePtr( wndPtr );
2616 USER_Driver->pSetParent( full_handle, parent, old_parent );
2618 /* SetParent additionally needs to make hwnd the topmost window
2619 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2620 WM_WINDOWPOSCHANGED notification messages.
2622 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2623 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2624 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2625 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2631 /*******************************************************************
2632 * IsChild (USER32.@)
2634 BOOL WINAPI IsChild( HWND parent, HWND child )
2636 HWND *list = list_window_parents( child );
2640 if (!list) return FALSE;
2641 parent = WIN_GetFullHandle( parent );
2642 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2643 ret = list[i] && list[i+1];
2644 HeapFree( GetProcessHeap(), 0, list );
2649 /***********************************************************************
2650 * IsWindowVisible (USER32.@)
2652 BOOL WINAPI IsWindowVisible( HWND hwnd )
2658 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2659 if (!(list = list_window_parents( hwnd ))) return TRUE;
2660 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2662 for (i = 0; list[i+1]; i++)
2663 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2664 retval = !list[i+1];
2666 HeapFree( GetProcessHeap(), 0, list );
2671 /***********************************************************************
2672 * WIN_IsWindowDrawable
2674 * hwnd is drawable when it is visible, all parents are not
2675 * minimized, and it is itself not minimized unless we are
2676 * trying to draw its default class icon.
2678 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2683 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2685 if (!(style & WS_VISIBLE)) return FALSE;
2686 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2688 if (!(list = list_window_parents( hwnd ))) return TRUE;
2689 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2691 for (i = 0; list[i+1]; i++)
2692 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2694 retval = !list[i+1];
2696 HeapFree( GetProcessHeap(), 0, list );
2701 /*******************************************************************
2702 * GetTopWindow (USER32.@)
2704 HWND WINAPI GetTopWindow( HWND hwnd )
2706 if (!hwnd) hwnd = GetDesktopWindow();
2707 return GetWindow( hwnd, GW_CHILD );
2711 /*******************************************************************
2712 * GetWindow (USER32.@)
2714 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2718 if (rel == GW_OWNER) /* this one may be available locally */
2720 WND *wndPtr = WIN_GetPtr( hwnd );
2723 SetLastError( ERROR_INVALID_HANDLE );
2726 if (wndPtr == WND_DESKTOP) return 0;
2727 if (wndPtr != WND_OTHER_PROCESS)
2729 retval = wndPtr->owner;
2730 WIN_ReleasePtr( wndPtr );
2733 /* else fall through to server call */
2736 SERVER_START_REQ( get_window_tree )
2739 if (!wine_server_call_err( req ))
2744 retval = reply->first_sibling;
2747 retval = reply->last_sibling;
2750 retval = reply->next_sibling;
2753 retval = reply->prev_sibling;
2756 retval = reply->owner;
2759 retval = reply->first_child;
2769 /*******************************************************************
2770 * ShowOwnedPopups (USER32.@)
2772 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2776 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2778 if (!win_array) return TRUE;
2780 while (win_array[count]) count++;
2781 while (--count >= 0)
2783 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2784 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2785 if (pWnd == WND_OTHER_PROCESS) continue;
2788 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2790 WIN_ReleasePtr( pWnd );
2791 /* In Windows, ShowOwnedPopups(TRUE) generates
2792 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2793 * regardless of the state of the owner
2795 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2801 if (pWnd->dwStyle & WS_VISIBLE)
2803 WIN_ReleasePtr( pWnd );
2804 /* In Windows, ShowOwnedPopups(FALSE) generates
2805 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2806 * regardless of the state of the owner
2808 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2812 WIN_ReleasePtr( pWnd );
2814 HeapFree( GetProcessHeap(), 0, win_array );
2819 /*******************************************************************
2820 * GetLastActivePopup (USER32.@)
2822 HWND WINAPI GetLastActivePopup( HWND hwnd )
2826 SERVER_START_REQ( get_window_info )
2829 if (!wine_server_call_err( req )) retval = reply->last_active;
2836 /*******************************************************************
2839 * Build an array of the children of a given window. The array must be
2840 * freed with HeapFree. Returns NULL when no windows are found.
2842 HWND *WIN_ListChildren( HWND hwnd )
2844 return list_window_children( hwnd, NULL, 0 );
2848 /*******************************************************************
2849 * EnumWindows (USER32.@)
2851 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2857 USER_CheckNotLock();
2859 /* We have to build a list of all windows first, to avoid */
2860 /* unpleasant side-effects, for instance if the callback */
2861 /* function changes the Z-order of the windows. */
2863 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2865 /* Now call the callback function for every window */
2867 for (i = 0; list[i]; i++)
2869 /* Make sure that the window still exists */
2870 if (!IsWindow( list[i] )) continue;
2871 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2873 HeapFree( GetProcessHeap(), 0, list );
2878 /**********************************************************************
2879 * EnumThreadWindows (USER32.@)
2881 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2886 USER_CheckNotLock();
2888 if (!(list = list_window_children( GetDesktopWindow(), NULL, id ))) return TRUE;
2890 /* Now call the callback function for every window */
2892 for (i = 0; list[i]; i++)
2893 if (!func( list[i], lParam )) break;
2894 HeapFree( GetProcessHeap(), 0, list );
2899 /**********************************************************************
2900 * WIN_EnumChildWindows
2902 * Helper function for EnumChildWindows().
2904 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2909 for ( ; *list; list++)
2911 /* Make sure that the window still exists */
2912 if (!IsWindow( *list )) continue;
2913 /* Build children list first */
2914 childList = WIN_ListChildren( *list );
2916 ret = func( *list, lParam );
2920 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2921 HeapFree( GetProcessHeap(), 0, childList );
2923 if (!ret) return FALSE;
2929 /**********************************************************************
2930 * EnumChildWindows (USER32.@)
2932 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2937 USER_CheckNotLock();
2939 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2940 ret = WIN_EnumChildWindows( list, func, lParam );
2941 HeapFree( GetProcessHeap(), 0, list );
2946 /*******************************************************************
2947 * AnyPopup (USER.52)
2949 BOOL16 WINAPI AnyPopup16(void)
2955 /*******************************************************************
2956 * AnyPopup (USER32.@)
2958 BOOL WINAPI AnyPopup(void)
2962 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2964 if (!list) return FALSE;
2965 for (i = 0; list[i]; i++)
2967 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2969 retvalue = (list[i] != 0);
2970 HeapFree( GetProcessHeap(), 0, list );
2975 /*******************************************************************
2976 * FlashWindow (USER32.@)
2978 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2982 TRACE("%p\n", hWnd);
2984 if (IsIconic( hWnd ))
2986 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2988 wndPtr = WIN_GetPtr(hWnd);
2989 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2990 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2992 wndPtr->flags |= WIN_NCACTIVATED;
2996 wndPtr->flags &= ~WIN_NCACTIVATED;
2998 WIN_ReleasePtr( wndPtr );
3005 wndPtr = WIN_GetPtr(hWnd);
3006 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3007 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3009 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3010 else wparam = (hWnd == GetForegroundWindow());
3012 WIN_ReleasePtr( wndPtr );
3013 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3018 /*******************************************************************
3019 * FlashWindowEx (USER32.@)
3021 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3023 FIXME("%p\n", pfwi);
3027 /*******************************************************************
3028 * GetWindowContextHelpId (USER32.@)
3030 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3033 WND *wnd = WIN_GetPtr( hwnd );
3034 if (!wnd || wnd == WND_DESKTOP) return 0;
3035 if (wnd == WND_OTHER_PROCESS)
3037 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3040 retval = wnd->helpContext;
3041 WIN_ReleasePtr( wnd );
3046 /*******************************************************************
3047 * SetWindowContextHelpId (USER32.@)
3049 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3051 WND *wnd = WIN_GetPtr( hwnd );
3052 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3053 if (wnd == WND_OTHER_PROCESS)
3055 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3058 wnd->helpContext = id;
3059 WIN_ReleasePtr( wnd );
3064 /*******************************************************************
3065 * DragDetect (USER32.@)
3067 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3071 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3072 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3074 rect.left = pt.x - wDragWidth;
3075 rect.right = pt.x + wDragWidth;
3077 rect.top = pt.y - wDragHeight;
3078 rect.bottom = pt.y + wDragHeight;
3084 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3086 if( msg.message == WM_LBUTTONUP )
3091 if( msg.message == WM_MOUSEMOVE )
3094 tmp.x = (short)LOWORD(msg.lParam);
3095 tmp.y = (short)HIWORD(msg.lParam);
3096 if( !PtInRect( &rect, tmp ))
3108 /******************************************************************************
3109 * GetWindowModuleFileNameA (USER32.@)
3111 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3113 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3114 hwnd, lpszFileName, cchFileNameMax);
3118 /******************************************************************************
3119 * GetWindowModuleFileNameW (USER32.@)
3121 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3123 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3124 hwnd, lpszFileName, cchFileNameMax);
3128 /******************************************************************************
3129 * GetWindowInfo (USER32.@)
3131 * Note: tests show that Windows doesn't check cbSize of the structure.
3133 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3135 if (!pwi) return FALSE;
3136 if (!IsWindow(hwnd)) return FALSE;
3138 GetWindowRect(hwnd, &pwi->rcWindow);
3139 GetClientRect(hwnd, &pwi->rcClient);
3140 /* translate to screen coordinates */
3141 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3143 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3144 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3145 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3147 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3148 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3150 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3151 pwi->wCreatorVersion = 0x0400;
3156 /******************************************************************************
3157 * SwitchDesktop (USER32.@)
3159 * NOTES: Sets the current input or interactive desktop.
3161 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3163 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3167 /*****************************************************************************
3168 * SetLayeredWindowAttributes (USER32.@)
3170 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey,
3171 BYTE bAlpha, DWORD dwFlags )
3173 FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3177 /*****************************************************************************
3178 * GetLayeredWindowAttributes (USER32.@)
3180 BOOL WINAPI GetLayeredWindowAttributes( HWND hWnd, COLORREF *prgbKey,
3181 BYTE *pbAlpha, DWORD *pdwFlags )
3183 FIXME("(%p,%p,%p,%p): stub!\n", hWnd, prgbKey, pbAlpha, pdwFlags);
3187 /*****************************************************************************
3188 * UpdateLayeredWindow (USER32.@)
3190 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3191 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3198 FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3199 hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3204 /* 64bit versions */
3206 #ifdef GetWindowLongPtrW
3207 #undef GetWindowLongPtrW
3210 #ifdef GetWindowLongPtrA
3211 #undef GetWindowLongPtrA
3214 #ifdef SetWindowLongPtrW
3215 #undef SetWindowLongPtrW
3218 #ifdef SetWindowLongPtrA
3219 #undef SetWindowLongPtrA
3222 /*****************************************************************************
3223 * GetWindowLongPtrW (USER32.@)
3225 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3227 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3230 /*****************************************************************************
3231 * GetWindowLongPtrA (USER32.@)
3233 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3235 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3238 /*****************************************************************************
3239 * SetWindowLongPtrW (USER32.@)
3241 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3243 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3246 /*****************************************************************************
3247 * SetWindowLongPtrA (USER32.@)
3249 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3251 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );