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( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
224 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
226 SERVER_START_REQ( get_window_children )
228 req->desktop = desktop;
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 (!current) return list;
278 if (++pos == size - 1)
280 /* need to grow the list */
281 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
282 if (!new_list) goto empty;
288 /* at least one parent belongs to another process, have to query the server */
293 SERVER_START_REQ( get_window_parents )
296 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
297 if (!wine_server_call( req )) count = reply->count;
300 if (!count) goto empty;
306 HeapFree( GetProcessHeap(), 0, list );
308 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
312 HeapFree( GetProcessHeap(), 0, list );
317 /*******************************************************************
320 static void send_parent_notify( HWND hwnd, UINT msg )
322 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
323 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
325 HWND parent = GetParent(hwnd);
326 if (parent && parent != GetDesktopWindow())
327 SendMessageW( parent, WM_PARENTNOTIFY,
328 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
333 /*******************************************************************
334 * get_server_window_text
336 * Retrieve the window text from the server.
338 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
342 SERVER_START_REQ( get_window_text )
345 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
346 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
349 text[len / sizeof(WCHAR)] = 0;
353 /***********************************************************************
356 * Return a pointer to the WND structure if local to the process,
357 * or WND_OTHER_PROCESS if handle may be valid in other process.
358 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
360 WND *WIN_GetPtr( HWND hwnd )
363 WORD index = USER_HANDLE_TO_INDEX(hwnd);
365 if (index >= NB_USER_HANDLES) return NULL;
368 if ((ptr = user_handles[index]))
370 if (ptr->dwMagic == WND_MAGIC &&
371 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
375 else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
377 if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
380 else ptr = WND_OTHER_PROCESS;
386 /***********************************************************************
387 * WIN_IsCurrentProcess
389 * Check whether a given window belongs to the current process (and return the full handle).
391 HWND WIN_IsCurrentProcess( HWND hwnd )
396 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
398 WIN_ReleasePtr( ptr );
403 /***********************************************************************
404 * WIN_IsCurrentThread
406 * Check whether a given window belongs to the current thread (and return the full handle).
408 HWND WIN_IsCurrentThread( HWND hwnd )
413 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
414 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
415 WIN_ReleasePtr( ptr );
420 /***********************************************************************
423 * Convert a 16-bit window handle to a full 32-bit handle.
425 HWND WIN_Handle32( HWND16 hwnd16 )
428 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
430 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
431 /* do sign extension for -2 and -3 */
432 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
434 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
436 if (ptr == WND_DESKTOP) return GetDesktopWindow();
438 if (ptr != WND_OTHER_PROCESS)
440 hwnd = ptr->hwndSelf;
441 WIN_ReleasePtr( ptr );
443 else /* may belong to another process */
445 SERVER_START_REQ( get_window_info )
448 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
456 /***********************************************************************
459 * Change the owner of a window.
461 HWND WIN_SetOwner( HWND hwnd, HWND owner )
463 WND *win = WIN_GetPtr( hwnd );
466 if (!win || win == WND_DESKTOP) return 0;
467 if (win == WND_OTHER_PROCESS)
469 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
472 SERVER_START_REQ( set_window_owner )
476 if (!wine_server_call( req ))
478 win->owner = reply->full_owner;
479 ret = reply->prev_owner;
483 WIN_ReleasePtr( win );
488 /***********************************************************************
491 * Change the style of a window.
493 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
496 ULONG new_style, old_style = 0;
497 WND *win = WIN_GetPtr( hwnd );
499 if (!win || win == WND_DESKTOP) return 0;
500 if (win == WND_OTHER_PROCESS)
503 ERR( "cannot set style %x/%x on other process window %p\n",
504 set_bits, clear_bits, hwnd );
507 new_style = (win->dwStyle | set_bits) & ~clear_bits;
508 if (new_style == win->dwStyle)
510 WIN_ReleasePtr( win );
513 SERVER_START_REQ( set_window_info )
516 req->flags = SET_WIN_STYLE;
517 req->style = new_style;
518 req->extra_offset = -1;
519 if ((ok = !wine_server_call( req )))
521 old_style = reply->old_style;
522 win->dwStyle = new_style;
526 WIN_ReleasePtr( win );
529 USER_Driver->pSetWindowStyle( hwnd, old_style );
530 if ((old_style ^ new_style) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
536 /***********************************************************************
539 * Get the window and client rectangles.
541 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
543 WND *win = WIN_GetPtr( hwnd );
546 if (!win) return FALSE;
547 if (win == WND_DESKTOP)
550 rect.left = rect.top = 0;
551 rect.right = GetSystemMetrics(SM_CXSCREEN);
552 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
553 if (rectWindow) *rectWindow = rect;
554 if (rectClient) *rectClient = rect;
556 else if (win == WND_OTHER_PROCESS)
558 SERVER_START_REQ( get_window_rectangles )
561 if ((ret = !wine_server_call( req )))
565 rectWindow->left = reply->window.left;
566 rectWindow->top = reply->window.top;
567 rectWindow->right = reply->window.right;
568 rectWindow->bottom = reply->window.bottom;
572 rectClient->left = reply->client.left;
573 rectClient->top = reply->client.top;
574 rectClient->right = reply->client.right;
575 rectClient->bottom = reply->client.bottom;
583 if (rectWindow) *rectWindow = win->rectWindow;
584 if (rectClient) *rectClient = win->rectClient;
585 WIN_ReleasePtr( win );
591 /***********************************************************************
594 * Destroy storage associated to a window. "Internals" p.358
596 LRESULT WIN_DestroyWindow( HWND hwnd )
600 HMENU menu = 0, sys_menu;
603 TRACE("%p\n", hwnd );
605 /* free child windows */
606 if ((list = WIN_ListChildren( hwnd )))
609 for (i = 0; list[i]; i++)
611 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
612 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
614 HeapFree( GetProcessHeap(), 0, list );
617 /* Unlink now so we won't bother with the children later on */
618 SERVER_START_REQ( set_parent )
622 wine_server_call( req );
627 * Send the WM_NCDESTROY to the window being destroyed.
629 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
631 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
633 /* free resources associated with the window */
635 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
636 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
637 menu = (HMENU)wndPtr->wIDmenu;
638 sys_menu = wndPtr->hSysMenu;
639 free_dce( wndPtr->dce, hwnd );
641 icon_title = wndPtr->icon_title;
642 WIN_ReleasePtr( wndPtr );
644 if (icon_title) DestroyWindow( icon_title );
645 if (menu) DestroyMenu( menu );
646 if (sys_menu) DestroyMenu( sys_menu );
648 USER_Driver->pDestroyWindow( hwnd );
650 free_window_handle( hwnd );
654 /***********************************************************************
655 * WIN_DestroyThreadWindows
657 * Destroy all children of 'wnd' owned by the current thread.
659 void WIN_DestroyThreadWindows( HWND hwnd )
664 if (!(list = WIN_ListChildren( hwnd ))) return;
665 for (i = 0; list[i]; i++)
667 if (WIN_IsCurrentThread( list[i] ))
668 DestroyWindow( list[i] );
670 WIN_DestroyThreadWindows( list[i] );
672 HeapFree( GetProcessHeap(), 0, list );
676 /***********************************************************************
679 * Fix the coordinates - Helper for WIN_CreateWindowEx.
680 * returns default show mode in sw.
682 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
684 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
687 if (cs->dwExStyle & WS_EX_MDICHILD)
691 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
692 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
694 TRACE("MDI child id %04x\n", id);
697 if (cs->style & (WS_CHILD | WS_POPUP))
699 if (cs->dwExStyle & WS_EX_MDICHILD)
701 if (IS_DEFAULT(cs->x))
706 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
707 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
711 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
712 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
715 else /* overlapped window */
718 MONITORINFO mon_info;
721 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
723 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
724 mon_info.cbSize = sizeof(mon_info);
725 GetMonitorInfoW( monitor, &mon_info );
726 GetStartupInfoW( &info );
728 if (IS_DEFAULT(cs->x))
730 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
731 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
732 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
735 if (IS_DEFAULT(cs->cx))
737 if (info.dwFlags & STARTF_USESIZE)
739 cs->cx = info.dwXSize;
740 cs->cy = info.dwYSize;
744 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
745 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
748 /* neither x nor cx are default. Check the y values .
749 * In the trace we see Outlook and Outlook Express using
750 * cy set to CW_USEDEFAULT when opening the address book.
752 else if (IS_DEFAULT(cs->cy))
754 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
755 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
761 /***********************************************************************
764 static void dump_window_styles( DWORD style, DWORD exstyle )
767 if(style & WS_POPUP) TRACE(" WS_POPUP");
768 if(style & WS_CHILD) TRACE(" WS_CHILD");
769 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
770 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
771 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
772 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
773 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
774 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
775 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
778 if(style & WS_BORDER) TRACE(" WS_BORDER");
779 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
781 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
782 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
783 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
784 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
785 if (style & WS_CHILD)
787 if(style & WS_GROUP) TRACE(" WS_GROUP");
788 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
792 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
793 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
796 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
797 #define DUMPED_STYLES \
817 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
822 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
823 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
824 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
825 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
826 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
827 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
828 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
829 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
830 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
831 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
832 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
833 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
834 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
835 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
836 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
837 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
838 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
839 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
841 #define DUMPED_EX_STYLES \
842 (WS_EX_DLGMODALFRAME | \
844 WS_EX_NOPARENTNOTIFY | \
846 WS_EX_ACCEPTFILES | \
847 WS_EX_TRANSPARENT | \
852 WS_EX_CONTEXTHELP | \
855 WS_EX_LEFTSCROLLBAR | \
856 WS_EX_CONTROLPARENT | \
861 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
863 #undef DUMPED_EX_STYLES
867 /***********************************************************************
870 * Implementation of CreateWindowEx().
872 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
874 INT cx, cy, style, sw = SW_SHOW;
878 HWND hwnd, parent, owner, top_child = 0;
879 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
880 MDICREATESTRUCTA mdi_cs;
884 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
885 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
886 debugstr_w(className),
887 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
888 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
889 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
891 /* Fix the styles for MDI children */
892 if (cs->dwExStyle & WS_EX_MDICHILD)
896 wndPtr = WIN_GetPtr(cs->hwndParent);
897 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
899 flags = wndPtr->flags;
900 WIN_ReleasePtr(wndPtr);
903 if (!(flags & WIN_ISMDICLIENT))
905 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
909 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
910 * MDICREATESTRUCT members have the originally passed values.
912 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
913 * have the same layout.
915 mdi_cs.szClass = cs->lpszClass;
916 mdi_cs.szTitle = cs->lpszName;
917 mdi_cs.hOwner = cs->hInstance;
922 mdi_cs.style = cs->style;
923 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
925 cs->lpCreateParams = (LPVOID)&mdi_cs;
927 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
929 if (cs->style & WS_POPUP)
931 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
934 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
938 cs->style &= ~WS_POPUP;
939 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
940 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
943 top_child = GetWindow(cs->hwndParent, GW_CHILD);
947 /* Restore current maximized child */
948 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
950 TRACE("Restoring current maximized child %p\n", top_child);
951 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
952 ShowWindow( top_child, SW_SHOWNORMAL );
953 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
958 /* Find the parent window */
960 parent = cs->hwndParent;
963 if (cs->hwndParent == HWND_MESSAGE)
965 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
966 * message window (style: WS_POPUP|WS_DISABLED)
968 FIXME("Parent is HWND_MESSAGE\n");
969 parent = GetDesktopWindow();
971 else if (cs->hwndParent)
973 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
975 parent = GetDesktopWindow();
976 owner = cs->hwndParent;
981 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
983 WARN("No parent for child window\n" );
984 SetLastError(ERROR_TLW_WITH_WSCHILD);
985 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
987 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM) /* are we creating the desktop itself? */
988 parent = GetDesktopWindow();
991 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
993 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
994 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
995 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
996 cs->dwExStyle |= WS_EX_WINDOWEDGE;
998 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1000 /* Create the window structure */
1002 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1004 hwnd = wndPtr->hwndSelf;
1006 /* Fill the window structure */
1008 wndPtr->tid = GetCurrentThreadId();
1009 wndPtr->hInstance = cs->hInstance;
1010 wndPtr->text = NULL;
1011 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1012 wndPtr->dwExStyle = cs->dwExStyle;
1013 wndPtr->wIDmenu = 0;
1014 wndPtr->helpContext = 0;
1015 wndPtr->pVScroll = NULL;
1016 wndPtr->pHScroll = NULL;
1017 wndPtr->userdata = 0;
1019 wndPtr->hIconSmall = 0;
1020 wndPtr->hSysMenu = 0;
1021 wndPtr->flags |= (flags & WIN_ISWIN32);
1023 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1026 * Correct the window styles.
1028 * It affects only the style loaded into the WIN structure.
1031 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1033 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1034 if (!(wndPtr->dwStyle & WS_POPUP))
1035 wndPtr->dwStyle |= WS_CAPTION;
1039 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1040 * why does the user get to set it?
1043 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1044 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1045 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1047 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1049 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1050 wndPtr->flags |= WIN_NEED_SIZE;
1052 SERVER_START_REQ( set_window_info )
1055 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1056 req->style = wndPtr->dwStyle;
1057 req->ex_style = wndPtr->dwExStyle;
1058 req->instance = (void *)wndPtr->hInstance;
1059 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1060 req->extra_offset = -1;
1061 wine_server_call( req );
1065 /* Set the window menu */
1067 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1071 if (!MENU_SetMenu(hwnd, cs->hMenu))
1073 WIN_ReleasePtr( wndPtr );
1074 free_window_handle( hwnd );
1080 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1083 if (!cs->hInstance || HIWORD(cs->hInstance))
1084 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1086 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1088 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1092 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1094 /* call the WH_CBT hook */
1096 /* the window style passed to the hook must be the real window style,
1097 * rather than just the window style that the caller to CreateWindowEx
1098 * passed in, so we have to copy the original CREATESTRUCT and get the
1099 * the real style. */
1101 cbcs.style = wndPtr->dwStyle;
1103 cbtc.hwndInsertAfter = HWND_TOP;
1104 WIN_ReleasePtr( wndPtr );
1105 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1107 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1111 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1113 POINT maxSize, maxPos, minTrack, maxTrack;
1114 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1115 if (maxTrack.x < cx) cx = maxTrack.x;
1116 if (maxTrack.y < cy) cy = maxTrack.y;
1121 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1122 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1124 /* send WM_NCCREATE */
1126 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1128 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1130 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1133 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1137 /* send WM_NCCALCSIZE */
1139 if ((wndPtr = WIN_GetPtr(hwnd)))
1141 /* yes, even if the CBT hook was called with HWND_TOP */
1143 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1144 RECT window_rect = wndPtr->rectWindow;
1145 RECT client_rect = window_rect;
1146 WIN_ReleasePtr( wndPtr );
1148 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1150 MapWindowPoints( parent, 0, &pt, 1 );
1151 OffsetRect( &client_rect, pt.x, pt.y );
1152 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1153 OffsetRect( &client_rect, -pt.x, -pt.y );
1154 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1158 /* send WM_CREATE */
1161 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1163 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1164 if (result == -1) goto failed;
1166 /* call the driver */
1168 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1170 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1172 /* send the size messages */
1174 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1175 if (!(wndPtr->flags & WIN_NEED_SIZE))
1177 rect = wndPtr->rectClient;
1178 WIN_ReleasePtr( wndPtr );
1179 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1180 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1181 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1183 else WIN_ReleasePtr( wndPtr );
1185 /* Show the window, maximizing or minimizing if needed */
1187 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1188 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1191 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1193 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1194 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1195 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1196 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right, newPos.bottom, swFlag );
1199 /* Notify the parent window only */
1201 send_parent_notify( hwnd, WM_CREATE );
1202 if (!IsWindow( hwnd )) return 0;
1204 if (cs->style & WS_VISIBLE)
1206 if (cs->style & WS_MAXIMIZE)
1208 else if (cs->style & WS_MINIMIZE)
1209 sw = SW_SHOWMINIMIZED;
1211 ShowWindow( hwnd, sw );
1212 if (cs->dwExStyle & WS_EX_MDICHILD)
1214 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1215 /* ShowWindow won't activate child windows */
1216 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1220 /* Call WH_SHELL hook */
1222 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1223 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1225 TRACE("created window %p\n", hwnd);
1229 WIN_DestroyWindow( hwnd );
1234 /***********************************************************************
1235 * CreateWindow (USER.41)
1237 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1238 DWORD style, INT16 x, INT16 y, INT16 width,
1239 INT16 height, HWND16 parent, HMENU16 menu,
1240 HINSTANCE16 instance, LPVOID data )
1242 return CreateWindowEx16( 0, className, windowName, style,
1243 x, y, width, height, parent, menu, instance, data );
1247 /***********************************************************************
1248 * CreateWindowEx (USER.452)
1250 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1251 LPCSTR windowName, DWORD style, INT16 x,
1252 INT16 y, INT16 width, INT16 height,
1253 HWND16 parent, HMENU16 menu,
1254 HINSTANCE16 instance, LPVOID data )
1259 /* Fix the coordinates */
1261 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1262 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1263 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1264 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1266 /* Create the window */
1268 cs.lpCreateParams = data;
1269 cs.hInstance = HINSTANCE_32(instance);
1270 cs.hMenu = HMENU_32(menu);
1271 cs.hwndParent = WIN_Handle32( parent );
1273 cs.lpszName = windowName;
1274 cs.lpszClass = className;
1275 cs.dwExStyle = exStyle;
1277 if (!IS_INTRESOURCE(className))
1281 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1283 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1287 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1289 ERR( "bad atom %x\n", LOWORD(className));
1292 cs.lpszClass = buffer;
1293 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1298 /***********************************************************************
1299 * CreateWindowExA (USER32.@)
1301 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1302 LPCSTR windowName, DWORD style, INT x,
1303 INT y, INT width, INT height,
1304 HWND parent, HMENU menu,
1305 HINSTANCE instance, LPVOID data )
1309 cs.lpCreateParams = data;
1310 cs.hInstance = instance;
1312 cs.hwndParent = parent;
1318 cs.lpszName = windowName;
1319 cs.lpszClass = className;
1320 cs.dwExStyle = exStyle;
1322 if (!IS_INTRESOURCE(className))
1325 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1327 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1329 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1333 /***********************************************************************
1334 * CreateWindowExW (USER32.@)
1336 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1337 LPCWSTR windowName, DWORD style, INT x,
1338 INT y, INT width, INT height,
1339 HWND parent, HMENU menu,
1340 HINSTANCE instance, LPVOID data )
1344 cs.lpCreateParams = data;
1345 cs.hInstance = instance;
1347 cs.hwndParent = parent;
1353 cs.lpszName = windowName;
1354 cs.lpszClass = className;
1355 cs.dwExStyle = exStyle;
1357 /* Note: we rely on the fact that CREATESTRUCTA and */
1358 /* CREATESTRUCTW have the same layout. */
1359 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1363 /***********************************************************************
1364 * WIN_SendDestroyMsg
1366 static void WIN_SendDestroyMsg( HWND hwnd )
1370 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1372 if (hwnd == info.hwndCaret) DestroyCaret();
1373 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1377 * Send the WM_DESTROY to the window.
1379 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1382 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1383 * make sure that the window still exists when we come back.
1390 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1392 for (i = 0; pWndArray[i]; i++)
1394 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1396 HeapFree( GetProcessHeap(), 0, pWndArray );
1399 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1403 /***********************************************************************
1404 * DestroyWindow (USER32.@)
1406 BOOL WINAPI DestroyWindow( HWND hwnd )
1410 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1412 SetLastError( ERROR_ACCESS_DENIED );
1416 TRACE("(%p)\n", hwnd);
1420 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1422 if (MENU_IsMenuActive() == hwnd)
1425 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1429 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1430 send_parent_notify( hwnd, WM_DESTROY );
1432 else if (!GetWindow( hwnd, GW_OWNER ))
1434 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1435 /* FIXME: clean up palette - see "Internals" p.352 */
1438 if (!IsWindow(hwnd)) return TRUE;
1440 /* Hide the window */
1441 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1443 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1445 ShowWindow( hwnd, SW_HIDE );
1447 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1448 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1451 if (!IsWindow(hwnd)) return TRUE;
1453 /* Recursively destroy owned windows */
1460 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1463 for (i = 0; list[i]; i++)
1465 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1466 if (WIN_IsCurrentThread( list[i] ))
1468 DestroyWindow( list[i] );
1472 WIN_SetOwner( list[i], 0 );
1474 HeapFree( GetProcessHeap(), 0, list );
1476 if (!got_one) break;
1480 /* Send destroy messages */
1482 WIN_SendDestroyMsg( hwnd );
1483 if (!IsWindow( hwnd )) return TRUE;
1485 if (GetClipboardOwner() == hwnd)
1486 CLIPBOARD_ReleaseOwner();
1488 /* Destroy the window storage */
1490 WIN_DestroyWindow( hwnd );
1495 /***********************************************************************
1496 * CloseWindow (USER32.@)
1498 BOOL WINAPI CloseWindow( HWND hwnd )
1500 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1501 ShowWindow( hwnd, SW_MINIMIZE );
1506 /***********************************************************************
1507 * OpenIcon (USER32.@)
1509 BOOL WINAPI OpenIcon( HWND hwnd )
1511 if (!IsIconic( hwnd )) return FALSE;
1512 ShowWindow( hwnd, SW_SHOWNORMAL );
1517 /***********************************************************************
1518 * FindWindowExW (USER32.@)
1520 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1525 WCHAR *buffer = NULL;
1527 if (!parent) parent = GetDesktopWindow();
1530 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1531 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1534 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1538 child = WIN_GetFullHandle( child );
1539 while (list[i] && list[i] != child) i++;
1540 if (!list[i]) goto done;
1541 i++; /* start from next window */
1548 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1555 HeapFree( GetProcessHeap(), 0, list );
1556 HeapFree( GetProcessHeap(), 0, buffer );
1562 /***********************************************************************
1563 * FindWindowA (USER32.@)
1565 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1567 HWND ret = FindWindowExA( 0, 0, className, title );
1568 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1573 /***********************************************************************
1574 * FindWindowExA (USER32.@)
1576 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1578 LPWSTR titleW = NULL;
1583 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1584 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1585 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1588 if (!IS_INTRESOURCE(className))
1591 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1592 hwnd = FindWindowExW( parent, child, classW, titleW );
1596 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1599 HeapFree( GetProcessHeap(), 0, titleW );
1604 /***********************************************************************
1605 * FindWindowW (USER32.@)
1607 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1609 return FindWindowExW( 0, 0, className, title );
1613 /**********************************************************************
1614 * GetDesktopWindow (USER32.@)
1616 HWND WINAPI GetDesktopWindow(void)
1618 struct user_thread_info *thread_info = get_user_thread_info();
1620 if (thread_info->desktop) return thread_info->desktop;
1622 SERVER_START_REQ( get_desktop_window )
1625 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1629 if (!thread_info->desktop)
1631 USEROBJECTFLAGS flags;
1632 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1633 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1635 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1637 PROCESS_INFORMATION pi;
1638 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1640 memset( &si, 0, sizeof(si) );
1642 si.dwFlags = STARTF_USESTDHANDLES;
1645 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1647 GetSystemDirectoryW( cmdline, MAX_PATH );
1648 lstrcatW( cmdline, command_line );
1649 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1650 NULL, NULL, &si, &pi ))
1652 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1653 WaitForInputIdle( pi.hProcess, 10000 );
1654 CloseHandle( pi.hThread );
1655 CloseHandle( pi.hProcess );
1657 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1659 else TRACE( "not starting explorer since winstation is not visible\n" );
1661 SERVER_START_REQ( get_desktop_window )
1664 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1669 if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1670 ERR( "failed to create desktop window\n" );
1672 return thread_info->desktop;
1676 /*******************************************************************
1677 * EnableWindow (USER32.@)
1679 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1684 if (is_broadcast(hwnd))
1686 SetLastError( ERROR_INVALID_PARAMETER );
1690 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1691 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1695 TRACE("( %p, %d )\n", hwnd, enable);
1697 retvalue = !IsWindowEnabled( hwnd );
1699 if (enable && retvalue)
1701 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1702 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1704 else if (!enable && !retvalue)
1708 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1710 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1712 if (hwnd == GetFocus())
1713 SetFocus( 0 ); /* A disabled window can't have the focus */
1715 capture_wnd = GetCapture();
1716 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1717 ReleaseCapture(); /* A disabled window can't capture the mouse */
1719 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1725 /***********************************************************************
1726 * IsWindowEnabled (USER32.@)
1728 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1730 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1734 /***********************************************************************
1735 * IsWindowUnicode (USER32.@)
1737 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1740 BOOL retvalue = FALSE;
1742 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1744 if (wndPtr == WND_DESKTOP) return TRUE;
1746 if (wndPtr != WND_OTHER_PROCESS)
1748 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1749 WIN_ReleasePtr( wndPtr );
1753 SERVER_START_REQ( get_window_info )
1756 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1764 /**********************************************************************
1767 * Helper function for GetWindowLong().
1769 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1771 LONG_PTR retvalue = 0;
1774 if (offset == GWLP_HWNDPARENT)
1776 HWND parent = GetAncestor( hwnd, GA_PARENT );
1777 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1778 return (ULONG_PTR)parent;
1781 if (!(wndPtr = WIN_GetPtr( hwnd )))
1783 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1787 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1789 if (offset == GWLP_WNDPROC)
1791 SetLastError( ERROR_ACCESS_DENIED );
1794 SERVER_START_REQ( set_window_info )
1797 req->flags = 0; /* don't set anything, just retrieve */
1798 req->extra_offset = (offset >= 0) ? offset : -1;
1799 req->extra_size = (offset >= 0) ? size : 0;
1800 if (!wine_server_call_err( req ))
1804 case GWL_STYLE: retvalue = reply->old_style; break;
1805 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1806 case GWLP_ID: retvalue = reply->old_id; break;
1807 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1808 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1810 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1811 else SetLastError( ERROR_INVALID_INDEX );
1820 /* now we have a valid wndPtr */
1824 if (offset > (int)(wndPtr->cbWndExtra - size))
1826 WARN("Invalid offset %d\n", offset );
1827 WIN_ReleasePtr( wndPtr );
1828 SetLastError( ERROR_INVALID_INDEX );
1831 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1833 /* Special case for dialog window procedure */
1834 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1835 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1836 WIN_ReleasePtr( wndPtr );
1842 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1843 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1844 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1845 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1846 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1848 /* This looks like a hack only for the edit control (see tests). This makes these controls
1849 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1850 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1852 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1853 retvalue = (ULONG_PTR)wndPtr->winproc;
1855 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1858 WARN("Unknown offset %d\n", offset );
1859 SetLastError( ERROR_INVALID_INDEX );
1862 WIN_ReleasePtr(wndPtr);
1867 /**********************************************************************
1870 * Helper function for SetWindowLong().
1872 * 0 is the failure code. However, in the case of failure SetLastError
1873 * must be set to distinguish between a 0 return value and a failure.
1875 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1879 LONG_PTR retval = 0;
1882 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1884 if (is_broadcast(hwnd))
1886 SetLastError( ERROR_INVALID_PARAMETER );
1890 if (!(wndPtr = WIN_GetPtr( hwnd )))
1892 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1895 if (wndPtr == WND_DESKTOP)
1897 /* can't change anything on the desktop window */
1898 SetLastError( ERROR_ACCESS_DENIED );
1901 if (wndPtr == WND_OTHER_PROCESS)
1903 if (offset == GWLP_WNDPROC)
1905 SetLastError( ERROR_ACCESS_DENIED );
1908 if (offset > 32767 || offset < -32767)
1910 SetLastError( ERROR_INVALID_INDEX );
1913 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1916 /* first some special cases */
1922 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1923 style.styleNew = newval;
1924 WIN_ReleasePtr( wndPtr );
1925 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1926 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1927 newval = style.styleNew;
1929 case GWLP_HWNDPARENT:
1930 if (wndPtr->parent == GetDesktopWindow())
1932 WIN_ReleasePtr( wndPtr );
1933 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1937 WIN_ReleasePtr( wndPtr );
1938 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1943 UINT old_flags = wndPtr->flags;
1944 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1945 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1946 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1947 if (proc) wndPtr->winproc = proc;
1948 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1949 else wndPtr->flags &= ~WIN_ISUNICODE;
1950 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1952 WIN_ReleasePtr( wndPtr );
1955 /* update is_unicode flag on the server side */
1959 case GWLP_HINSTANCE:
1963 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1964 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1966 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1967 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1968 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1969 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1970 WIN_ReleasePtr( wndPtr );
1975 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1977 WARN("Invalid offset %d\n", offset );
1978 WIN_ReleasePtr( wndPtr );
1979 SetLastError( ERROR_INVALID_INDEX );
1982 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1984 /* already set to the same value */
1985 WIN_ReleasePtr( wndPtr );
1991 SERVER_START_REQ( set_window_info )
1994 req->extra_offset = -1;
1998 req->flags = SET_WIN_STYLE;
1999 req->style = newval;
2002 req->flags = SET_WIN_EXSTYLE;
2003 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2004 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2005 req->ex_style = newval;
2008 req->flags = SET_WIN_ID;
2011 case GWLP_HINSTANCE:
2012 req->flags = SET_WIN_INSTANCE;
2013 req->instance = (void *)newval;
2016 req->flags = SET_WIN_UNICODE;
2017 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2020 req->flags = SET_WIN_USERDATA;
2021 req->user_data = newval;
2024 req->flags = SET_WIN_EXTRA;
2025 req->extra_offset = offset;
2026 req->extra_size = size;
2027 set_win_data( &req->extra_value, newval, size );
2029 if ((ok = !wine_server_call_err( req )))
2034 wndPtr->dwStyle = newval;
2035 retval = reply->old_style;
2038 wndPtr->dwExStyle = newval;
2039 retval = reply->old_ex_style;
2042 wndPtr->wIDmenu = newval;
2043 retval = reply->old_id;
2045 case GWLP_HINSTANCE:
2046 wndPtr->hInstance = (HINSTANCE)newval;
2047 retval = (ULONG_PTR)reply->old_instance;
2052 wndPtr->userdata = newval;
2053 retval = reply->old_user_data;
2056 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2057 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2063 WIN_ReleasePtr( wndPtr );
2067 if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2069 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2070 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2076 /**********************************************************************
2077 * GetWindowLong (USER.135)
2079 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2083 BOOL is_winproc = (offset == GWLP_WNDPROC);
2087 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2089 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2092 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2094 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2097 * Some programs try to access last element from 16 bit
2098 * code using illegal offset value. Hopefully this is
2099 * what those programs really expect.
2101 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2103 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2104 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2109 WARN("Invalid offset %d\n", offset );
2110 WIN_ReleasePtr( wndPtr );
2111 SetLastError( ERROR_INVALID_INDEX );
2115 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2116 WIN_ReleasePtr( wndPtr );
2119 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2120 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2125 /**********************************************************************
2126 * GetWindowWord (USER32.@)
2128 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2133 case GWLP_HINSTANCE:
2134 case GWLP_HWNDPARENT:
2139 WARN("Invalid offset %d\n", offset );
2140 SetLastError( ERROR_INVALID_INDEX );
2145 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2149 /**********************************************************************
2150 * GetWindowLongA (USER32.@)
2152 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2154 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2158 /**********************************************************************
2159 * GetWindowLongW (USER32.@)
2161 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2163 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2167 /**********************************************************************
2168 * SetWindowLong (USER.136)
2170 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2173 BOOL is_winproc = (offset == GWLP_WNDPROC);
2175 if (offset == DWLP_DLGPROC)
2177 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2179 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2182 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2184 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2185 (wndPtr->flags & WIN_ISDIALOG));
2186 WIN_ReleasePtr( wndPtr );
2192 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2193 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2194 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2196 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2200 /**********************************************************************
2201 * SetWindowWord (USER32.@)
2203 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2208 case GWLP_HINSTANCE:
2209 case GWLP_HWNDPARENT:
2214 WARN("Invalid offset %d\n", offset );
2215 SetLastError( ERROR_INVALID_INDEX );
2220 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2224 /**********************************************************************
2225 * SetWindowLongA (USER32.@)
2227 * See SetWindowLongW.
2229 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2231 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2235 /**********************************************************************
2236 * SetWindowLongW (USER32.@) Set window attribute
2238 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2239 * value in a window's extra memory.
2241 * The _hwnd_ parameter specifies the window. is the handle to a
2242 * window that has extra memory. The _newval_ parameter contains the
2243 * new attribute or extra memory value. If positive, the _offset_
2244 * parameter is the byte-addressed location in the window's extra
2245 * memory to set. If negative, _offset_ specifies the window
2246 * attribute to set, and should be one of the following values:
2248 * GWL_EXSTYLE The window's extended window style
2250 * GWL_STYLE The window's window style.
2252 * GWLP_WNDPROC Pointer to the window's window procedure.
2254 * GWLP_HINSTANCE The window's pplication instance handle.
2256 * GWLP_ID The window's identifier.
2258 * GWLP_USERDATA The window's user-specified data.
2260 * If the window is a dialog box, the _offset_ parameter can be one of
2261 * the following values:
2263 * DWLP_DLGPROC The address of the window's dialog box procedure.
2265 * DWLP_MSGRESULT The return value of a message
2266 * that the dialog box procedure processed.
2268 * DWLP_USER Application specific information.
2272 * If successful, returns the previous value located at _offset_. Otherwise,
2277 * Extra memory for a window class is specified by a nonzero cbWndExtra
2278 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2279 * time of class creation.
2281 * Using GWL_WNDPROC to set a new window procedure effectively creates
2282 * a window subclass. Use CallWindowProc() in the new windows procedure
2283 * to pass messages to the superclass's window procedure.
2285 * The user data is reserved for use by the application which created
2288 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2289 * instead, call the EnableWindow() function to change the window's
2292 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2293 * SetParent() instead.
2296 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2297 * it sends WM_STYLECHANGING before changing the settings
2298 * and WM_STYLECHANGED afterwards.
2299 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2301 LONG WINAPI SetWindowLongW(
2302 HWND hwnd, /* [in] window to alter */
2303 INT offset, /* [in] offset, in bytes, of location to alter */
2304 LONG newval /* [in] new value of location */
2306 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2310 /*******************************************************************
2311 * GetWindowTextA (USER32.@)
2313 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2317 if (!lpString) return 0;
2319 if (WIN_IsCurrentProcess( hwnd ))
2320 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2322 /* when window belongs to other process, don't send a message */
2323 if (nMaxCount <= 0) return 0;
2324 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2325 get_server_window_text( hwnd, buffer, nMaxCount );
2326 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2327 lpString[nMaxCount-1] = 0;
2328 HeapFree( GetProcessHeap(), 0, buffer );
2329 return strlen(lpString);
2333 /*******************************************************************
2334 * InternalGetWindowText (USER32.@)
2336 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2340 if (nMaxCount <= 0) return 0;
2341 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2342 if (win == WND_DESKTOP) lpString[0] = 0;
2343 else if (win != WND_OTHER_PROCESS)
2345 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2346 else lpString[0] = 0;
2347 WIN_ReleasePtr( win );
2351 get_server_window_text( hwnd, lpString, nMaxCount );
2353 return strlenW(lpString);
2357 /*******************************************************************
2358 * GetWindowTextW (USER32.@)
2360 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2362 if (!lpString) return 0;
2364 if (WIN_IsCurrentProcess( hwnd ))
2365 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2367 /* when window belongs to other process, don't send a message */
2368 if (nMaxCount <= 0) return 0;
2369 get_server_window_text( hwnd, lpString, nMaxCount );
2370 return strlenW(lpString);
2374 /*******************************************************************
2375 * SetWindowTextA (USER32.@)
2376 * SetWindowText (USER32.@)
2378 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2380 if (is_broadcast(hwnd))
2382 SetLastError( ERROR_INVALID_PARAMETER );
2385 if (!WIN_IsCurrentProcess( hwnd ))
2386 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2387 debugstr_a(lpString), hwnd );
2388 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2392 /*******************************************************************
2393 * SetWindowTextW (USER32.@)
2395 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2397 if (is_broadcast(hwnd))
2399 SetLastError( ERROR_INVALID_PARAMETER );
2402 if (!WIN_IsCurrentProcess( hwnd ))
2403 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2404 debugstr_w(lpString), hwnd );
2405 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2409 /*******************************************************************
2410 * GetWindowTextLengthA (USER32.@)
2412 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2414 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2417 /*******************************************************************
2418 * GetWindowTextLengthW (USER32.@)
2420 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2422 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2426 /*******************************************************************
2427 * IsWindow (USER32.@)
2429 BOOL WINAPI IsWindow( HWND hwnd )
2434 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2435 if (ptr == WND_DESKTOP) return TRUE;
2437 if (ptr != WND_OTHER_PROCESS)
2439 WIN_ReleasePtr( ptr );
2443 /* check other processes */
2444 SERVER_START_REQ( get_window_info )
2447 ret = !wine_server_call_err( req );
2454 /***********************************************************************
2455 * GetWindowThreadProcessId (USER32.@)
2457 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2462 if (!(ptr = WIN_GetPtr( hwnd )))
2464 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2468 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2470 /* got a valid window */
2472 if (process) *process = GetCurrentProcessId();
2473 WIN_ReleasePtr( ptr );
2477 /* check other processes */
2478 SERVER_START_REQ( get_window_info )
2481 if (!wine_server_call_err( req ))
2483 tid = (DWORD)reply->tid;
2484 if (process) *process = (DWORD)reply->pid;
2492 /*****************************************************************
2493 * GetParent (USER32.@)
2495 HWND WINAPI GetParent( HWND hwnd )
2500 if (!(wndPtr = WIN_GetPtr( hwnd )))
2502 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2505 if (wndPtr == WND_DESKTOP) return 0;
2506 if (wndPtr == WND_OTHER_PROCESS)
2508 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2509 if (style & (WS_POPUP | WS_CHILD))
2511 SERVER_START_REQ( get_window_tree )
2514 if (!wine_server_call_err( req ))
2516 if (style & WS_POPUP) retvalue = reply->owner;
2517 else if (style & WS_CHILD) retvalue = reply->parent;
2525 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2526 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2527 WIN_ReleasePtr( wndPtr );
2533 /*****************************************************************
2534 * GetAncestor (USER32.@)
2536 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2539 HWND *list, ret = 0;
2544 if (!(win = WIN_GetPtr( hwnd )))
2546 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2549 if (win == WND_DESKTOP) return 0;
2550 if (win != WND_OTHER_PROCESS)
2553 WIN_ReleasePtr( win );
2555 else /* need to query the server */
2557 SERVER_START_REQ( get_window_tree )
2560 if (!wine_server_call_err( req )) ret = reply->parent;
2567 if (!(list = list_window_parents( hwnd ))) return 0;
2569 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2573 while (list[count]) count++;
2574 ret = list[count - 2]; /* get the one before the desktop */
2576 HeapFree( GetProcessHeap(), 0, list );
2580 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2583 HWND parent = GetParent( ret );
2593 /*****************************************************************
2594 * SetParent (USER32.@)
2596 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2599 HWND old_parent = 0;
2604 if (is_broadcast(hwnd) || is_broadcast(parent))
2606 SetLastError(ERROR_INVALID_PARAMETER);
2610 if (!parent) parent = GetDesktopWindow();
2611 else parent = WIN_GetFullHandle( parent );
2613 if (!IsWindow( parent ))
2615 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2619 /* Some applications try to set a child as a parent */
2620 if (IsChild(hwnd, parent))
2622 SetLastError( ERROR_INVALID_PARAMETER );
2626 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2627 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2629 /* Windows hides the window first, then shows it again
2630 * including the WM_SHOWWINDOW messages and all */
2631 was_visible = ShowWindow( hwnd, SW_HIDE );
2633 wndPtr = WIN_GetPtr( hwnd );
2634 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2636 SERVER_START_REQ( set_parent )
2639 req->parent = parent;
2640 if ((ret = !wine_server_call( req )))
2642 old_parent = reply->old_parent;
2643 wndPtr->parent = parent = reply->full_parent;
2648 WIN_ReleasePtr( wndPtr );
2651 USER_Driver->pSetParent( full_handle, parent, old_parent );
2653 /* SetParent additionally needs to make hwnd the topmost window
2654 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2655 WM_WINDOWPOSCHANGED notification messages.
2657 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2658 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2659 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2660 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2666 /*******************************************************************
2667 * IsChild (USER32.@)
2669 BOOL WINAPI IsChild( HWND parent, HWND child )
2671 HWND *list = list_window_parents( child );
2675 if (!list) return FALSE;
2676 parent = WIN_GetFullHandle( parent );
2677 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2678 ret = list[i] && list[i+1];
2679 HeapFree( GetProcessHeap(), 0, list );
2684 /***********************************************************************
2685 * IsWindowVisible (USER32.@)
2687 BOOL WINAPI IsWindowVisible( HWND hwnd )
2693 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2694 if (!(list = list_window_parents( hwnd ))) return TRUE;
2695 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2697 for (i = 0; list[i+1]; i++)
2698 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2699 retval = !list[i+1];
2701 HeapFree( GetProcessHeap(), 0, list );
2706 /***********************************************************************
2707 * WIN_IsWindowDrawable
2709 * hwnd is drawable when it is visible, all parents are not
2710 * minimized, and it is itself not minimized unless we are
2711 * trying to draw its default class icon.
2713 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2718 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2720 if (!(style & WS_VISIBLE)) return FALSE;
2721 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2723 if (!(list = list_window_parents( hwnd ))) return TRUE;
2724 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2726 for (i = 0; list[i+1]; i++)
2727 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2729 retval = !list[i+1];
2731 HeapFree( GetProcessHeap(), 0, list );
2736 /*******************************************************************
2737 * GetTopWindow (USER32.@)
2739 HWND WINAPI GetTopWindow( HWND hwnd )
2741 if (!hwnd) hwnd = GetDesktopWindow();
2742 return GetWindow( hwnd, GW_CHILD );
2746 /*******************************************************************
2747 * GetWindow (USER32.@)
2749 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2753 if (rel == GW_OWNER) /* this one may be available locally */
2755 WND *wndPtr = WIN_GetPtr( hwnd );
2758 SetLastError( ERROR_INVALID_HANDLE );
2761 if (wndPtr == WND_DESKTOP) return 0;
2762 if (wndPtr != WND_OTHER_PROCESS)
2764 retval = wndPtr->owner;
2765 WIN_ReleasePtr( wndPtr );
2768 /* else fall through to server call */
2771 SERVER_START_REQ( get_window_tree )
2774 if (!wine_server_call_err( req ))
2779 retval = reply->first_sibling;
2782 retval = reply->last_sibling;
2785 retval = reply->next_sibling;
2788 retval = reply->prev_sibling;
2791 retval = reply->owner;
2794 retval = reply->first_child;
2804 /*******************************************************************
2805 * ShowOwnedPopups (USER32.@)
2807 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2811 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2813 if (!win_array) return TRUE;
2815 while (win_array[count]) count++;
2816 while (--count >= 0)
2818 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2819 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2820 if (pWnd == WND_OTHER_PROCESS) continue;
2823 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2825 WIN_ReleasePtr( pWnd );
2826 /* In Windows, ShowOwnedPopups(TRUE) generates
2827 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2828 * regardless of the state of the owner
2830 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2836 if (pWnd->dwStyle & WS_VISIBLE)
2838 WIN_ReleasePtr( pWnd );
2839 /* In Windows, ShowOwnedPopups(FALSE) generates
2840 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2841 * regardless of the state of the owner
2843 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2847 WIN_ReleasePtr( pWnd );
2849 HeapFree( GetProcessHeap(), 0, win_array );
2854 /*******************************************************************
2855 * GetLastActivePopup (USER32.@)
2857 HWND WINAPI GetLastActivePopup( HWND hwnd )
2861 SERVER_START_REQ( get_window_info )
2864 if (!wine_server_call_err( req )) retval = reply->last_active;
2871 /*******************************************************************
2874 * Build an array of the children of a given window. The array must be
2875 * freed with HeapFree. Returns NULL when no windows are found.
2877 HWND *WIN_ListChildren( HWND hwnd )
2879 return list_window_children( 0, hwnd, NULL, 0 );
2883 /*******************************************************************
2884 * EnumWindows (USER32.@)
2886 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2892 USER_CheckNotLock();
2894 /* We have to build a list of all windows first, to avoid */
2895 /* unpleasant side-effects, for instance if the callback */
2896 /* function changes the Z-order of the windows. */
2898 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2900 /* Now call the callback function for every window */
2902 for (i = 0; list[i]; i++)
2904 /* Make sure that the window still exists */
2905 if (!IsWindow( list[i] )) continue;
2906 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2908 HeapFree( GetProcessHeap(), 0, list );
2913 /**********************************************************************
2914 * EnumThreadWindows (USER32.@)
2916 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2921 USER_CheckNotLock();
2923 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
2925 /* Now call the callback function for every window */
2927 for (i = 0; list[i]; i++)
2928 if (!func( list[i], lParam )) break;
2929 HeapFree( GetProcessHeap(), 0, list );
2934 /***********************************************************************
2935 * EnumDesktopWindows (USER32.@)
2937 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
2942 USER_CheckNotLock();
2944 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
2946 for (i = 0; list[i]; i++)
2947 if (!func( list[i], lparam )) break;
2948 HeapFree( GetProcessHeap(), 0, list );
2953 /**********************************************************************
2954 * WIN_EnumChildWindows
2956 * Helper function for EnumChildWindows().
2958 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2963 for ( ; *list; list++)
2965 /* Make sure that the window still exists */
2966 if (!IsWindow( *list )) continue;
2967 /* Build children list first */
2968 childList = WIN_ListChildren( *list );
2970 ret = func( *list, lParam );
2974 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2975 HeapFree( GetProcessHeap(), 0, childList );
2977 if (!ret) return FALSE;
2983 /**********************************************************************
2984 * EnumChildWindows (USER32.@)
2986 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2991 USER_CheckNotLock();
2993 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2994 ret = WIN_EnumChildWindows( list, func, lParam );
2995 HeapFree( GetProcessHeap(), 0, list );
3000 /*******************************************************************
3001 * AnyPopup (USER.52)
3003 BOOL16 WINAPI AnyPopup16(void)
3009 /*******************************************************************
3010 * AnyPopup (USER32.@)
3012 BOOL WINAPI AnyPopup(void)
3016 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3018 if (!list) return FALSE;
3019 for (i = 0; list[i]; i++)
3021 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3023 retvalue = (list[i] != 0);
3024 HeapFree( GetProcessHeap(), 0, list );
3029 /*******************************************************************
3030 * FlashWindow (USER32.@)
3032 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3036 TRACE("%p\n", hWnd);
3038 if (IsIconic( hWnd ))
3040 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3042 wndPtr = WIN_GetPtr(hWnd);
3043 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3044 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3046 wndPtr->flags |= WIN_NCACTIVATED;
3050 wndPtr->flags &= ~WIN_NCACTIVATED;
3052 WIN_ReleasePtr( wndPtr );
3059 wndPtr = WIN_GetPtr(hWnd);
3060 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3061 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3063 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3064 else wparam = (hWnd == GetForegroundWindow());
3066 WIN_ReleasePtr( wndPtr );
3067 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3072 /*******************************************************************
3073 * FlashWindowEx (USER32.@)
3075 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3077 FIXME("%p\n", pfwi);
3081 /*******************************************************************
3082 * GetWindowContextHelpId (USER32.@)
3084 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3087 WND *wnd = WIN_GetPtr( hwnd );
3088 if (!wnd || wnd == WND_DESKTOP) return 0;
3089 if (wnd == WND_OTHER_PROCESS)
3091 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3094 retval = wnd->helpContext;
3095 WIN_ReleasePtr( wnd );
3100 /*******************************************************************
3101 * SetWindowContextHelpId (USER32.@)
3103 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3105 WND *wnd = WIN_GetPtr( hwnd );
3106 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3107 if (wnd == WND_OTHER_PROCESS)
3109 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3112 wnd->helpContext = id;
3113 WIN_ReleasePtr( wnd );
3118 /*******************************************************************
3119 * DragDetect (USER32.@)
3121 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3125 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3126 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3128 rect.left = pt.x - wDragWidth;
3129 rect.right = pt.x + wDragWidth;
3131 rect.top = pt.y - wDragHeight;
3132 rect.bottom = pt.y + wDragHeight;
3138 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3140 if( msg.message == WM_LBUTTONUP )
3145 if( msg.message == WM_MOUSEMOVE )
3148 tmp.x = (short)LOWORD(msg.lParam);
3149 tmp.y = (short)HIWORD(msg.lParam);
3150 if( !PtInRect( &rect, tmp ))
3162 /******************************************************************************
3163 * GetWindowModuleFileNameA (USER32.@)
3165 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3167 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3168 hwnd, lpszFileName, cchFileNameMax);
3172 /******************************************************************************
3173 * GetWindowModuleFileNameW (USER32.@)
3175 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3177 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3178 hwnd, lpszFileName, cchFileNameMax);
3182 /******************************************************************************
3183 * GetWindowInfo (USER32.@)
3185 * Note: tests show that Windows doesn't check cbSize of the structure.
3187 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3189 if (!pwi) return FALSE;
3190 if (!IsWindow(hwnd)) return FALSE;
3192 GetWindowRect(hwnd, &pwi->rcWindow);
3193 GetClientRect(hwnd, &pwi->rcClient);
3194 /* translate to screen coordinates */
3195 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3197 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3198 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3199 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3201 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3202 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3204 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3205 pwi->wCreatorVersion = 0x0400;
3210 /******************************************************************************
3211 * SwitchDesktop (USER32.@)
3213 * NOTES: Sets the current input or interactive desktop.
3215 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3217 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3221 /*****************************************************************************
3222 * SetLayeredWindowAttributes (USER32.@)
3224 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey,
3225 BYTE bAlpha, DWORD dwFlags )
3227 FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3231 /*****************************************************************************
3232 * GetLayeredWindowAttributes (USER32.@)
3234 BOOL WINAPI GetLayeredWindowAttributes( HWND hWnd, COLORREF *prgbKey,
3235 BYTE *pbAlpha, DWORD *pdwFlags )
3237 FIXME("(%p,%p,%p,%p): stub!\n", hWnd, prgbKey, pbAlpha, pdwFlags);
3241 /*****************************************************************************
3242 * UpdateLayeredWindow (USER32.@)
3244 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3245 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3252 FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3253 hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3258 /* 64bit versions */
3260 #ifdef GetWindowLongPtrW
3261 #undef GetWindowLongPtrW
3264 #ifdef GetWindowLongPtrA
3265 #undef GetWindowLongPtrA
3268 #ifdef SetWindowLongPtrW
3269 #undef SetWindowLongPtrW
3272 #ifdef SetWindowLongPtrA
3273 #undef SetWindowLongPtrA
3276 /*****************************************************************************
3277 * GetWindowLongPtrW (USER32.@)
3279 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3281 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3284 /*****************************************************************************
3285 * GetWindowLongPtrA (USER32.@)
3287 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3289 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3292 /*****************************************************************************
3293 * SetWindowLongPtrW (USER32.@)
3295 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3297 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3300 /*****************************************************************************
3301 * SetWindowLongPtrA (USER32.@)
3303 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3305 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );