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/server.h"
31 #include "wine/unicode.h"
33 #include "user_private.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(win);
40 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
41 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
43 /**********************************************************************/
45 /* helper for Get/SetWindowLong */
46 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
48 if (size == sizeof(WORD))
51 memcpy( &ret, ptr, sizeof(ret) );
54 else if (size == sizeof(DWORD))
57 memcpy( &ret, ptr, sizeof(ret) );
63 memcpy( &ret, ptr, sizeof(ret) );
68 /* helper for Get/SetWindowLong */
69 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
71 if (size == sizeof(WORD))
74 memcpy( ptr, &newval, sizeof(newval) );
76 else if (size == sizeof(DWORD))
79 memcpy( ptr, &newval, sizeof(newval) );
83 memcpy( ptr, &val, sizeof(val) );
88 static void *user_handles[NB_USER_HANDLES];
90 /***********************************************************************
93 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
97 SERVER_START_REQ( alloc_user_handle )
99 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
105 UINT index = USER_HANDLE_TO_INDEX( handle );
107 assert( index < NB_USER_HANDLES );
108 ptr->handle = handle;
110 user_handles[index] = ptr;
116 /***********************************************************************
117 * get_user_handle_ptr
119 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
121 struct user_object *ptr;
122 WORD index = USER_HANDLE_TO_INDEX( handle );
124 if (index >= NB_USER_HANDLES) return NULL;
127 if ((ptr = user_handles[index]))
129 if (ptr->type == type &&
130 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
131 !HIWORD(handle) || HIWORD(handle) == 0xffff))
135 else ptr = OBJ_OTHER_PROCESS;
141 /***********************************************************************
142 * release_user_handle_ptr
144 void release_user_handle_ptr( void *ptr )
146 assert( ptr && ptr != OBJ_OTHER_PROCESS );
151 /***********************************************************************
154 void *free_user_handle( HANDLE handle, enum user_obj_type type )
156 struct user_object *ptr;
157 WORD index = USER_HANDLE_TO_INDEX( handle );
159 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
161 SERVER_START_REQ( free_user_handle )
163 req->handle = wine_server_user_handle( handle );
164 if (!wine_server_call( req )) user_handles[index] = NULL;
168 release_user_handle_ptr( ptr );
174 /***********************************************************************
175 * create_window_handle
177 * Create a window handle with the server.
179 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
180 HINSTANCE instance, BOOL unicode )
184 HWND handle = 0, full_parent = 0, full_owner = 0;
185 struct tagCLASS *class = NULL;
188 SERVER_START_REQ( create_window )
190 req->parent = wine_server_user_handle( parent );
191 req->owner = wine_server_user_handle( owner );
192 req->instance = wine_server_client_ptr( instance );
193 if (!(req->atom = get_int_atom_value( name )) && name)
194 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
195 if (!wine_server_call_err( req ))
197 handle = wine_server_ptr_handle( reply->handle );
198 full_parent = wine_server_ptr_handle( reply->parent );
199 full_owner = wine_server_ptr_handle( reply->owner );
200 extra_bytes = reply->extra;
201 class = wine_server_get_ptr( reply->class_ptr );
208 WARN( "error %d creating window\n", GetLastError() );
212 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
213 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
215 SERVER_START_REQ( destroy_window )
217 req->handle = wine_server_user_handle( handle );
218 wine_server_call( req );
221 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
225 if (!parent) /* if parent is 0 we don't have a desktop window yet */
227 struct user_thread_info *thread_info = get_user_thread_info();
229 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
231 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
232 else assert( full_parent == thread_info->top_window );
233 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
234 ERR( "failed to create desktop window\n" );
236 else /* HWND_MESSAGE parent */
238 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
244 index = USER_HANDLE_TO_INDEX(handle);
245 assert( index < NB_USER_HANDLES );
246 user_handles[index] = win;
247 win->obj.handle = handle;
248 win->obj.type = USER_WINDOW;
249 win->parent = full_parent;
250 win->owner = full_owner;
252 win->winproc = get_class_winproc( class );
253 win->cbWndExtra = extra_bytes;
254 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
259 /***********************************************************************
262 * Free a window handle.
264 static void free_window_handle( HWND hwnd )
266 struct user_object *ptr;
267 WORD index = USER_HANDLE_TO_INDEX(hwnd);
269 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
271 SERVER_START_REQ( destroy_window )
273 req->handle = wine_server_user_handle( hwnd );
274 if (!wine_server_call_err( req )) user_handles[index] = NULL;
278 release_user_handle_ptr( ptr );
279 HeapFree( GetProcessHeap(), 0, ptr );
284 /*******************************************************************
285 * list_window_children
287 * Build an array of the children of a given window. The array must be
288 * freed with HeapFree. Returns NULL when no windows are found.
290 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
294 ATOM atom = get_int_atom_value( class );
296 /* empty class is not the same as NULL class */
297 if (!atom && class && !class[0]) return NULL;
303 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
305 SERVER_START_REQ( get_window_children )
307 req->desktop = wine_server_obj_handle( desktop );
308 req->parent = wine_server_user_handle( hwnd );
311 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
312 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
313 if (!wine_server_call( req )) count = reply->count;
316 if (count && count < size)
318 /* start from the end since HWND is potentially larger than user_handle_t */
319 for (i = count - 1; i >= 0; i--)
320 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
324 HeapFree( GetProcessHeap(), 0, list );
326 size = count + 1; /* restart with a large enough buffer */
332 /*******************************************************************
333 * list_window_parents
335 * Build an array of all parents of a given window, starting with
336 * the immediate parent. The array must be freed with HeapFree.
338 static HWND *list_window_parents( HWND hwnd )
342 int i, pos = 0, size = 16, count = 0;
344 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
349 if (!(win = WIN_GetPtr( current ))) goto empty;
350 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
351 if (win == WND_DESKTOP)
353 if (!pos) goto empty;
357 list[pos] = current = win->parent;
358 WIN_ReleasePtr( win );
359 if (!current) return list;
360 if (++pos == size - 1)
362 /* need to grow the list */
363 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
364 if (!new_list) goto empty;
370 /* at least one parent belongs to another process, have to query the server */
375 SERVER_START_REQ( get_window_parents )
377 req->handle = wine_server_user_handle( hwnd );
378 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
379 if (!wine_server_call( req )) count = reply->count;
382 if (!count) goto empty;
385 /* start from the end since HWND is potentially larger than user_handle_t */
386 for (i = count - 1; i >= 0; i--)
387 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
391 HeapFree( GetProcessHeap(), 0, list );
393 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
397 HeapFree( GetProcessHeap(), 0, list );
402 /*******************************************************************
405 static void send_parent_notify( HWND hwnd, UINT msg )
407 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
408 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
410 HWND parent = GetParent(hwnd);
411 if (parent && parent != GetDesktopWindow())
412 SendMessageW( parent, WM_PARENTNOTIFY,
413 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
418 /*******************************************************************
419 * get_server_window_text
421 * Retrieve the window text from the server.
423 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
427 SERVER_START_REQ( get_window_text )
429 req->handle = wine_server_user_handle( hwnd );
430 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
431 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
434 text[len / sizeof(WCHAR)] = 0;
438 /*******************************************************************
439 * get_hwnd_message_parent
441 * Return the parent for HWND_MESSAGE windows.
443 HWND get_hwnd_message_parent(void)
445 struct user_thread_info *thread_info = get_user_thread_info();
447 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
448 return thread_info->msg_window;
452 /*******************************************************************
455 * Check if window is the desktop or the HWND_MESSAGE top parent.
457 BOOL is_desktop_window( HWND hwnd )
459 struct user_thread_info *thread_info = get_user_thread_info();
461 if (!hwnd) return FALSE;
462 if (hwnd == thread_info->top_window) return TRUE;
463 if (hwnd == thread_info->msg_window) return TRUE;
465 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
467 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
468 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
474 /***********************************************************************
477 * Return a pointer to the WND structure if local to the process,
478 * or WND_OTHER_PROCESS if handle may be valid in other process.
479 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
481 WND *WIN_GetPtr( HWND hwnd )
485 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
487 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
493 /***********************************************************************
494 * WIN_IsCurrentProcess
496 * Check whether a given window belongs to the current process (and return the full handle).
498 HWND WIN_IsCurrentProcess( HWND hwnd )
503 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
504 ret = ptr->obj.handle;
505 WIN_ReleasePtr( ptr );
510 /***********************************************************************
511 * WIN_IsCurrentThread
513 * Check whether a given window belongs to the current thread (and return the full handle).
515 HWND WIN_IsCurrentThread( HWND hwnd )
520 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
521 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
522 WIN_ReleasePtr( ptr );
527 /***********************************************************************
530 * Convert a possibly truncated window handle to a full 32-bit handle.
532 HWND WIN_GetFullHandle( HWND hwnd )
536 if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
537 if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
538 /* do sign extension for -2 and -3 */
539 if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
541 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
543 if (ptr == WND_DESKTOP)
545 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
546 else return get_hwnd_message_parent();
549 if (ptr != WND_OTHER_PROCESS)
551 hwnd = ptr->obj.handle;
552 WIN_ReleasePtr( ptr );
554 else /* may belong to another process */
556 SERVER_START_REQ( get_window_info )
558 req->handle = wine_server_user_handle( hwnd );
559 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
567 /***********************************************************************
570 * Change the owner of a window.
572 HWND WIN_SetOwner( HWND hwnd, HWND owner )
574 WND *win = WIN_GetPtr( hwnd );
577 if (!win || win == WND_DESKTOP) return 0;
578 if (win == WND_OTHER_PROCESS)
580 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
583 SERVER_START_REQ( set_window_owner )
585 req->handle = wine_server_user_handle( hwnd );
586 req->owner = wine_server_user_handle( owner );
587 if (!wine_server_call( req ))
589 win->owner = wine_server_ptr_handle( reply->full_owner );
590 ret = wine_server_ptr_handle( reply->prev_owner );
594 WIN_ReleasePtr( win );
599 /***********************************************************************
602 * Change the style of a window.
604 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
608 WND *win = WIN_GetPtr( hwnd );
610 if (!win || win == WND_DESKTOP) return 0;
611 if (win == WND_OTHER_PROCESS)
614 ERR( "cannot set style %x/%x on other process window %p\n",
615 set_bits, clear_bits, hwnd );
618 style.styleOld = win->dwStyle;
619 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
620 if (style.styleNew == style.styleOld)
622 WIN_ReleasePtr( win );
623 return style.styleNew;
625 SERVER_START_REQ( set_window_info )
627 req->handle = wine_server_user_handle( hwnd );
628 req->flags = SET_WIN_STYLE;
629 req->style = style.styleNew;
630 req->extra_offset = -1;
631 if ((ok = !wine_server_call( req )))
633 style.styleOld = reply->old_style;
634 win->dwStyle = style.styleNew;
638 WIN_ReleasePtr( win );
641 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
642 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
644 return style.styleOld;
648 /***********************************************************************
651 * Get the window and client rectangles.
653 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
655 WND *win = WIN_GetPtr( hwnd );
660 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
663 if (win == WND_DESKTOP)
666 rect.left = rect.top = 0;
667 if (hwnd == get_hwnd_message_parent())
674 rect.right = GetSystemMetrics(SM_CXSCREEN);
675 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
677 if (rectWindow) *rectWindow = rect;
678 if (rectClient) *rectClient = rect;
680 else if (win == WND_OTHER_PROCESS)
682 SERVER_START_REQ( get_window_rectangles )
684 req->handle = wine_server_user_handle( hwnd );
685 if ((ret = !wine_server_call_err( req )))
689 rectWindow->left = reply->window.left;
690 rectWindow->top = reply->window.top;
691 rectWindow->right = reply->window.right;
692 rectWindow->bottom = reply->window.bottom;
696 rectClient->left = reply->client.left;
697 rectClient->top = reply->client.top;
698 rectClient->right = reply->client.right;
699 rectClient->bottom = reply->client.bottom;
707 if (rectWindow) *rectWindow = win->rectWindow;
708 if (rectClient) *rectClient = win->rectClient;
709 WIN_ReleasePtr( win );
715 /***********************************************************************
718 * Destroy storage associated to a window. "Internals" p.358
720 LRESULT WIN_DestroyWindow( HWND hwnd )
724 HMENU menu = 0, sys_menu;
727 TRACE("%p\n", hwnd );
729 /* free child windows */
730 if ((list = WIN_ListChildren( hwnd )))
733 for (i = 0; list[i]; i++)
735 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
736 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
738 HeapFree( GetProcessHeap(), 0, list );
741 /* Unlink now so we won't bother with the children later on */
742 SERVER_START_REQ( set_parent )
744 req->handle = wine_server_user_handle( hwnd );
746 wine_server_call( req );
751 * Send the WM_NCDESTROY to the window being destroyed.
753 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
755 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
757 /* free resources associated with the window */
759 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
760 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
761 menu = (HMENU)wndPtr->wIDmenu;
762 sys_menu = wndPtr->hSysMenu;
763 free_dce( wndPtr->dce, hwnd );
765 icon_title = wndPtr->icon_title;
766 HeapFree( GetProcessHeap(), 0, wndPtr->text );
768 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
769 wndPtr->pScroll = NULL;
770 WIN_ReleasePtr( wndPtr );
772 if (icon_title) DestroyWindow( icon_title );
773 if (menu) DestroyMenu( menu );
774 if (sys_menu) DestroyMenu( sys_menu );
776 USER_Driver->pDestroyWindow( hwnd );
778 free_window_handle( hwnd );
783 /***********************************************************************
784 * destroy_thread_window
786 * Destroy a window upon exit of its thread.
788 static void destroy_thread_window( HWND hwnd )
792 HMENU menu = 0, sys_menu = 0;
795 /* free child windows */
797 if ((list = WIN_ListChildren( hwnd )))
800 for (i = 0; list[i]; i++)
802 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
803 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
805 HeapFree( GetProcessHeap(), 0, list );
808 /* destroy the client-side storage */
810 index = USER_HANDLE_TO_INDEX(hwnd);
811 if (index >= NB_USER_HANDLES) return;
813 if ((wndPtr = user_handles[index]))
815 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
816 sys_menu = wndPtr->hSysMenu;
817 free_dce( wndPtr->dce, hwnd );
818 user_handles[index] = NULL;
822 HeapFree( GetProcessHeap(), 0, wndPtr );
823 if (menu) DestroyMenu( menu );
824 if (sys_menu) DestroyMenu( sys_menu );
828 /***********************************************************************
829 * destroy_thread_child_windows
831 * Destroy child windows upon exit of its thread.
833 static void destroy_thread_child_windows( HWND hwnd )
838 if (WIN_IsCurrentThread( hwnd ))
840 destroy_thread_window( hwnd );
842 else if ((list = WIN_ListChildren( hwnd )))
844 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
845 HeapFree( GetProcessHeap(), 0, list );
850 /***********************************************************************
851 * WIN_DestroyThreadWindows
853 * Destroy all children of 'wnd' owned by the current thread.
855 void WIN_DestroyThreadWindows( HWND hwnd )
860 if (!(list = WIN_ListChildren( hwnd ))) return;
862 /* reset owners of top-level windows */
863 for (i = 0; list[i]; i++)
865 if (!WIN_IsCurrentThread( list[i] ))
867 HWND owner = GetWindow( list[i], GW_OWNER );
868 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
872 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
873 HeapFree( GetProcessHeap(), 0, list );
877 /***********************************************************************
880 * Fix the coordinates - Helper for WIN_CreateWindowEx.
881 * returns default show mode in sw.
883 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
885 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
888 if (cs->dwExStyle & WS_EX_MDICHILD)
892 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
893 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
895 TRACE("MDI child id %04x\n", id);
898 if (cs->style & (WS_CHILD | WS_POPUP))
900 if (cs->dwExStyle & WS_EX_MDICHILD)
902 if (IS_DEFAULT(cs->x))
907 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
908 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
912 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
913 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
916 else /* overlapped window */
919 MONITORINFO mon_info;
922 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
924 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
925 mon_info.cbSize = sizeof(mon_info);
926 GetMonitorInfoW( monitor, &mon_info );
927 GetStartupInfoW( &info );
929 if (IS_DEFAULT(cs->x))
931 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
932 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
933 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
936 if (IS_DEFAULT(cs->cx))
938 if (info.dwFlags & STARTF_USESIZE)
940 cs->cx = info.dwXSize;
941 cs->cy = info.dwYSize;
945 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
946 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
949 /* neither x nor cx are default. Check the y values .
950 * In the trace we see Outlook and Outlook Express using
951 * cy set to CW_USEDEFAULT when opening the address book.
953 else if (IS_DEFAULT(cs->cy))
955 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
956 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
962 /***********************************************************************
965 static void dump_window_styles( DWORD style, DWORD exstyle )
968 if(style & WS_POPUP) TRACE(" WS_POPUP");
969 if(style & WS_CHILD) TRACE(" WS_CHILD");
970 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
971 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
972 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
973 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
974 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
975 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
976 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
979 if(style & WS_BORDER) TRACE(" WS_BORDER");
980 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
982 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
983 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
984 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
985 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
986 if (style & WS_CHILD)
988 if(style & WS_GROUP) TRACE(" WS_GROUP");
989 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
993 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
994 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
997 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
998 #define DUMPED_STYLES \
1018 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1020 #undef DUMPED_STYLES
1022 TRACE( "exstyle:" );
1023 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1024 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1025 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1026 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1027 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1028 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1029 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1030 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1031 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1032 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1033 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1034 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1035 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1036 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1037 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1038 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1039 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1040 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1042 #define DUMPED_EX_STYLES \
1043 (WS_EX_DLGMODALFRAME | \
1044 WS_EX_DRAGDETECT | \
1045 WS_EX_NOPARENTNOTIFY | \
1047 WS_EX_ACCEPTFILES | \
1048 WS_EX_TRANSPARENT | \
1050 WS_EX_TOOLWINDOW | \
1051 WS_EX_WINDOWEDGE | \
1052 WS_EX_CLIENTEDGE | \
1053 WS_EX_CONTEXTHELP | \
1055 WS_EX_RTLREADING | \
1056 WS_EX_LEFTSCROLLBAR | \
1057 WS_EX_CONTROLPARENT | \
1058 WS_EX_STATICEDGE | \
1062 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1064 #undef DUMPED_EX_STYLES
1068 /***********************************************************************
1069 * WIN_CreateWindowEx
1071 * Implementation of CreateWindowEx().
1073 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1075 INT cx, cy, style, sw = SW_SHOW;
1079 HWND hwnd, parent, owner, top_child = 0;
1080 MDICREATESTRUCTW mdi_cs;
1081 CBT_CREATEWNDW cbtc;
1084 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1085 unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1086 debugstr_w(className),
1087 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1088 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1089 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1091 /* Fix the styles for MDI children */
1092 if (cs->dwExStyle & WS_EX_MDICHILD)
1096 wndPtr = WIN_GetPtr(cs->hwndParent);
1097 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1099 flags = wndPtr->flags;
1100 WIN_ReleasePtr(wndPtr);
1103 if (!(flags & WIN_ISMDICLIENT))
1105 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1109 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1110 * MDICREATESTRUCT members have the originally passed values.
1112 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1113 * have the same layout.
1115 mdi_cs.szClass = cs->lpszClass;
1116 mdi_cs.szTitle = cs->lpszName;
1117 mdi_cs.hOwner = cs->hInstance;
1122 mdi_cs.style = cs->style;
1123 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1125 cs->lpCreateParams = &mdi_cs;
1127 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1129 if (cs->style & WS_POPUP)
1131 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1134 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1138 cs->style &= ~WS_POPUP;
1139 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1140 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1143 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1147 /* Restore current maximized child */
1148 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1150 TRACE("Restoring current maximized child %p\n", top_child);
1151 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1152 ShowWindow( top_child, SW_SHOWNORMAL );
1153 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1158 /* Find the parent window */
1160 parent = cs->hwndParent;
1163 if (cs->hwndParent == HWND_MESSAGE)
1165 cs->hwndParent = parent = get_hwnd_message_parent();
1167 else if (cs->hwndParent)
1169 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1171 parent = GetDesktopWindow();
1172 owner = cs->hwndParent;
1177 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1179 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1181 WARN("No parent for child window\n" );
1182 SetLastError(ERROR_TLW_WITH_WSCHILD);
1183 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1185 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1186 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1187 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1188 parent = GetDesktopWindow();
1191 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1193 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1194 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1195 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1196 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1198 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1200 /* Create the window structure */
1202 if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1204 hwnd = wndPtr->obj.handle;
1206 /* Fill the window structure */
1208 wndPtr->tid = GetCurrentThreadId();
1209 wndPtr->hInstance = cs->hInstance;
1210 wndPtr->text = NULL;
1211 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1212 wndPtr->dwExStyle = cs->dwExStyle;
1213 wndPtr->wIDmenu = 0;
1214 wndPtr->helpContext = 0;
1215 wndPtr->pScroll = NULL;
1216 wndPtr->userdata = 0;
1218 wndPtr->hIconSmall = 0;
1219 wndPtr->hSysMenu = 0;
1221 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1222 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1224 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1227 * Correct the window styles.
1229 * It affects only the style loaded into the WIN structure.
1232 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1234 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1235 if (!(wndPtr->dwStyle & WS_POPUP))
1236 wndPtr->dwStyle |= WS_CAPTION;
1240 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1241 * why does the user get to set it?
1244 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1245 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1246 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1248 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1250 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1251 wndPtr->flags |= WIN_NEED_SIZE;
1253 SERVER_START_REQ( set_window_info )
1255 req->handle = wine_server_user_handle( hwnd );
1256 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1257 req->style = wndPtr->dwStyle;
1258 req->ex_style = wndPtr->dwExStyle;
1259 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1260 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1261 req->extra_offset = -1;
1262 wine_server_call( req );
1266 /* Set the window menu */
1268 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1272 if (!MENU_SetMenu(hwnd, cs->hMenu))
1274 WIN_ReleasePtr( wndPtr );
1275 free_window_handle( hwnd );
1281 LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1284 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1285 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1289 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1291 /* call the WH_CBT hook */
1293 /* the window style passed to the hook must be the real window style,
1294 * rather than just the window style that the caller to CreateWindowEx
1295 * passed in, so we have to copy the original CREATESTRUCT and get the
1296 * the real style. */
1298 cbcs.style = wndPtr->dwStyle;
1300 cbtc.hwndInsertAfter = HWND_TOP;
1301 WIN_ReleasePtr( wndPtr );
1302 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1304 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1308 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1310 POINT maxSize, maxPos, minTrack, maxTrack;
1311 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1312 if (maxTrack.x < cx) cx = maxTrack.x;
1313 if (maxTrack.y < cy) cy = maxTrack.y;
1314 if (minTrack.x > cx) cx = minTrack.x;
1315 if (minTrack.y > cy) cy = minTrack.y;
1320 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1321 /* check for wraparound */
1322 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1323 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1324 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1326 /* send WM_NCCREATE */
1328 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1330 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1332 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1335 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1339 /* send WM_NCCALCSIZE */
1341 if ((wndPtr = WIN_GetPtr(hwnd)))
1343 /* yes, even if the CBT hook was called with HWND_TOP */
1345 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1346 RECT window_rect = wndPtr->rectWindow;
1347 RECT client_rect = window_rect;
1348 WIN_ReleasePtr( wndPtr );
1350 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1352 MapWindowPoints( parent, 0, &pt, 1 );
1353 OffsetRect( &client_rect, pt.x, pt.y );
1354 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1355 OffsetRect( &client_rect, -pt.x, -pt.y );
1356 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1360 /* send WM_CREATE */
1363 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1365 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1366 if (result == -1) goto failed;
1368 /* call the driver */
1370 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1372 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1374 /* send the size messages */
1376 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1377 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1378 if (!(wndPtr->flags & WIN_NEED_SIZE))
1380 rect = wndPtr->rectClient;
1381 WIN_ReleasePtr( wndPtr );
1382 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1383 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1384 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1386 else WIN_ReleasePtr( wndPtr );
1388 /* Show the window, maximizing or minimizing if needed */
1390 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1391 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1394 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1396 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1397 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1398 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1399 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1400 newPos.bottom - newPos.top, swFlag );
1403 /* Notify the parent window only */
1405 send_parent_notify( hwnd, WM_CREATE );
1406 if (!IsWindow( hwnd )) return 0;
1408 if (cs->style & WS_VISIBLE)
1410 if (cs->style & WS_MAXIMIZE)
1412 else if (cs->style & WS_MINIMIZE)
1413 sw = SW_SHOWMINIMIZED;
1415 ShowWindow( hwnd, sw );
1416 if (cs->dwExStyle & WS_EX_MDICHILD)
1418 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1419 /* ShowWindow won't activate child windows */
1420 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1424 /* Call WH_SHELL hook */
1426 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1427 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1429 TRACE("created window %p\n", hwnd);
1433 WIN_DestroyWindow( hwnd );
1438 /***********************************************************************
1439 * CreateWindowExA (USER32.@)
1441 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1442 LPCSTR windowName, DWORD style, INT x,
1443 INT y, INT width, INT height,
1444 HWND parent, HMENU menu,
1445 HINSTANCE instance, LPVOID data )
1449 cs.lpCreateParams = data;
1450 cs.hInstance = instance;
1452 cs.hwndParent = parent;
1458 cs.lpszName = windowName;
1459 cs.lpszClass = className;
1460 cs.dwExStyle = exStyle;
1462 if (!IS_INTRESOURCE(className))
1465 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1467 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1469 /* Note: we rely on the fact that CREATESTRUCTA and */
1470 /* CREATESTRUCTW have the same layout. */
1471 return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1475 /***********************************************************************
1476 * CreateWindowExW (USER32.@)
1478 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1479 LPCWSTR windowName, DWORD style, INT x,
1480 INT y, INT width, INT height,
1481 HWND parent, HMENU menu,
1482 HINSTANCE instance, LPVOID data )
1486 cs.lpCreateParams = data;
1487 cs.hInstance = instance;
1489 cs.hwndParent = parent;
1495 cs.lpszName = windowName;
1496 cs.lpszClass = className;
1497 cs.dwExStyle = exStyle;
1499 return wow_handlers.create_window( &cs, className, instance, TRUE );
1503 /***********************************************************************
1504 * WIN_SendDestroyMsg
1506 static void WIN_SendDestroyMsg( HWND hwnd )
1510 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1512 if (hwnd == info.hwndCaret) DestroyCaret();
1513 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1517 * Send the WM_DESTROY to the window.
1519 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1522 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1523 * make sure that the window still exists when we come back.
1530 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1532 for (i = 0; pWndArray[i]; i++)
1534 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1536 HeapFree( GetProcessHeap(), 0, pWndArray );
1539 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1543 /***********************************************************************
1544 * DestroyWindow (USER32.@)
1546 BOOL WINAPI DestroyWindow( HWND hwnd )
1550 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1552 SetLastError( ERROR_ACCESS_DENIED );
1556 TRACE("(%p)\n", hwnd);
1560 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1562 if (MENU_IsMenuActive() == hwnd)
1565 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1569 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1570 send_parent_notify( hwnd, WM_DESTROY );
1572 else if (!GetWindow( hwnd, GW_OWNER ))
1574 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1575 /* FIXME: clean up palette - see "Internals" p.352 */
1578 if (!IsWindow(hwnd)) return TRUE;
1580 /* Hide the window */
1581 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1583 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1585 ShowWindow( hwnd, SW_HIDE );
1587 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1588 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1591 if (!IsWindow(hwnd)) return TRUE;
1593 /* Recursively destroy owned windows */
1600 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1603 for (i = 0; list[i]; i++)
1605 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1606 if (WIN_IsCurrentThread( list[i] ))
1608 DestroyWindow( list[i] );
1612 WIN_SetOwner( list[i], 0 );
1614 HeapFree( GetProcessHeap(), 0, list );
1616 if (!got_one) break;
1620 /* Send destroy messages */
1622 WIN_SendDestroyMsg( hwnd );
1623 if (!IsWindow( hwnd )) return TRUE;
1625 if (GetClipboardOwner() == hwnd)
1626 CLIPBOARD_ReleaseOwner();
1628 /* Destroy the window storage */
1630 WIN_DestroyWindow( hwnd );
1635 /***********************************************************************
1636 * CloseWindow (USER32.@)
1638 BOOL WINAPI CloseWindow( HWND hwnd )
1640 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1641 ShowWindow( hwnd, SW_MINIMIZE );
1646 /***********************************************************************
1647 * OpenIcon (USER32.@)
1649 BOOL WINAPI OpenIcon( HWND hwnd )
1651 if (!IsIconic( hwnd )) return FALSE;
1652 ShowWindow( hwnd, SW_SHOWNORMAL );
1657 /***********************************************************************
1658 * FindWindowExW (USER32.@)
1660 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1665 WCHAR *buffer = NULL;
1667 if (!parent && child) parent = GetDesktopWindow();
1668 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1672 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1673 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1676 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1680 child = WIN_GetFullHandle( child );
1681 while (list[i] && list[i] != child) i++;
1682 if (!list[i]) goto done;
1683 i++; /* start from next window */
1690 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1697 HeapFree( GetProcessHeap(), 0, list );
1698 HeapFree( GetProcessHeap(), 0, buffer );
1704 /***********************************************************************
1705 * FindWindowA (USER32.@)
1707 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1709 HWND ret = FindWindowExA( 0, 0, className, title );
1710 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1715 /***********************************************************************
1716 * FindWindowExA (USER32.@)
1718 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1720 LPWSTR titleW = NULL;
1725 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1726 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1727 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1730 if (!IS_INTRESOURCE(className))
1733 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1734 hwnd = FindWindowExW( parent, child, classW, titleW );
1738 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1741 HeapFree( GetProcessHeap(), 0, titleW );
1746 /***********************************************************************
1747 * FindWindowW (USER32.@)
1749 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1751 return FindWindowExW( 0, 0, className, title );
1755 /**********************************************************************
1756 * GetDesktopWindow (USER32.@)
1758 HWND WINAPI GetDesktopWindow(void)
1760 struct user_thread_info *thread_info = get_user_thread_info();
1762 if (thread_info->top_window) return thread_info->top_window;
1764 SERVER_START_REQ( get_desktop_window )
1767 if (!wine_server_call( req ))
1769 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1770 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1775 if (!thread_info->top_window)
1777 USEROBJECTFLAGS flags;
1778 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1779 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1781 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1782 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1784 PROCESS_INFORMATION pi;
1785 WCHAR windir[MAX_PATH];
1786 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1787 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1789 memset( &si, 0, sizeof(si) );
1791 si.dwFlags = STARTF_USESTDHANDLES;
1794 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1796 GetWindowsDirectoryW( windir, MAX_PATH );
1797 strcpyW( app, windir );
1798 strcatW( app, explorer );
1799 strcpyW( cmdline, app );
1800 strcatW( cmdline, args );
1801 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1802 NULL, windir, &si, &pi ))
1804 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1805 WaitForInputIdle( pi.hProcess, 10000 );
1806 CloseHandle( pi.hThread );
1807 CloseHandle( pi.hProcess );
1809 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1811 else TRACE( "not starting explorer since winstation is not visible\n" );
1813 SERVER_START_REQ( get_desktop_window )
1816 if (!wine_server_call( req ))
1818 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1819 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1825 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1826 ERR( "failed to create desktop window\n" );
1828 return thread_info->top_window;
1832 /*******************************************************************
1833 * EnableWindow (USER32.@)
1835 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1840 if (is_broadcast(hwnd))
1842 SetLastError( ERROR_INVALID_PARAMETER );
1846 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1847 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1851 TRACE("( %p, %d )\n", hwnd, enable);
1853 retvalue = !IsWindowEnabled( hwnd );
1855 if (enable && retvalue)
1857 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1858 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1860 else if (!enable && !retvalue)
1864 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1866 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1868 if (hwnd == GetFocus())
1869 SetFocus( 0 ); /* A disabled window can't have the focus */
1871 capture_wnd = GetCapture();
1872 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1873 ReleaseCapture(); /* A disabled window can't capture the mouse */
1875 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1881 /***********************************************************************
1882 * IsWindowEnabled (USER32.@)
1884 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1886 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1890 /***********************************************************************
1891 * IsWindowUnicode (USER32.@)
1893 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1896 BOOL retvalue = FALSE;
1898 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1900 if (wndPtr == WND_DESKTOP) return TRUE;
1902 if (wndPtr != WND_OTHER_PROCESS)
1904 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1905 WIN_ReleasePtr( wndPtr );
1909 SERVER_START_REQ( get_window_info )
1911 req->handle = wine_server_user_handle( hwnd );
1912 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1920 /**********************************************************************
1923 * Helper function for GetWindowLong().
1925 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1927 LONG_PTR retvalue = 0;
1930 if (offset == GWLP_HWNDPARENT)
1932 HWND parent = GetAncestor( hwnd, GA_PARENT );
1933 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1934 return (ULONG_PTR)parent;
1937 if (!(wndPtr = WIN_GetPtr( hwnd )))
1939 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1943 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1945 if (offset == GWLP_WNDPROC)
1947 SetLastError( ERROR_ACCESS_DENIED );
1950 SERVER_START_REQ( set_window_info )
1952 req->handle = wine_server_user_handle( hwnd );
1953 req->flags = 0; /* don't set anything, just retrieve */
1954 req->extra_offset = (offset >= 0) ? offset : -1;
1955 req->extra_size = (offset >= 0) ? size : 0;
1956 if (!wine_server_call_err( req ))
1960 case GWL_STYLE: retvalue = reply->old_style; break;
1961 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1962 case GWLP_ID: retvalue = reply->old_id; break;
1963 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1964 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1966 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1967 else SetLastError( ERROR_INVALID_INDEX );
1976 /* now we have a valid wndPtr */
1980 if (offset > (int)(wndPtr->cbWndExtra - size))
1982 WARN("Invalid offset %d\n", offset );
1983 WIN_ReleasePtr( wndPtr );
1984 SetLastError( ERROR_INVALID_INDEX );
1987 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1989 /* Special case for dialog window procedure */
1990 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1991 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1992 WIN_ReleasePtr( wndPtr );
1998 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1999 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2000 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2001 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2002 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2004 /* This looks like a hack only for the edit control (see tests). This makes these controls
2005 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2006 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2008 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2009 retvalue = (ULONG_PTR)wndPtr->winproc;
2011 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2014 WARN("Unknown offset %d\n", offset );
2015 SetLastError( ERROR_INVALID_INDEX );
2018 WIN_ReleasePtr(wndPtr);
2023 /**********************************************************************
2026 * Helper function for SetWindowLong().
2028 * 0 is the failure code. However, in the case of failure SetLastError
2029 * must be set to distinguish between a 0 return value and a failure.
2031 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2035 LONG_PTR retval = 0;
2038 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2040 if (is_broadcast(hwnd))
2042 SetLastError( ERROR_INVALID_PARAMETER );
2046 if (!(wndPtr = WIN_GetPtr( hwnd )))
2048 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2051 if (wndPtr == WND_DESKTOP)
2053 /* can't change anything on the desktop window */
2054 SetLastError( ERROR_ACCESS_DENIED );
2057 if (wndPtr == WND_OTHER_PROCESS)
2059 if (offset == GWLP_WNDPROC)
2061 SetLastError( ERROR_ACCESS_DENIED );
2064 if (offset > 32767 || offset < -32767)
2066 SetLastError( ERROR_INVALID_INDEX );
2069 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2072 /* first some special cases */
2078 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2079 style.styleNew = newval;
2080 WIN_ReleasePtr( wndPtr );
2081 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2082 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2083 newval = style.styleNew;
2085 case GWLP_HWNDPARENT:
2086 if (wndPtr->parent == GetDesktopWindow())
2088 WIN_ReleasePtr( wndPtr );
2089 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2093 WIN_ReleasePtr( wndPtr );
2094 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2099 UINT old_flags = wndPtr->flags;
2100 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2101 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2102 if (proc) wndPtr->winproc = proc;
2103 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2104 else wndPtr->flags &= ~WIN_ISUNICODE;
2105 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2107 WIN_ReleasePtr( wndPtr );
2110 /* update is_unicode flag on the server side */
2114 case GWLP_HINSTANCE:
2118 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2119 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2121 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2122 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2123 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2124 WIN_ReleasePtr( wndPtr );
2129 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2131 WARN("Invalid offset %d\n", offset );
2132 WIN_ReleasePtr( wndPtr );
2133 SetLastError( ERROR_INVALID_INDEX );
2136 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2138 /* already set to the same value */
2139 WIN_ReleasePtr( wndPtr );
2145 SERVER_START_REQ( set_window_info )
2147 req->handle = wine_server_user_handle( hwnd );
2148 req->extra_offset = -1;
2152 req->flags = SET_WIN_STYLE;
2153 req->style = newval;
2156 req->flags = SET_WIN_EXSTYLE;
2157 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2158 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2159 req->ex_style = newval;
2162 req->flags = SET_WIN_ID;
2165 case GWLP_HINSTANCE:
2166 req->flags = SET_WIN_INSTANCE;
2167 req->instance = wine_server_client_ptr( (void *)newval );
2170 req->flags = SET_WIN_UNICODE;
2171 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2174 req->flags = SET_WIN_USERDATA;
2175 req->user_data = newval;
2178 req->flags = SET_WIN_EXTRA;
2179 req->extra_offset = offset;
2180 req->extra_size = size;
2181 set_win_data( &req->extra_value, newval, size );
2183 if ((ok = !wine_server_call_err( req )))
2188 wndPtr->dwStyle = newval;
2189 retval = reply->old_style;
2192 wndPtr->dwExStyle = newval;
2193 retval = reply->old_ex_style;
2196 wndPtr->wIDmenu = newval;
2197 retval = reply->old_id;
2199 case GWLP_HINSTANCE:
2200 wndPtr->hInstance = (HINSTANCE)newval;
2201 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2206 wndPtr->userdata = newval;
2207 retval = reply->old_user_data;
2210 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2211 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2217 WIN_ReleasePtr( wndPtr );
2221 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2223 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2224 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2231 /**********************************************************************
2232 * GetWindowWord (USER32.@)
2234 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2239 case GWLP_HINSTANCE:
2240 case GWLP_HWNDPARENT:
2245 WARN("Invalid offset %d\n", offset );
2246 SetLastError( ERROR_INVALID_INDEX );
2251 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2255 /**********************************************************************
2256 * GetWindowLongA (USER32.@)
2258 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2260 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2264 /**********************************************************************
2265 * GetWindowLongW (USER32.@)
2267 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2269 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2273 /**********************************************************************
2274 * SetWindowWord (USER32.@)
2276 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2281 case GWLP_HINSTANCE:
2282 case GWLP_HWNDPARENT:
2287 WARN("Invalid offset %d\n", offset );
2288 SetLastError( ERROR_INVALID_INDEX );
2293 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2297 /**********************************************************************
2298 * SetWindowLongA (USER32.@)
2300 * See SetWindowLongW.
2302 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2304 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2308 /**********************************************************************
2309 * SetWindowLongW (USER32.@) Set window attribute
2311 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2312 * value in a window's extra memory.
2314 * The _hwnd_ parameter specifies the window. is the handle to a
2315 * window that has extra memory. The _newval_ parameter contains the
2316 * new attribute or extra memory value. If positive, the _offset_
2317 * parameter is the byte-addressed location in the window's extra
2318 * memory to set. If negative, _offset_ specifies the window
2319 * attribute to set, and should be one of the following values:
2321 * GWL_EXSTYLE The window's extended window style
2323 * GWL_STYLE The window's window style.
2325 * GWLP_WNDPROC Pointer to the window's window procedure.
2327 * GWLP_HINSTANCE The window's pplication instance handle.
2329 * GWLP_ID The window's identifier.
2331 * GWLP_USERDATA The window's user-specified data.
2333 * If the window is a dialog box, the _offset_ parameter can be one of
2334 * the following values:
2336 * DWLP_DLGPROC The address of the window's dialog box procedure.
2338 * DWLP_MSGRESULT The return value of a message
2339 * that the dialog box procedure processed.
2341 * DWLP_USER Application specific information.
2345 * If successful, returns the previous value located at _offset_. Otherwise,
2350 * Extra memory for a window class is specified by a nonzero cbWndExtra
2351 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2352 * time of class creation.
2354 * Using GWL_WNDPROC to set a new window procedure effectively creates
2355 * a window subclass. Use CallWindowProc() in the new windows procedure
2356 * to pass messages to the superclass's window procedure.
2358 * The user data is reserved for use by the application which created
2361 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2362 * instead, call the EnableWindow() function to change the window's
2365 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2366 * SetParent() instead.
2369 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2370 * it sends WM_STYLECHANGING before changing the settings
2371 * and WM_STYLECHANGED afterwards.
2372 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2374 LONG WINAPI SetWindowLongW(
2375 HWND hwnd, /* [in] window to alter */
2376 INT offset, /* [in] offset, in bytes, of location to alter */
2377 LONG newval /* [in] new value of location */
2379 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2383 /*******************************************************************
2384 * GetWindowTextA (USER32.@)
2386 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2390 if (!lpString) return 0;
2392 if (WIN_IsCurrentProcess( hwnd ))
2393 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2395 /* when window belongs to other process, don't send a message */
2396 if (nMaxCount <= 0) return 0;
2397 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2398 get_server_window_text( hwnd, buffer, nMaxCount );
2399 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2400 lpString[nMaxCount-1] = 0;
2401 HeapFree( GetProcessHeap(), 0, buffer );
2402 return strlen(lpString);
2406 /*******************************************************************
2407 * InternalGetWindowText (USER32.@)
2409 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2413 if (nMaxCount <= 0) return 0;
2414 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2415 if (win == WND_DESKTOP) lpString[0] = 0;
2416 else if (win != WND_OTHER_PROCESS)
2418 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2419 else lpString[0] = 0;
2420 WIN_ReleasePtr( win );
2424 get_server_window_text( hwnd, lpString, nMaxCount );
2426 return strlenW(lpString);
2430 /*******************************************************************
2431 * GetWindowTextW (USER32.@)
2433 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2435 if (!lpString) return 0;
2437 if (WIN_IsCurrentProcess( hwnd ))
2438 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2440 /* when window belongs to other process, don't send a message */
2441 if (nMaxCount <= 0) return 0;
2442 get_server_window_text( hwnd, lpString, nMaxCount );
2443 return strlenW(lpString);
2447 /*******************************************************************
2448 * SetWindowTextA (USER32.@)
2449 * SetWindowText (USER32.@)
2451 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2453 if (is_broadcast(hwnd))
2455 SetLastError( ERROR_INVALID_PARAMETER );
2458 if (!WIN_IsCurrentProcess( hwnd ))
2459 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2460 debugstr_a(lpString), hwnd );
2461 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2465 /*******************************************************************
2466 * SetWindowTextW (USER32.@)
2468 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2470 if (is_broadcast(hwnd))
2472 SetLastError( ERROR_INVALID_PARAMETER );
2475 if (!WIN_IsCurrentProcess( hwnd ))
2476 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2477 debugstr_w(lpString), hwnd );
2478 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2482 /*******************************************************************
2483 * GetWindowTextLengthA (USER32.@)
2485 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2487 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2490 /*******************************************************************
2491 * GetWindowTextLengthW (USER32.@)
2493 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2495 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2499 /*******************************************************************
2500 * IsWindow (USER32.@)
2502 BOOL WINAPI IsWindow( HWND hwnd )
2507 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2508 if (ptr == WND_DESKTOP) return TRUE;
2510 if (ptr != WND_OTHER_PROCESS)
2512 WIN_ReleasePtr( ptr );
2516 /* check other processes */
2517 SERVER_START_REQ( get_window_info )
2519 req->handle = wine_server_user_handle( hwnd );
2520 ret = !wine_server_call_err( req );
2527 /***********************************************************************
2528 * GetWindowThreadProcessId (USER32.@)
2530 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2535 if (!(ptr = WIN_GetPtr( hwnd )))
2537 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2541 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2543 /* got a valid window */
2545 if (process) *process = GetCurrentProcessId();
2546 WIN_ReleasePtr( ptr );
2550 /* check other processes */
2551 SERVER_START_REQ( get_window_info )
2553 req->handle = wine_server_user_handle( hwnd );
2554 if (!wine_server_call_err( req ))
2556 tid = (DWORD)reply->tid;
2557 if (process) *process = (DWORD)reply->pid;
2565 /*****************************************************************
2566 * GetParent (USER32.@)
2568 HWND WINAPI GetParent( HWND hwnd )
2573 if (!(wndPtr = WIN_GetPtr( hwnd )))
2575 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2578 if (wndPtr == WND_DESKTOP) return 0;
2579 if (wndPtr == WND_OTHER_PROCESS)
2581 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2582 if (style & (WS_POPUP | WS_CHILD))
2584 SERVER_START_REQ( get_window_tree )
2586 req->handle = wine_server_user_handle( hwnd );
2587 if (!wine_server_call_err( req ))
2589 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2590 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2598 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2599 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2600 WIN_ReleasePtr( wndPtr );
2606 /*****************************************************************
2607 * GetAncestor (USER32.@)
2609 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2612 HWND *list, ret = 0;
2617 if (!(win = WIN_GetPtr( hwnd )))
2619 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2622 if (win == WND_DESKTOP) return 0;
2623 if (win != WND_OTHER_PROCESS)
2626 WIN_ReleasePtr( win );
2628 else /* need to query the server */
2630 SERVER_START_REQ( get_window_tree )
2632 req->handle = wine_server_user_handle( hwnd );
2633 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2640 if (!(list = list_window_parents( hwnd ))) return 0;
2642 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2646 while (list[count]) count++;
2647 ret = list[count - 2]; /* get the one before the desktop */
2649 HeapFree( GetProcessHeap(), 0, list );
2653 if (is_desktop_window( hwnd )) return 0;
2654 ret = WIN_GetFullHandle( hwnd );
2657 HWND parent = GetParent( ret );
2667 /*****************************************************************
2668 * SetParent (USER32.@)
2670 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2673 HWND old_parent = 0;
2678 if (is_broadcast(hwnd) || is_broadcast(parent))
2680 SetLastError(ERROR_INVALID_PARAMETER);
2684 if (!parent) parent = GetDesktopWindow();
2685 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2686 else parent = WIN_GetFullHandle( parent );
2688 if (!IsWindow( parent ))
2690 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2694 /* Some applications try to set a child as a parent */
2695 if (IsChild(hwnd, parent))
2697 SetLastError( ERROR_INVALID_PARAMETER );
2701 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2702 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2704 if (full_handle == parent)
2706 SetLastError( ERROR_INVALID_PARAMETER );
2710 /* Windows hides the window first, then shows it again
2711 * including the WM_SHOWWINDOW messages and all */
2712 was_visible = ShowWindow( hwnd, SW_HIDE );
2714 wndPtr = WIN_GetPtr( hwnd );
2715 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2717 SERVER_START_REQ( set_parent )
2719 req->handle = wine_server_user_handle( hwnd );
2720 req->parent = wine_server_user_handle( parent );
2721 if ((ret = !wine_server_call( req )))
2723 old_parent = wine_server_ptr_handle( reply->old_parent );
2724 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2729 WIN_ReleasePtr( wndPtr );
2732 USER_Driver->pSetParent( full_handle, parent, old_parent );
2734 /* SetParent additionally needs to make hwnd the topmost window
2735 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2736 WM_WINDOWPOSCHANGED notification messages.
2738 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2739 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2740 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2741 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2747 /*******************************************************************
2748 * IsChild (USER32.@)
2750 BOOL WINAPI IsChild( HWND parent, HWND child )
2752 HWND *list = list_window_parents( child );
2756 if (!list) return FALSE;
2757 parent = WIN_GetFullHandle( parent );
2758 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2759 ret = list[i] && list[i+1];
2760 HeapFree( GetProcessHeap(), 0, list );
2765 /***********************************************************************
2766 * IsWindowVisible (USER32.@)
2768 BOOL WINAPI IsWindowVisible( HWND hwnd )
2774 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2775 if (!(list = list_window_parents( hwnd ))) return TRUE;
2778 for (i = 0; list[i+1]; i++)
2779 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2780 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2782 HeapFree( GetProcessHeap(), 0, list );
2787 /***********************************************************************
2788 * WIN_IsWindowDrawable
2790 * hwnd is drawable when it is visible, all parents are not
2791 * minimized, and it is itself not minimized unless we are
2792 * trying to draw its default class icon.
2794 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2799 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2801 if (!(style & WS_VISIBLE)) return FALSE;
2802 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2804 if (!(list = list_window_parents( hwnd ))) return TRUE;
2807 for (i = 0; list[i+1]; i++)
2808 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2810 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2812 HeapFree( GetProcessHeap(), 0, list );
2817 /*******************************************************************
2818 * GetTopWindow (USER32.@)
2820 HWND WINAPI GetTopWindow( HWND hwnd )
2822 if (!hwnd) hwnd = GetDesktopWindow();
2823 return GetWindow( hwnd, GW_CHILD );
2827 /*******************************************************************
2828 * GetWindow (USER32.@)
2830 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2834 if (rel == GW_OWNER) /* this one may be available locally */
2836 WND *wndPtr = WIN_GetPtr( hwnd );
2839 SetLastError( ERROR_INVALID_HANDLE );
2842 if (wndPtr == WND_DESKTOP) return 0;
2843 if (wndPtr != WND_OTHER_PROCESS)
2845 retval = wndPtr->owner;
2846 WIN_ReleasePtr( wndPtr );
2849 /* else fall through to server call */
2852 SERVER_START_REQ( get_window_tree )
2854 req->handle = wine_server_user_handle( hwnd );
2855 if (!wine_server_call_err( req ))
2860 retval = wine_server_ptr_handle( reply->first_sibling );
2863 retval = wine_server_ptr_handle( reply->last_sibling );
2866 retval = wine_server_ptr_handle( reply->next_sibling );
2869 retval = wine_server_ptr_handle( reply->prev_sibling );
2872 retval = wine_server_ptr_handle( reply->owner );
2875 retval = wine_server_ptr_handle( reply->first_child );
2885 /*******************************************************************
2886 * ShowOwnedPopups (USER32.@)
2888 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2892 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2894 if (!win_array) return TRUE;
2896 while (win_array[count]) count++;
2897 while (--count >= 0)
2899 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2900 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2901 if (pWnd == WND_OTHER_PROCESS) continue;
2904 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2906 WIN_ReleasePtr( pWnd );
2907 /* In Windows, ShowOwnedPopups(TRUE) generates
2908 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2909 * regardless of the state of the owner
2911 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2917 if (pWnd->dwStyle & WS_VISIBLE)
2919 WIN_ReleasePtr( pWnd );
2920 /* In Windows, ShowOwnedPopups(FALSE) generates
2921 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2922 * regardless of the state of the owner
2924 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2928 WIN_ReleasePtr( pWnd );
2930 HeapFree( GetProcessHeap(), 0, win_array );
2935 /*******************************************************************
2936 * GetLastActivePopup (USER32.@)
2938 HWND WINAPI GetLastActivePopup( HWND hwnd )
2942 SERVER_START_REQ( get_window_info )
2944 req->handle = wine_server_user_handle( hwnd );
2945 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2952 /*******************************************************************
2955 * Build an array of the children of a given window. The array must be
2956 * freed with HeapFree. Returns NULL when no windows are found.
2958 HWND *WIN_ListChildren( HWND hwnd )
2962 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2965 return list_window_children( 0, hwnd, NULL, 0 );
2969 /*******************************************************************
2970 * EnumWindows (USER32.@)
2972 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2978 USER_CheckNotLock();
2980 /* We have to build a list of all windows first, to avoid */
2981 /* unpleasant side-effects, for instance if the callback */
2982 /* function changes the Z-order of the windows. */
2984 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2986 /* Now call the callback function for every window */
2988 for (i = 0; list[i]; i++)
2990 /* Make sure that the window still exists */
2991 if (!IsWindow( list[i] )) continue;
2992 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2994 HeapFree( GetProcessHeap(), 0, list );
2999 /**********************************************************************
3000 * EnumThreadWindows (USER32.@)
3002 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3008 USER_CheckNotLock();
3010 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3012 /* Now call the callback function for every window */
3014 for (i = 0; list[i]; i++)
3015 if (!(ret = func( list[i], lParam ))) break;
3016 HeapFree( GetProcessHeap(), 0, list );
3021 /***********************************************************************
3022 * EnumDesktopWindows (USER32.@)
3024 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3029 USER_CheckNotLock();
3031 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3033 for (i = 0; list[i]; i++)
3034 if (!func( list[i], lparam )) break;
3035 HeapFree( GetProcessHeap(), 0, list );
3040 /**********************************************************************
3041 * WIN_EnumChildWindows
3043 * Helper function for EnumChildWindows().
3045 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3050 for ( ; *list; list++)
3052 /* Make sure that the window still exists */
3053 if (!IsWindow( *list )) continue;
3054 /* Build children list first */
3055 childList = WIN_ListChildren( *list );
3057 ret = func( *list, lParam );
3061 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3062 HeapFree( GetProcessHeap(), 0, childList );
3064 if (!ret) return FALSE;
3070 /**********************************************************************
3071 * EnumChildWindows (USER32.@)
3073 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3078 USER_CheckNotLock();
3080 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3081 ret = WIN_EnumChildWindows( list, func, lParam );
3082 HeapFree( GetProcessHeap(), 0, list );
3087 /*******************************************************************
3088 * AnyPopup (USER32.@)
3090 BOOL WINAPI AnyPopup(void)
3094 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3096 if (!list) return FALSE;
3097 for (i = 0; list[i]; i++)
3099 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3101 retvalue = (list[i] != 0);
3102 HeapFree( GetProcessHeap(), 0, list );
3107 /*******************************************************************
3108 * FlashWindow (USER32.@)
3110 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3114 TRACE("%p\n", hWnd);
3116 if (IsIconic( hWnd ))
3118 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3120 wndPtr = WIN_GetPtr(hWnd);
3121 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3122 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3124 wndPtr->flags |= WIN_NCACTIVATED;
3128 wndPtr->flags &= ~WIN_NCACTIVATED;
3130 WIN_ReleasePtr( wndPtr );
3137 wndPtr = WIN_GetPtr(hWnd);
3138 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3139 hWnd = wndPtr->obj.handle; /* make it a full handle */
3141 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3142 else wparam = (hWnd == GetForegroundWindow());
3144 WIN_ReleasePtr( wndPtr );
3145 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3150 /*******************************************************************
3151 * FlashWindowEx (USER32.@)
3153 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3155 FIXME("%p\n", pfwi);
3159 /*******************************************************************
3160 * GetWindowContextHelpId (USER32.@)
3162 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3165 WND *wnd = WIN_GetPtr( hwnd );
3166 if (!wnd || wnd == WND_DESKTOP) return 0;
3167 if (wnd == WND_OTHER_PROCESS)
3169 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3172 retval = wnd->helpContext;
3173 WIN_ReleasePtr( wnd );
3178 /*******************************************************************
3179 * SetWindowContextHelpId (USER32.@)
3181 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3183 WND *wnd = WIN_GetPtr( hwnd );
3184 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3185 if (wnd == WND_OTHER_PROCESS)
3187 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3190 wnd->helpContext = id;
3191 WIN_ReleasePtr( wnd );
3196 /*******************************************************************
3197 * DragDetect (USER32.@)
3199 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3203 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3204 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3206 rect.left = pt.x - wDragWidth;
3207 rect.right = pt.x + wDragWidth;
3209 rect.top = pt.y - wDragHeight;
3210 rect.bottom = pt.y + wDragHeight;
3216 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3218 if( msg.message == WM_LBUTTONUP )
3223 if( msg.message == WM_MOUSEMOVE )
3226 tmp.x = (short)LOWORD(msg.lParam);
3227 tmp.y = (short)HIWORD(msg.lParam);
3228 if( !PtInRect( &rect, tmp ))
3240 /******************************************************************************
3241 * GetWindowModuleFileNameA (USER32.@)
3243 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3248 TRACE( "%p, %p, %u\n", hwnd, module, size );
3250 win = WIN_GetPtr( hwnd );
3251 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3253 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3256 hinst = win->hInstance;
3257 WIN_ReleasePtr( win );
3259 return GetModuleFileNameA( hinst, module, size );
3262 /******************************************************************************
3263 * GetWindowModuleFileNameW (USER32.@)
3265 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3270 TRACE( "%p, %p, %u\n", hwnd, module, size );
3272 win = WIN_GetPtr( hwnd );
3273 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3275 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3278 hinst = win->hInstance;
3279 WIN_ReleasePtr( win );
3281 return GetModuleFileNameW( hinst, module, size );
3284 /******************************************************************************
3285 * GetWindowInfo (USER32.@)
3287 * Note: tests show that Windows doesn't check cbSize of the structure.
3289 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3291 if (!pwi) return FALSE;
3292 if (!IsWindow(hwnd)) return FALSE;
3294 GetWindowRect(hwnd, &pwi->rcWindow);
3295 GetClientRect(hwnd, &pwi->rcClient);
3296 /* translate to screen coordinates */
3297 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3299 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3300 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3301 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3303 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3304 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3306 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3307 pwi->wCreatorVersion = 0x0400;
3312 /******************************************************************************
3313 * SwitchDesktop (USER32.@)
3315 * NOTES: Sets the current input or interactive desktop.
3317 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3319 FIXME("(hwnd %p) stub!\n", hDesktop);
3323 /*****************************************************************************
3324 * SetLayeredWindowAttributes (USER32.@)
3326 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3330 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3332 SERVER_START_REQ( set_window_layered_info )
3334 req->handle = wine_server_user_handle( hwnd );
3335 req->color_key = key;
3338 ret = !wine_server_call_err( req );
3342 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3348 /*****************************************************************************
3349 * GetLayeredWindowAttributes (USER32.@)
3351 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3355 SERVER_START_REQ( get_window_layered_info )
3357 req->handle = wine_server_user_handle( hwnd );
3358 if ((ret = !wine_server_call_err( req )))
3360 if (key) *key = reply->color_key;
3361 if (alpha) *alpha = reply->alpha;
3362 if (flags) *flags = reply->flags;
3371 /*****************************************************************************
3372 * UpdateLayeredWindowIndirect (USER32.@)
3374 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3378 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3380 int x = 0, y = 0, cx = 0, cy = 0;
3381 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3385 x = info->pptDst->x;
3386 y = info->pptDst->y;
3387 flags &= ~SWP_NOMOVE;
3391 cx = info->psize->cx;
3392 cy = info->psize->cy;
3393 flags &= ~SWP_NOSIZE;
3395 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3396 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3402 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3408 GetClientRect( hwnd, &rect );
3411 x = info->pptSrc->x;
3412 y = info->pptSrc->y;
3414 /* FIXME: intersect rect with info->prcDirty */
3415 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3416 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3417 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3418 ReleaseDC( hwnd, hdc );
3422 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3423 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3424 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3425 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3430 /*****************************************************************************
3431 * UpdateLayeredWindow (USER32.@)
3433 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3434 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3437 UPDATELAYEREDWINDOWINFO info;
3439 info.cbSize = sizeof(info);
3440 info.hdcDst = hdcDst;
3441 info.pptDst = pptDst;
3443 info.hdcSrc = hdcSrc;
3444 info.pptSrc = pptSrc;
3446 info.pblend = pblend;
3447 info.dwFlags = dwFlags;
3448 info.prcDirty = NULL;
3449 return UpdateLayeredWindowIndirect( hwnd, &info );
3452 /* 64bit versions */
3454 #ifdef GetWindowLongPtrW
3455 #undef GetWindowLongPtrW
3458 #ifdef GetWindowLongPtrA
3459 #undef GetWindowLongPtrA
3462 #ifdef SetWindowLongPtrW
3463 #undef SetWindowLongPtrW
3466 #ifdef SetWindowLongPtrA
3467 #undef SetWindowLongPtrA
3470 /*****************************************************************************
3471 * GetWindowLongPtrW (USER32.@)
3473 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3475 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3478 /*****************************************************************************
3479 * GetWindowLongPtrA (USER32.@)
3481 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3483 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3486 /*****************************************************************************
3487 * SetWindowLongPtrW (USER32.@)
3489 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3491 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3494 /*****************************************************************************
3495 * SetWindowLongPtrA (USER32.@)
3497 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3499 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );