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)];
1790 memset( &si, 0, sizeof(si) );
1792 si.dwFlags = STARTF_USESTDHANDLES;
1795 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1797 GetSystemDirectoryW( windir, MAX_PATH );
1798 strcpyW( app, windir );
1799 strcatW( app, explorer );
1800 strcpyW( cmdline, app );
1801 strcatW( cmdline, args );
1803 Wow64DisableWow64FsRedirection( &redir );
1804 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1805 NULL, windir, &si, &pi ))
1807 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1808 WaitForInputIdle( pi.hProcess, 10000 );
1809 CloseHandle( pi.hThread );
1810 CloseHandle( pi.hProcess );
1812 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1813 Wow64RevertWow64FsRedirection( redir );
1815 else TRACE( "not starting explorer since winstation is not visible\n" );
1817 SERVER_START_REQ( get_desktop_window )
1820 if (!wine_server_call( req ))
1822 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1823 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1829 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1830 ERR( "failed to create desktop window\n" );
1832 return thread_info->top_window;
1836 /*******************************************************************
1837 * EnableWindow (USER32.@)
1839 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1844 if (is_broadcast(hwnd))
1846 SetLastError( ERROR_INVALID_PARAMETER );
1850 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1851 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1855 TRACE("( %p, %d )\n", hwnd, enable);
1857 retvalue = !IsWindowEnabled( hwnd );
1859 if (enable && retvalue)
1861 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1862 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1864 else if (!enable && !retvalue)
1868 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1870 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1872 if (hwnd == GetFocus())
1873 SetFocus( 0 ); /* A disabled window can't have the focus */
1875 capture_wnd = GetCapture();
1876 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1877 ReleaseCapture(); /* A disabled window can't capture the mouse */
1879 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1885 /***********************************************************************
1886 * IsWindowEnabled (USER32.@)
1888 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1890 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1894 /***********************************************************************
1895 * IsWindowUnicode (USER32.@)
1897 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1900 BOOL retvalue = FALSE;
1902 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1904 if (wndPtr == WND_DESKTOP) return TRUE;
1906 if (wndPtr != WND_OTHER_PROCESS)
1908 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1909 WIN_ReleasePtr( wndPtr );
1913 SERVER_START_REQ( get_window_info )
1915 req->handle = wine_server_user_handle( hwnd );
1916 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1924 /**********************************************************************
1927 * Helper function for GetWindowLong().
1929 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1931 LONG_PTR retvalue = 0;
1934 if (offset == GWLP_HWNDPARENT)
1936 HWND parent = GetAncestor( hwnd, GA_PARENT );
1937 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1938 return (ULONG_PTR)parent;
1941 if (!(wndPtr = WIN_GetPtr( hwnd )))
1943 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1947 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1949 if (offset == GWLP_WNDPROC)
1951 SetLastError( ERROR_ACCESS_DENIED );
1954 SERVER_START_REQ( set_window_info )
1956 req->handle = wine_server_user_handle( hwnd );
1957 req->flags = 0; /* don't set anything, just retrieve */
1958 req->extra_offset = (offset >= 0) ? offset : -1;
1959 req->extra_size = (offset >= 0) ? size : 0;
1960 if (!wine_server_call_err( req ))
1964 case GWL_STYLE: retvalue = reply->old_style; break;
1965 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1966 case GWLP_ID: retvalue = reply->old_id; break;
1967 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1968 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1970 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1971 else SetLastError( ERROR_INVALID_INDEX );
1980 /* now we have a valid wndPtr */
1984 if (offset > (int)(wndPtr->cbWndExtra - size))
1986 WARN("Invalid offset %d\n", offset );
1987 WIN_ReleasePtr( wndPtr );
1988 SetLastError( ERROR_INVALID_INDEX );
1991 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1993 /* Special case for dialog window procedure */
1994 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1995 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1996 WIN_ReleasePtr( wndPtr );
2002 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2003 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2004 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2005 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2006 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2008 /* This looks like a hack only for the edit control (see tests). This makes these controls
2009 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2010 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2012 if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2013 retvalue = (ULONG_PTR)wndPtr->winproc;
2015 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2018 WARN("Unknown offset %d\n", offset );
2019 SetLastError( ERROR_INVALID_INDEX );
2022 WIN_ReleasePtr(wndPtr);
2027 /**********************************************************************
2030 * Helper function for SetWindowLong().
2032 * 0 is the failure code. However, in the case of failure SetLastError
2033 * must be set to distinguish between a 0 return value and a failure.
2035 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2039 LONG_PTR retval = 0;
2042 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2044 if (is_broadcast(hwnd))
2046 SetLastError( ERROR_INVALID_PARAMETER );
2050 if (!(wndPtr = WIN_GetPtr( hwnd )))
2052 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2055 if (wndPtr == WND_DESKTOP)
2057 /* can't change anything on the desktop window */
2058 SetLastError( ERROR_ACCESS_DENIED );
2061 if (wndPtr == WND_OTHER_PROCESS)
2063 if (offset == GWLP_WNDPROC)
2065 SetLastError( ERROR_ACCESS_DENIED );
2068 if (offset > 32767 || offset < -32767)
2070 SetLastError( ERROR_INVALID_INDEX );
2073 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2076 /* first some special cases */
2082 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2083 style.styleNew = newval;
2084 WIN_ReleasePtr( wndPtr );
2085 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2086 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2087 newval = style.styleNew;
2089 case GWLP_HWNDPARENT:
2090 if (wndPtr->parent == GetDesktopWindow())
2092 WIN_ReleasePtr( wndPtr );
2093 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2097 WIN_ReleasePtr( wndPtr );
2098 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2103 UINT old_flags = wndPtr->flags;
2104 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2105 proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2106 if (proc) wndPtr->winproc = proc;
2107 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2108 else wndPtr->flags &= ~WIN_ISUNICODE;
2109 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2111 WIN_ReleasePtr( wndPtr );
2114 /* update is_unicode flag on the server side */
2118 case GWLP_HINSTANCE:
2122 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2123 (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2125 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2126 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2127 *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2128 WIN_ReleasePtr( wndPtr );
2133 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2135 WARN("Invalid offset %d\n", offset );
2136 WIN_ReleasePtr( wndPtr );
2137 SetLastError( ERROR_INVALID_INDEX );
2140 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2142 /* already set to the same value */
2143 WIN_ReleasePtr( wndPtr );
2149 SERVER_START_REQ( set_window_info )
2151 req->handle = wine_server_user_handle( hwnd );
2152 req->extra_offset = -1;
2156 req->flags = SET_WIN_STYLE;
2157 req->style = newval;
2160 req->flags = SET_WIN_EXSTYLE;
2161 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2162 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2163 req->ex_style = newval;
2166 req->flags = SET_WIN_ID;
2169 case GWLP_HINSTANCE:
2170 req->flags = SET_WIN_INSTANCE;
2171 req->instance = wine_server_client_ptr( (void *)newval );
2174 req->flags = SET_WIN_UNICODE;
2175 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2178 req->flags = SET_WIN_USERDATA;
2179 req->user_data = newval;
2182 req->flags = SET_WIN_EXTRA;
2183 req->extra_offset = offset;
2184 req->extra_size = size;
2185 set_win_data( &req->extra_value, newval, size );
2187 if ((ok = !wine_server_call_err( req )))
2192 wndPtr->dwStyle = newval;
2193 retval = reply->old_style;
2196 wndPtr->dwExStyle = newval;
2197 retval = reply->old_ex_style;
2200 wndPtr->wIDmenu = newval;
2201 retval = reply->old_id;
2203 case GWLP_HINSTANCE:
2204 wndPtr->hInstance = (HINSTANCE)newval;
2205 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2210 wndPtr->userdata = newval;
2211 retval = reply->old_user_data;
2214 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2215 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2221 WIN_ReleasePtr( wndPtr );
2225 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2227 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2228 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2235 /**********************************************************************
2236 * GetWindowWord (USER32.@)
2238 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2243 case GWLP_HINSTANCE:
2244 case GWLP_HWNDPARENT:
2249 WARN("Invalid offset %d\n", offset );
2250 SetLastError( ERROR_INVALID_INDEX );
2255 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2259 /**********************************************************************
2260 * GetWindowLongA (USER32.@)
2262 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2264 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2268 /**********************************************************************
2269 * GetWindowLongW (USER32.@)
2271 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2273 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2277 /**********************************************************************
2278 * SetWindowWord (USER32.@)
2280 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2285 case GWLP_HINSTANCE:
2286 case GWLP_HWNDPARENT:
2291 WARN("Invalid offset %d\n", offset );
2292 SetLastError( ERROR_INVALID_INDEX );
2297 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2301 /**********************************************************************
2302 * SetWindowLongA (USER32.@)
2304 * See SetWindowLongW.
2306 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2308 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2312 /**********************************************************************
2313 * SetWindowLongW (USER32.@) Set window attribute
2315 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2316 * value in a window's extra memory.
2318 * The _hwnd_ parameter specifies the window. is the handle to a
2319 * window that has extra memory. The _newval_ parameter contains the
2320 * new attribute or extra memory value. If positive, the _offset_
2321 * parameter is the byte-addressed location in the window's extra
2322 * memory to set. If negative, _offset_ specifies the window
2323 * attribute to set, and should be one of the following values:
2325 * GWL_EXSTYLE The window's extended window style
2327 * GWL_STYLE The window's window style.
2329 * GWLP_WNDPROC Pointer to the window's window procedure.
2331 * GWLP_HINSTANCE The window's pplication instance handle.
2333 * GWLP_ID The window's identifier.
2335 * GWLP_USERDATA The window's user-specified data.
2337 * If the window is a dialog box, the _offset_ parameter can be one of
2338 * the following values:
2340 * DWLP_DLGPROC The address of the window's dialog box procedure.
2342 * DWLP_MSGRESULT The return value of a message
2343 * that the dialog box procedure processed.
2345 * DWLP_USER Application specific information.
2349 * If successful, returns the previous value located at _offset_. Otherwise,
2354 * Extra memory for a window class is specified by a nonzero cbWndExtra
2355 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2356 * time of class creation.
2358 * Using GWL_WNDPROC to set a new window procedure effectively creates
2359 * a window subclass. Use CallWindowProc() in the new windows procedure
2360 * to pass messages to the superclass's window procedure.
2362 * The user data is reserved for use by the application which created
2365 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2366 * instead, call the EnableWindow() function to change the window's
2369 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2370 * SetParent() instead.
2373 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2374 * it sends WM_STYLECHANGING before changing the settings
2375 * and WM_STYLECHANGED afterwards.
2376 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2378 LONG WINAPI SetWindowLongW(
2379 HWND hwnd, /* [in] window to alter */
2380 INT offset, /* [in] offset, in bytes, of location to alter */
2381 LONG newval /* [in] new value of location */
2383 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2387 /*******************************************************************
2388 * GetWindowTextA (USER32.@)
2390 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2394 if (!lpString) return 0;
2396 if (WIN_IsCurrentProcess( hwnd ))
2397 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2399 /* when window belongs to other process, don't send a message */
2400 if (nMaxCount <= 0) return 0;
2401 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2402 get_server_window_text( hwnd, buffer, nMaxCount );
2403 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2404 lpString[nMaxCount-1] = 0;
2405 HeapFree( GetProcessHeap(), 0, buffer );
2406 return strlen(lpString);
2410 /*******************************************************************
2411 * InternalGetWindowText (USER32.@)
2413 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2417 if (nMaxCount <= 0) return 0;
2418 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2419 if (win == WND_DESKTOP) lpString[0] = 0;
2420 else if (win != WND_OTHER_PROCESS)
2422 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2423 else lpString[0] = 0;
2424 WIN_ReleasePtr( win );
2428 get_server_window_text( hwnd, lpString, nMaxCount );
2430 return strlenW(lpString);
2434 /*******************************************************************
2435 * GetWindowTextW (USER32.@)
2437 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2439 if (!lpString) return 0;
2441 if (WIN_IsCurrentProcess( hwnd ))
2442 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2444 /* when window belongs to other process, don't send a message */
2445 if (nMaxCount <= 0) return 0;
2446 get_server_window_text( hwnd, lpString, nMaxCount );
2447 return strlenW(lpString);
2451 /*******************************************************************
2452 * SetWindowTextA (USER32.@)
2453 * SetWindowText (USER32.@)
2455 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2457 if (is_broadcast(hwnd))
2459 SetLastError( ERROR_INVALID_PARAMETER );
2462 if (!WIN_IsCurrentProcess( hwnd ))
2463 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2464 debugstr_a(lpString), hwnd );
2465 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2469 /*******************************************************************
2470 * SetWindowTextW (USER32.@)
2472 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2474 if (is_broadcast(hwnd))
2476 SetLastError( ERROR_INVALID_PARAMETER );
2479 if (!WIN_IsCurrentProcess( hwnd ))
2480 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2481 debugstr_w(lpString), hwnd );
2482 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2486 /*******************************************************************
2487 * GetWindowTextLengthA (USER32.@)
2489 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2491 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2494 /*******************************************************************
2495 * GetWindowTextLengthW (USER32.@)
2497 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2499 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2503 /*******************************************************************
2504 * IsWindow (USER32.@)
2506 BOOL WINAPI IsWindow( HWND hwnd )
2511 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2512 if (ptr == WND_DESKTOP) return TRUE;
2514 if (ptr != WND_OTHER_PROCESS)
2516 WIN_ReleasePtr( ptr );
2520 /* check other processes */
2521 SERVER_START_REQ( get_window_info )
2523 req->handle = wine_server_user_handle( hwnd );
2524 ret = !wine_server_call_err( req );
2531 /***********************************************************************
2532 * GetWindowThreadProcessId (USER32.@)
2534 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2539 if (!(ptr = WIN_GetPtr( hwnd )))
2541 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2545 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2547 /* got a valid window */
2549 if (process) *process = GetCurrentProcessId();
2550 WIN_ReleasePtr( ptr );
2554 /* check other processes */
2555 SERVER_START_REQ( get_window_info )
2557 req->handle = wine_server_user_handle( hwnd );
2558 if (!wine_server_call_err( req ))
2560 tid = (DWORD)reply->tid;
2561 if (process) *process = (DWORD)reply->pid;
2569 /*****************************************************************
2570 * GetParent (USER32.@)
2572 HWND WINAPI GetParent( HWND hwnd )
2577 if (!(wndPtr = WIN_GetPtr( hwnd )))
2579 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2582 if (wndPtr == WND_DESKTOP) return 0;
2583 if (wndPtr == WND_OTHER_PROCESS)
2585 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2586 if (style & (WS_POPUP | WS_CHILD))
2588 SERVER_START_REQ( get_window_tree )
2590 req->handle = wine_server_user_handle( hwnd );
2591 if (!wine_server_call_err( req ))
2593 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2594 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2602 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2603 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2604 WIN_ReleasePtr( wndPtr );
2610 /*****************************************************************
2611 * GetAncestor (USER32.@)
2613 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2616 HWND *list, ret = 0;
2621 if (!(win = WIN_GetPtr( hwnd )))
2623 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2626 if (win == WND_DESKTOP) return 0;
2627 if (win != WND_OTHER_PROCESS)
2630 WIN_ReleasePtr( win );
2632 else /* need to query the server */
2634 SERVER_START_REQ( get_window_tree )
2636 req->handle = wine_server_user_handle( hwnd );
2637 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2644 if (!(list = list_window_parents( hwnd ))) return 0;
2646 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2650 while (list[count]) count++;
2651 ret = list[count - 2]; /* get the one before the desktop */
2653 HeapFree( GetProcessHeap(), 0, list );
2657 if (is_desktop_window( hwnd )) return 0;
2658 ret = WIN_GetFullHandle( hwnd );
2661 HWND parent = GetParent( ret );
2671 /*****************************************************************
2672 * SetParent (USER32.@)
2674 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2677 HWND old_parent = 0;
2682 if (is_broadcast(hwnd) || is_broadcast(parent))
2684 SetLastError(ERROR_INVALID_PARAMETER);
2688 if (!parent) parent = GetDesktopWindow();
2689 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2690 else parent = WIN_GetFullHandle( parent );
2692 if (!IsWindow( parent ))
2694 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2698 /* Some applications try to set a child as a parent */
2699 if (IsChild(hwnd, parent))
2701 SetLastError( ERROR_INVALID_PARAMETER );
2705 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2706 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2708 if (full_handle == parent)
2710 SetLastError( ERROR_INVALID_PARAMETER );
2714 /* Windows hides the window first, then shows it again
2715 * including the WM_SHOWWINDOW messages and all */
2716 was_visible = ShowWindow( hwnd, SW_HIDE );
2718 wndPtr = WIN_GetPtr( hwnd );
2719 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2721 SERVER_START_REQ( set_parent )
2723 req->handle = wine_server_user_handle( hwnd );
2724 req->parent = wine_server_user_handle( parent );
2725 if ((ret = !wine_server_call( req )))
2727 old_parent = wine_server_ptr_handle( reply->old_parent );
2728 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2733 WIN_ReleasePtr( wndPtr );
2736 USER_Driver->pSetParent( full_handle, parent, old_parent );
2738 /* SetParent additionally needs to make hwnd the topmost window
2739 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2740 WM_WINDOWPOSCHANGED notification messages.
2742 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2743 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2744 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2745 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2751 /*******************************************************************
2752 * IsChild (USER32.@)
2754 BOOL WINAPI IsChild( HWND parent, HWND child )
2756 HWND *list = list_window_parents( child );
2760 if (!list) return FALSE;
2761 parent = WIN_GetFullHandle( parent );
2762 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2763 ret = list[i] && list[i+1];
2764 HeapFree( GetProcessHeap(), 0, list );
2769 /***********************************************************************
2770 * IsWindowVisible (USER32.@)
2772 BOOL WINAPI IsWindowVisible( HWND hwnd )
2778 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2779 if (!(list = list_window_parents( hwnd ))) return TRUE;
2782 for (i = 0; list[i+1]; i++)
2783 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2784 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2786 HeapFree( GetProcessHeap(), 0, list );
2791 /***********************************************************************
2792 * WIN_IsWindowDrawable
2794 * hwnd is drawable when it is visible, all parents are not
2795 * minimized, and it is itself not minimized unless we are
2796 * trying to draw its default class icon.
2798 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2803 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2805 if (!(style & WS_VISIBLE)) return FALSE;
2806 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2808 if (!(list = list_window_parents( hwnd ))) return TRUE;
2811 for (i = 0; list[i+1]; i++)
2812 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2814 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2816 HeapFree( GetProcessHeap(), 0, list );
2821 /*******************************************************************
2822 * GetTopWindow (USER32.@)
2824 HWND WINAPI GetTopWindow( HWND hwnd )
2826 if (!hwnd) hwnd = GetDesktopWindow();
2827 return GetWindow( hwnd, GW_CHILD );
2831 /*******************************************************************
2832 * GetWindow (USER32.@)
2834 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2838 if (rel == GW_OWNER) /* this one may be available locally */
2840 WND *wndPtr = WIN_GetPtr( hwnd );
2843 SetLastError( ERROR_INVALID_HANDLE );
2846 if (wndPtr == WND_DESKTOP) return 0;
2847 if (wndPtr != WND_OTHER_PROCESS)
2849 retval = wndPtr->owner;
2850 WIN_ReleasePtr( wndPtr );
2853 /* else fall through to server call */
2856 SERVER_START_REQ( get_window_tree )
2858 req->handle = wine_server_user_handle( hwnd );
2859 if (!wine_server_call_err( req ))
2864 retval = wine_server_ptr_handle( reply->first_sibling );
2867 retval = wine_server_ptr_handle( reply->last_sibling );
2870 retval = wine_server_ptr_handle( reply->next_sibling );
2873 retval = wine_server_ptr_handle( reply->prev_sibling );
2876 retval = wine_server_ptr_handle( reply->owner );
2879 retval = wine_server_ptr_handle( reply->first_child );
2889 /*******************************************************************
2890 * ShowOwnedPopups (USER32.@)
2892 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2896 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2898 if (!win_array) return TRUE;
2900 while (win_array[count]) count++;
2901 while (--count >= 0)
2903 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2904 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2905 if (pWnd == WND_OTHER_PROCESS) continue;
2908 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2910 WIN_ReleasePtr( pWnd );
2911 /* In Windows, ShowOwnedPopups(TRUE) generates
2912 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2913 * regardless of the state of the owner
2915 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2921 if (pWnd->dwStyle & WS_VISIBLE)
2923 WIN_ReleasePtr( pWnd );
2924 /* In Windows, ShowOwnedPopups(FALSE) generates
2925 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2926 * regardless of the state of the owner
2928 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2932 WIN_ReleasePtr( pWnd );
2934 HeapFree( GetProcessHeap(), 0, win_array );
2939 /*******************************************************************
2940 * GetLastActivePopup (USER32.@)
2942 HWND WINAPI GetLastActivePopup( HWND hwnd )
2946 SERVER_START_REQ( get_window_info )
2948 req->handle = wine_server_user_handle( hwnd );
2949 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2956 /*******************************************************************
2959 * Build an array of the children of a given window. The array must be
2960 * freed with HeapFree. Returns NULL when no windows are found.
2962 HWND *WIN_ListChildren( HWND hwnd )
2966 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2969 return list_window_children( 0, hwnd, NULL, 0 );
2973 /*******************************************************************
2974 * EnumWindows (USER32.@)
2976 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2982 USER_CheckNotLock();
2984 /* We have to build a list of all windows first, to avoid */
2985 /* unpleasant side-effects, for instance if the callback */
2986 /* function changes the Z-order of the windows. */
2988 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2990 /* Now call the callback function for every window */
2992 for (i = 0; list[i]; i++)
2994 /* Make sure that the window still exists */
2995 if (!IsWindow( list[i] )) continue;
2996 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2998 HeapFree( GetProcessHeap(), 0, list );
3003 /**********************************************************************
3004 * EnumThreadWindows (USER32.@)
3006 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3012 USER_CheckNotLock();
3014 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3016 /* Now call the callback function for every window */
3018 for (i = 0; list[i]; i++)
3019 if (!(ret = func( list[i], lParam ))) break;
3020 HeapFree( GetProcessHeap(), 0, list );
3025 /***********************************************************************
3026 * EnumDesktopWindows (USER32.@)
3028 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3033 USER_CheckNotLock();
3035 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3037 for (i = 0; list[i]; i++)
3038 if (!func( list[i], lparam )) break;
3039 HeapFree( GetProcessHeap(), 0, list );
3044 /**********************************************************************
3045 * WIN_EnumChildWindows
3047 * Helper function for EnumChildWindows().
3049 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3054 for ( ; *list; list++)
3056 /* Make sure that the window still exists */
3057 if (!IsWindow( *list )) continue;
3058 /* Build children list first */
3059 childList = WIN_ListChildren( *list );
3061 ret = func( *list, lParam );
3065 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3066 HeapFree( GetProcessHeap(), 0, childList );
3068 if (!ret) return FALSE;
3074 /**********************************************************************
3075 * EnumChildWindows (USER32.@)
3077 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3082 USER_CheckNotLock();
3084 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3085 ret = WIN_EnumChildWindows( list, func, lParam );
3086 HeapFree( GetProcessHeap(), 0, list );
3091 /*******************************************************************
3092 * AnyPopup (USER32.@)
3094 BOOL WINAPI AnyPopup(void)
3098 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3100 if (!list) return FALSE;
3101 for (i = 0; list[i]; i++)
3103 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3105 retvalue = (list[i] != 0);
3106 HeapFree( GetProcessHeap(), 0, list );
3111 /*******************************************************************
3112 * FlashWindow (USER32.@)
3114 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3118 TRACE("%p\n", hWnd);
3120 if (IsIconic( hWnd ))
3122 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3124 wndPtr = WIN_GetPtr(hWnd);
3125 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3126 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3128 wndPtr->flags |= WIN_NCACTIVATED;
3132 wndPtr->flags &= ~WIN_NCACTIVATED;
3134 WIN_ReleasePtr( wndPtr );
3141 wndPtr = WIN_GetPtr(hWnd);
3142 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3143 hWnd = wndPtr->obj.handle; /* make it a full handle */
3145 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3146 else wparam = (hWnd == GetForegroundWindow());
3148 WIN_ReleasePtr( wndPtr );
3149 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3154 /*******************************************************************
3155 * FlashWindowEx (USER32.@)
3157 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3159 FIXME("%p\n", pfwi);
3163 /*******************************************************************
3164 * GetWindowContextHelpId (USER32.@)
3166 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3169 WND *wnd = WIN_GetPtr( hwnd );
3170 if (!wnd || wnd == WND_DESKTOP) return 0;
3171 if (wnd == WND_OTHER_PROCESS)
3173 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3176 retval = wnd->helpContext;
3177 WIN_ReleasePtr( wnd );
3182 /*******************************************************************
3183 * SetWindowContextHelpId (USER32.@)
3185 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3187 WND *wnd = WIN_GetPtr( hwnd );
3188 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3189 if (wnd == WND_OTHER_PROCESS)
3191 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3194 wnd->helpContext = id;
3195 WIN_ReleasePtr( wnd );
3200 /*******************************************************************
3201 * DragDetect (USER32.@)
3203 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3207 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3208 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3210 rect.left = pt.x - wDragWidth;
3211 rect.right = pt.x + wDragWidth;
3213 rect.top = pt.y - wDragHeight;
3214 rect.bottom = pt.y + wDragHeight;
3220 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3222 if( msg.message == WM_LBUTTONUP )
3227 if( msg.message == WM_MOUSEMOVE )
3230 tmp.x = (short)LOWORD(msg.lParam);
3231 tmp.y = (short)HIWORD(msg.lParam);
3232 if( !PtInRect( &rect, tmp ))
3244 /******************************************************************************
3245 * GetWindowModuleFileNameA (USER32.@)
3247 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3252 TRACE( "%p, %p, %u\n", hwnd, module, size );
3254 win = WIN_GetPtr( hwnd );
3255 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3257 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3260 hinst = win->hInstance;
3261 WIN_ReleasePtr( win );
3263 return GetModuleFileNameA( hinst, module, size );
3266 /******************************************************************************
3267 * GetWindowModuleFileNameW (USER32.@)
3269 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3274 TRACE( "%p, %p, %u\n", hwnd, module, size );
3276 win = WIN_GetPtr( hwnd );
3277 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3279 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3282 hinst = win->hInstance;
3283 WIN_ReleasePtr( win );
3285 return GetModuleFileNameW( hinst, module, size );
3288 /******************************************************************************
3289 * GetWindowInfo (USER32.@)
3291 * Note: tests show that Windows doesn't check cbSize of the structure.
3293 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3295 if (!pwi) return FALSE;
3296 if (!IsWindow(hwnd)) return FALSE;
3298 GetWindowRect(hwnd, &pwi->rcWindow);
3299 GetClientRect(hwnd, &pwi->rcClient);
3300 /* translate to screen coordinates */
3301 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3303 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3304 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3305 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3307 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3308 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3310 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3311 pwi->wCreatorVersion = 0x0400;
3316 /******************************************************************************
3317 * SwitchDesktop (USER32.@)
3319 * NOTES: Sets the current input or interactive desktop.
3321 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3323 FIXME("(hwnd %p) stub!\n", hDesktop);
3327 /*****************************************************************************
3328 * SetLayeredWindowAttributes (USER32.@)
3330 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3334 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3336 SERVER_START_REQ( set_window_layered_info )
3338 req->handle = wine_server_user_handle( hwnd );
3339 req->color_key = key;
3342 ret = !wine_server_call_err( req );
3346 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3352 /*****************************************************************************
3353 * GetLayeredWindowAttributes (USER32.@)
3355 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3359 SERVER_START_REQ( get_window_layered_info )
3361 req->handle = wine_server_user_handle( hwnd );
3362 if ((ret = !wine_server_call_err( req )))
3364 if (key) *key = reply->color_key;
3365 if (alpha) *alpha = reply->alpha;
3366 if (flags) *flags = reply->flags;
3375 /*****************************************************************************
3376 * UpdateLayeredWindowIndirect (USER32.@)
3378 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3382 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3384 int x = 0, y = 0, cx = 0, cy = 0;
3385 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3389 x = info->pptDst->x;
3390 y = info->pptDst->y;
3391 flags &= ~SWP_NOMOVE;
3395 cx = info->psize->cx;
3396 cy = info->psize->cy;
3397 flags &= ~SWP_NOSIZE;
3399 TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3400 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3405 HDC hdc = GetWindowDC( hwnd );
3412 GetWindowRect( hwnd, &rect );
3413 OffsetRect( &rect, -rect.left, -rect.top);
3416 x = info->pptSrc->x;
3417 y = info->pptSrc->y;
3420 if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3422 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3423 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3424 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3426 ReleaseDC( hwnd, hdc );
3430 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3431 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3432 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3433 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3438 /*****************************************************************************
3439 * UpdateLayeredWindow (USER32.@)
3441 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3442 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3445 UPDATELAYEREDWINDOWINFO info;
3447 info.cbSize = sizeof(info);
3448 info.hdcDst = hdcDst;
3449 info.pptDst = pptDst;
3451 info.hdcSrc = hdcSrc;
3452 info.pptSrc = pptSrc;
3454 info.pblend = pblend;
3455 info.dwFlags = dwFlags;
3456 info.prcDirty = NULL;
3457 return UpdateLayeredWindowIndirect( hwnd, &info );
3460 /* 64bit versions */
3462 #ifdef GetWindowLongPtrW
3463 #undef GetWindowLongPtrW
3466 #ifdef GetWindowLongPtrA
3467 #undef GetWindowLongPtrA
3470 #ifdef SetWindowLongPtrW
3471 #undef SetWindowLongPtrW
3474 #ifdef SetWindowLongPtrA
3475 #undef SetWindowLongPtrA
3478 /*****************************************************************************
3479 * GetWindowLongPtrW (USER32.@)
3481 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3483 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3486 /*****************************************************************************
3487 * GetWindowLongPtrA (USER32.@)
3489 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3491 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3494 /*****************************************************************************
3495 * SetWindowLongPtrW (USER32.@)
3497 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3499 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3502 /*****************************************************************************
3503 * SetWindowLongPtrA (USER32.@)
3505 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3507 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );