2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
36 #include "user_private.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
43 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
44 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
46 /**********************************************************************/
48 /* helper for Get/SetWindowLong */
49 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 if (size == sizeof(WORD))
54 memcpy( &ret, ptr, sizeof(ret) );
57 else if (size == sizeof(DWORD))
60 memcpy( &ret, ptr, sizeof(ret) );
66 memcpy( &ret, ptr, sizeof(ret) );
71 /* helper for Get/SetWindowLong */
72 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 if (size == sizeof(WORD))
77 memcpy( ptr, &newval, sizeof(newval) );
79 else if (size == sizeof(DWORD))
82 memcpy( ptr, &newval, sizeof(newval) );
86 memcpy( ptr, &val, sizeof(val) );
91 static void *user_handles[NB_USER_HANDLES];
93 /***********************************************************************
96 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
100 SERVER_START_REQ( alloc_user_handle )
102 if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
108 UINT index = USER_HANDLE_TO_INDEX( handle );
110 assert( index < NB_USER_HANDLES );
111 ptr->handle = handle;
113 user_handles[index] = ptr;
119 /***********************************************************************
120 * get_user_handle_ptr
122 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
124 struct user_object *ptr;
125 WORD index = USER_HANDLE_TO_INDEX( handle );
127 if (index >= NB_USER_HANDLES) return NULL;
130 if ((ptr = user_handles[index]))
132 if (ptr->type == type &&
133 ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
134 !HIWORD(handle) || HIWORD(handle) == 0xffff))
138 else ptr = OBJ_OTHER_PROCESS;
144 /***********************************************************************
145 * release_user_handle_ptr
147 void release_user_handle_ptr( void *ptr )
153 /***********************************************************************
156 void *free_user_handle( HANDLE handle, enum user_obj_type type )
158 struct user_object *ptr;
159 WORD index = USER_HANDLE_TO_INDEX( handle );
161 if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
163 SERVER_START_REQ( free_user_handle )
165 req->handle = wine_server_user_handle( handle );
166 if (!wine_server_call( req )) user_handles[index] = NULL;
170 release_user_handle_ptr( ptr );
176 /***********************************************************************
177 * create_window_handle
179 * Create a window handle with the server.
181 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
182 HINSTANCE instance, BOOL unicode )
186 HWND handle = 0, full_parent = 0, full_owner = 0;
187 struct tagCLASS *class = NULL;
190 /* if 16-bit instance, map to module handle */
191 if (instance && !HIWORD(instance))
192 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
194 SERVER_START_REQ( create_window )
196 req->parent = wine_server_user_handle( parent );
197 req->owner = wine_server_user_handle( owner );
198 req->instance = wine_server_client_ptr( instance );
199 if (!(req->atom = get_int_atom_value( name )) && name)
200 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
201 if (!wine_server_call_err( req ))
203 handle = wine_server_ptr_handle( reply->handle );
204 full_parent = wine_server_ptr_handle( reply->parent );
205 full_owner = wine_server_ptr_handle( reply->owner );
206 extra_bytes = reply->extra;
207 class = wine_server_get_ptr( reply->class_ptr );
214 WARN( "error %d creating window\n", GetLastError() );
218 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
219 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
221 SERVER_START_REQ( destroy_window )
223 req->handle = wine_server_user_handle( handle );
224 wine_server_call( req );
227 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
231 if (!parent) /* if parent is 0 we don't have a desktop window yet */
233 struct user_thread_info *thread_info = get_user_thread_info();
235 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
237 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
238 else assert( full_parent == thread_info->top_window );
239 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
240 ERR( "failed to create desktop window\n" );
242 else /* HWND_MESSAGE parent */
244 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
250 index = USER_HANDLE_TO_INDEX(handle);
251 assert( index < NB_USER_HANDLES );
252 user_handles[index] = win;
253 win->obj.handle = handle;
254 win->obj.type = USER_WINDOW;
255 win->parent = full_parent;
256 win->owner = full_owner;
258 win->winproc = get_class_winproc( class );
259 win->cbWndExtra = extra_bytes;
260 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
265 /***********************************************************************
268 * Free a window handle.
270 static void free_window_handle( HWND hwnd )
272 struct user_object *ptr;
273 WORD index = USER_HANDLE_TO_INDEX(hwnd);
275 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
277 SERVER_START_REQ( destroy_window )
279 req->handle = wine_server_user_handle( hwnd );
280 if (!wine_server_call_err( req )) user_handles[index] = NULL;
284 release_user_handle_ptr( ptr );
285 HeapFree( GetProcessHeap(), 0, ptr );
290 /*******************************************************************
291 * list_window_children
293 * Build an array of the children of a given window. The array must be
294 * freed with HeapFree. Returns NULL when no windows are found.
296 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
300 ATOM atom = get_int_atom_value( class );
302 /* empty class is not the same as NULL class */
303 if (!atom && class && !class[0]) return NULL;
309 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
311 SERVER_START_REQ( get_window_children )
313 req->desktop = wine_server_obj_handle( desktop );
314 req->parent = wine_server_user_handle( hwnd );
317 if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
318 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
319 if (!wine_server_call( req )) count = reply->count;
322 if (count && count < size)
324 /* start from the end since HWND is potentially larger than user_handle_t */
325 for (i = count - 1; i >= 0; i--)
326 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
330 HeapFree( GetProcessHeap(), 0, list );
332 size = count + 1; /* restart with a large enough buffer */
338 /*******************************************************************
339 * list_window_parents
341 * Build an array of all parents of a given window, starting with
342 * the immediate parent. The array must be freed with HeapFree.
344 static HWND *list_window_parents( HWND hwnd )
348 int i, pos = 0, size = 16, count = 0;
350 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
355 if (!(win = WIN_GetPtr( current ))) goto empty;
356 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
357 if (win == WND_DESKTOP)
359 if (!pos) goto empty;
363 list[pos] = current = win->parent;
364 WIN_ReleasePtr( win );
365 if (!current) return list;
366 if (++pos == size - 1)
368 /* need to grow the list */
369 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
370 if (!new_list) goto empty;
376 /* at least one parent belongs to another process, have to query the server */
381 SERVER_START_REQ( get_window_parents )
383 req->handle = wine_server_user_handle( hwnd );
384 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
385 if (!wine_server_call( req )) count = reply->count;
388 if (!count) goto empty;
391 /* start from the end since HWND is potentially larger than user_handle_t */
392 for (i = count - 1; i >= 0; i--)
393 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
397 HeapFree( GetProcessHeap(), 0, list );
399 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
403 HeapFree( GetProcessHeap(), 0, list );
408 /*******************************************************************
411 static void send_parent_notify( HWND hwnd, UINT msg )
413 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
414 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
416 HWND parent = GetParent(hwnd);
417 if (parent && parent != GetDesktopWindow())
418 SendMessageW( parent, WM_PARENTNOTIFY,
419 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
424 /*******************************************************************
425 * get_server_window_text
427 * Retrieve the window text from the server.
429 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
433 SERVER_START_REQ( get_window_text )
435 req->handle = wine_server_user_handle( hwnd );
436 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
437 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
440 text[len / sizeof(WCHAR)] = 0;
444 /*******************************************************************
445 * get_hwnd_message_parent
447 * Return the parent for HWND_MESSAGE windows.
449 HWND get_hwnd_message_parent(void)
451 struct user_thread_info *thread_info = get_user_thread_info();
453 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
454 return thread_info->msg_window;
458 /*******************************************************************
461 * Check if window is the desktop or the HWND_MESSAGE top parent.
463 BOOL is_desktop_window( HWND hwnd )
465 struct user_thread_info *thread_info = get_user_thread_info();
467 if (!hwnd) return FALSE;
468 if (hwnd == thread_info->top_window) return TRUE;
469 if (hwnd == thread_info->msg_window) return TRUE;
471 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
473 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
474 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
480 /***********************************************************************
483 * Return a pointer to the WND structure if local to the process,
484 * or WND_OTHER_PROCESS if handle may be valid in other process.
485 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
487 WND *WIN_GetPtr( HWND hwnd )
491 if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
493 if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
499 /***********************************************************************
500 * WIN_IsCurrentProcess
502 * Check whether a given window belongs to the current process (and return the full handle).
504 HWND WIN_IsCurrentProcess( HWND hwnd )
509 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
510 ret = ptr->obj.handle;
511 WIN_ReleasePtr( ptr );
516 /***********************************************************************
517 * WIN_IsCurrentThread
519 * Check whether a given window belongs to the current thread (and return the full handle).
521 HWND WIN_IsCurrentThread( HWND hwnd )
526 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
527 if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
528 WIN_ReleasePtr( ptr );
533 /***********************************************************************
536 * Convert a 16-bit window handle to a full 32-bit handle.
538 HWND WIN_Handle32( HWND16 hwnd16 )
541 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
543 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
544 /* do sign extension for -2 and -3 */
545 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
547 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
549 if (ptr == WND_DESKTOP)
551 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
552 else return get_hwnd_message_parent();
555 if (ptr != WND_OTHER_PROCESS)
557 hwnd = ptr->obj.handle;
558 WIN_ReleasePtr( ptr );
560 else /* may belong to another process */
562 SERVER_START_REQ( get_window_info )
564 req->handle = wine_server_user_handle( hwnd );
565 if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
573 /***********************************************************************
576 * Change the owner of a window.
578 HWND WIN_SetOwner( HWND hwnd, HWND owner )
580 WND *win = WIN_GetPtr( hwnd );
583 if (!win || win == WND_DESKTOP) return 0;
584 if (win == WND_OTHER_PROCESS)
586 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
589 SERVER_START_REQ( set_window_owner )
591 req->handle = wine_server_user_handle( hwnd );
592 req->owner = wine_server_user_handle( owner );
593 if (!wine_server_call( req ))
595 win->owner = wine_server_ptr_handle( reply->full_owner );
596 ret = wine_server_ptr_handle( reply->prev_owner );
600 WIN_ReleasePtr( win );
605 /***********************************************************************
608 * Change the style of a window.
610 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
614 WND *win = WIN_GetPtr( hwnd );
616 if (!win || win == WND_DESKTOP) return 0;
617 if (win == WND_OTHER_PROCESS)
620 ERR( "cannot set style %x/%x on other process window %p\n",
621 set_bits, clear_bits, hwnd );
624 style.styleOld = win->dwStyle;
625 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
626 if (style.styleNew == style.styleOld)
628 WIN_ReleasePtr( win );
629 return style.styleNew;
631 SERVER_START_REQ( set_window_info )
633 req->handle = wine_server_user_handle( hwnd );
634 req->flags = SET_WIN_STYLE;
635 req->style = style.styleNew;
636 req->extra_offset = -1;
637 if ((ok = !wine_server_call( req )))
639 style.styleOld = reply->old_style;
640 win->dwStyle = style.styleNew;
644 WIN_ReleasePtr( win );
647 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
648 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
650 return style.styleOld;
654 /***********************************************************************
657 * Get the window and client rectangles.
659 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
661 WND *win = WIN_GetPtr( hwnd );
666 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
669 if (win == WND_DESKTOP)
672 rect.left = rect.top = 0;
673 if (hwnd == get_hwnd_message_parent())
680 rect.right = GetSystemMetrics(SM_CXSCREEN);
681 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
683 if (rectWindow) *rectWindow = rect;
684 if (rectClient) *rectClient = rect;
686 else if (win == WND_OTHER_PROCESS)
688 SERVER_START_REQ( get_window_rectangles )
690 req->handle = wine_server_user_handle( hwnd );
691 if ((ret = !wine_server_call_err( req )))
695 rectWindow->left = reply->window.left;
696 rectWindow->top = reply->window.top;
697 rectWindow->right = reply->window.right;
698 rectWindow->bottom = reply->window.bottom;
702 rectClient->left = reply->client.left;
703 rectClient->top = reply->client.top;
704 rectClient->right = reply->client.right;
705 rectClient->bottom = reply->client.bottom;
713 if (rectWindow) *rectWindow = win->rectWindow;
714 if (rectClient) *rectClient = win->rectClient;
715 WIN_ReleasePtr( win );
721 /***********************************************************************
724 * Destroy storage associated to a window. "Internals" p.358
726 LRESULT WIN_DestroyWindow( HWND hwnd )
730 HMENU menu = 0, sys_menu;
733 TRACE("%p\n", hwnd );
735 /* free child windows */
736 if ((list = WIN_ListChildren( hwnd )))
739 for (i = 0; list[i]; i++)
741 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
742 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
744 HeapFree( GetProcessHeap(), 0, list );
747 /* Unlink now so we won't bother with the children later on */
748 SERVER_START_REQ( set_parent )
750 req->handle = wine_server_user_handle( hwnd );
752 wine_server_call( req );
757 * Send the WM_NCDESTROY to the window being destroyed.
759 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
761 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
763 /* free resources associated with the window */
765 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
766 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
767 menu = (HMENU)wndPtr->wIDmenu;
768 sys_menu = wndPtr->hSysMenu;
769 free_dce( wndPtr->dce, hwnd );
771 icon_title = wndPtr->icon_title;
772 HeapFree(GetProcessHeap(), 0, wndPtr->pScroll);
773 wndPtr->pScroll = NULL;
774 WIN_ReleasePtr( wndPtr );
776 if (icon_title) DestroyWindow( icon_title );
777 if (menu) DestroyMenu( menu );
778 if (sys_menu) DestroyMenu( sys_menu );
780 USER_Driver->pDestroyWindow( hwnd );
782 free_window_handle( hwnd );
787 /***********************************************************************
788 * destroy_thread_window
790 * Destroy a window upon exit of its thread.
792 static void destroy_thread_window( HWND hwnd )
796 HMENU menu = 0, sys_menu = 0;
799 /* free child windows */
801 if ((list = WIN_ListChildren( hwnd )))
804 for (i = 0; list[i]; i++)
806 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
807 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
809 HeapFree( GetProcessHeap(), 0, list );
812 /* destroy the client-side storage */
814 index = USER_HANDLE_TO_INDEX(hwnd);
815 if (index >= NB_USER_HANDLES) return;
817 if ((wndPtr = user_handles[index]))
819 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
820 sys_menu = wndPtr->hSysMenu;
821 free_dce( wndPtr->dce, hwnd );
822 user_handles[index] = NULL;
826 HeapFree( GetProcessHeap(), 0, wndPtr );
827 if (menu) DestroyMenu( menu );
828 if (sys_menu) DestroyMenu( sys_menu );
832 /***********************************************************************
833 * destroy_thread_child_windows
835 * Destroy child windows upon exit of its thread.
837 static void destroy_thread_child_windows( HWND hwnd )
842 if (WIN_IsCurrentThread( hwnd ))
844 destroy_thread_window( hwnd );
846 else if ((list = WIN_ListChildren( hwnd )))
848 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
849 HeapFree( GetProcessHeap(), 0, list );
854 /***********************************************************************
855 * WIN_DestroyThreadWindows
857 * Destroy all children of 'wnd' owned by the current thread.
859 void WIN_DestroyThreadWindows( HWND hwnd )
864 if (!(list = WIN_ListChildren( hwnd ))) return;
866 /* reset owners of top-level windows */
867 for (i = 0; list[i]; i++)
869 if (!WIN_IsCurrentThread( list[i] ))
871 HWND owner = GetWindow( list[i], GW_OWNER );
872 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
876 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
877 HeapFree( GetProcessHeap(), 0, list );
881 /***********************************************************************
884 * Fix the coordinates - Helper for WIN_CreateWindowEx.
885 * returns default show mode in sw.
887 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
889 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
892 if (cs->dwExStyle & WS_EX_MDICHILD)
896 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
897 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
899 TRACE("MDI child id %04x\n", id);
902 if (cs->style & (WS_CHILD | WS_POPUP))
904 if (cs->dwExStyle & WS_EX_MDICHILD)
906 if (IS_DEFAULT(cs->x))
911 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
912 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
916 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
917 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
920 else /* overlapped window */
923 MONITORINFO mon_info;
926 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
928 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
929 mon_info.cbSize = sizeof(mon_info);
930 GetMonitorInfoW( monitor, &mon_info );
931 GetStartupInfoW( &info );
933 if (IS_DEFAULT(cs->x))
935 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
936 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
937 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
940 if (IS_DEFAULT(cs->cx))
942 if (info.dwFlags & STARTF_USESIZE)
944 cs->cx = info.dwXSize;
945 cs->cy = info.dwYSize;
949 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
950 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
953 /* neither x nor cx are default. Check the y values .
954 * In the trace we see Outlook and Outlook Express using
955 * cy set to CW_USEDEFAULT when opening the address book.
957 else if (IS_DEFAULT(cs->cy))
959 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
960 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
966 /***********************************************************************
969 static void dump_window_styles( DWORD style, DWORD exstyle )
972 if(style & WS_POPUP) TRACE(" WS_POPUP");
973 if(style & WS_CHILD) TRACE(" WS_CHILD");
974 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
975 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
976 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
977 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
978 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
979 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
980 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
983 if(style & WS_BORDER) TRACE(" WS_BORDER");
984 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
986 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
987 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
988 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
989 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
990 if (style & WS_CHILD)
992 if(style & WS_GROUP) TRACE(" WS_GROUP");
993 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
997 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
998 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1001 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1002 #define DUMPED_STYLES \
1022 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1024 #undef DUMPED_STYLES
1026 TRACE( "exstyle:" );
1027 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1028 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1029 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1030 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1031 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1032 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1033 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1034 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1035 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1036 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1037 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1038 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1039 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1040 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1041 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1042 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1043 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1044 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1046 #define DUMPED_EX_STYLES \
1047 (WS_EX_DLGMODALFRAME | \
1048 WS_EX_DRAGDETECT | \
1049 WS_EX_NOPARENTNOTIFY | \
1051 WS_EX_ACCEPTFILES | \
1052 WS_EX_TRANSPARENT | \
1054 WS_EX_TOOLWINDOW | \
1055 WS_EX_WINDOWEDGE | \
1056 WS_EX_CLIENTEDGE | \
1057 WS_EX_CONTEXTHELP | \
1059 WS_EX_RTLREADING | \
1060 WS_EX_LEFTSCROLLBAR | \
1061 WS_EX_CONTROLPARENT | \
1062 WS_EX_STATICEDGE | \
1066 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1068 #undef DUMPED_EX_STYLES
1072 /***********************************************************************
1073 * WIN_CreateWindowEx
1075 * Implementation of CreateWindowEx().
1077 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
1079 INT cx, cy, style, sw = SW_SHOW;
1083 HWND hwnd, parent, owner, top_child = 0;
1084 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
1085 MDICREATESTRUCTA mdi_cs;
1086 CBT_CREATEWNDA cbtc;
1089 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1090 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1091 debugstr_w(className),
1092 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1093 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1094 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1096 /* Fix the styles for MDI children */
1097 if (cs->dwExStyle & WS_EX_MDICHILD)
1101 wndPtr = WIN_GetPtr(cs->hwndParent);
1102 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1104 flags = wndPtr->flags;
1105 WIN_ReleasePtr(wndPtr);
1108 if (!(flags & WIN_ISMDICLIENT))
1110 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1114 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1115 * MDICREATESTRUCT members have the originally passed values.
1117 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1118 * have the same layout.
1120 mdi_cs.szClass = cs->lpszClass;
1121 mdi_cs.szTitle = cs->lpszName;
1122 mdi_cs.hOwner = cs->hInstance;
1127 mdi_cs.style = cs->style;
1128 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1130 cs->lpCreateParams = &mdi_cs;
1132 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1134 if (cs->style & WS_POPUP)
1136 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1139 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1143 cs->style &= ~WS_POPUP;
1144 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1145 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1148 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1152 /* Restore current maximized child */
1153 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1155 TRACE("Restoring current maximized child %p\n", top_child);
1156 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1157 ShowWindow( top_child, SW_SHOWNORMAL );
1158 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1163 /* Find the parent window */
1165 parent = cs->hwndParent;
1168 if (cs->hwndParent == HWND_MESSAGE)
1170 cs->hwndParent = parent = get_hwnd_message_parent();
1172 else if (cs->hwndParent)
1174 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1176 parent = GetDesktopWindow();
1177 owner = cs->hwndParent;
1182 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1184 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1186 WARN("No parent for child window\n" );
1187 SetLastError(ERROR_TLW_WITH_WSCHILD);
1188 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1190 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1191 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1192 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1193 parent = GetDesktopWindow();
1196 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1198 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1199 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1200 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1201 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1203 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1205 /* Create the window structure */
1207 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1209 hwnd = wndPtr->obj.handle;
1211 /* Fill the window structure */
1213 wndPtr->tid = GetCurrentThreadId();
1214 wndPtr->hInstance = cs->hInstance;
1215 wndPtr->text = NULL;
1216 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1217 wndPtr->dwExStyle = cs->dwExStyle;
1218 wndPtr->wIDmenu = 0;
1219 wndPtr->helpContext = 0;
1220 wndPtr->pScroll = NULL;
1221 wndPtr->userdata = 0;
1223 wndPtr->hIconSmall = 0;
1224 wndPtr->hSysMenu = 0;
1225 wndPtr->flags |= (flags & WIN_ISWIN32);
1227 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1228 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1230 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1233 * Correct the window styles.
1235 * It affects only the style loaded into the WIN structure.
1238 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1240 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1241 if (!(wndPtr->dwStyle & WS_POPUP))
1242 wndPtr->dwStyle |= WS_CAPTION;
1246 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1247 * why does the user get to set it?
1250 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1251 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1252 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1254 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1256 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1257 wndPtr->flags |= WIN_NEED_SIZE;
1259 SERVER_START_REQ( set_window_info )
1261 req->handle = wine_server_user_handle( hwnd );
1262 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1263 req->style = wndPtr->dwStyle;
1264 req->ex_style = wndPtr->dwExStyle;
1265 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1266 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1267 req->extra_offset = -1;
1268 wine_server_call( req );
1272 /* Set the window menu */
1274 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1278 if (!MENU_SetMenu(hwnd, cs->hMenu))
1280 WIN_ReleasePtr( wndPtr );
1281 free_window_handle( hwnd );
1287 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1290 if (!cs->hInstance || HIWORD(cs->hInstance))
1291 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1293 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1295 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1299 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1301 /* call the WH_CBT hook */
1303 /* the window style passed to the hook must be the real window style,
1304 * rather than just the window style that the caller to CreateWindowEx
1305 * passed in, so we have to copy the original CREATESTRUCT and get the
1306 * the real style. */
1308 cbcs.style = wndPtr->dwStyle;
1310 cbtc.hwndInsertAfter = HWND_TOP;
1311 WIN_ReleasePtr( wndPtr );
1312 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1314 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1318 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1320 POINT maxSize, maxPos, minTrack, maxTrack;
1321 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1322 if (maxTrack.x < cx) cx = maxTrack.x;
1323 if (maxTrack.y < cy) cy = maxTrack.y;
1324 if (minTrack.x > cx) cx = minTrack.x;
1325 if (minTrack.y > cy) cy = minTrack.y;
1330 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1331 /* check for wraparound */
1332 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1333 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1334 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1336 /* send WM_NCCREATE */
1338 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1340 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1342 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1345 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1349 /* send WM_NCCALCSIZE */
1351 if ((wndPtr = WIN_GetPtr(hwnd)))
1353 /* yes, even if the CBT hook was called with HWND_TOP */
1355 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1356 RECT window_rect = wndPtr->rectWindow;
1357 RECT client_rect = window_rect;
1358 WIN_ReleasePtr( wndPtr );
1360 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1362 MapWindowPoints( parent, 0, &pt, 1 );
1363 OffsetRect( &client_rect, pt.x, pt.y );
1364 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1365 OffsetRect( &client_rect, -pt.x, -pt.y );
1366 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1370 /* send WM_CREATE */
1373 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1375 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1376 if (result == -1) goto failed;
1378 /* call the driver */
1380 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1382 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1384 /* send the size messages */
1386 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1387 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1388 if (!(wndPtr->flags & WIN_NEED_SIZE))
1390 rect = wndPtr->rectClient;
1391 WIN_ReleasePtr( wndPtr );
1392 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1393 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1394 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1396 else WIN_ReleasePtr( wndPtr );
1398 /* Show the window, maximizing or minimizing if needed */
1400 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1401 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1404 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1406 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1407 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1408 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1409 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1410 newPos.bottom - newPos.top, swFlag );
1413 /* Notify the parent window only */
1415 send_parent_notify( hwnd, WM_CREATE );
1416 if (!IsWindow( hwnd )) return 0;
1418 if (cs->style & WS_VISIBLE)
1420 if (cs->style & WS_MAXIMIZE)
1422 else if (cs->style & WS_MINIMIZE)
1423 sw = SW_SHOWMINIMIZED;
1425 ShowWindow( hwnd, sw );
1426 if (cs->dwExStyle & WS_EX_MDICHILD)
1428 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1429 /* ShowWindow won't activate child windows */
1430 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1434 /* Call WH_SHELL hook */
1436 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1437 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1439 TRACE("created window %p\n", hwnd);
1443 WIN_DestroyWindow( hwnd );
1448 /***********************************************************************
1449 * CreateWindow (USER.41)
1451 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1452 DWORD style, INT16 x, INT16 y, INT16 width,
1453 INT16 height, HWND16 parent, HMENU16 menu,
1454 HINSTANCE16 instance, LPVOID data )
1456 return CreateWindowEx16( 0, className, windowName, style,
1457 x, y, width, height, parent, menu, instance, data );
1461 /***********************************************************************
1462 * CreateWindowEx (USER.452)
1464 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1465 LPCSTR windowName, DWORD style, INT16 x,
1466 INT16 y, INT16 width, INT16 height,
1467 HWND16 parent, HMENU16 menu,
1468 HINSTANCE16 instance, LPVOID data )
1473 /* Fix the coordinates */
1475 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1476 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1477 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1478 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1480 /* Create the window */
1482 cs.lpCreateParams = data;
1483 cs.hInstance = HINSTANCE_32(instance);
1484 cs.hMenu = HMENU_32(menu);
1485 cs.hwndParent = WIN_Handle32( parent );
1487 cs.lpszName = windowName;
1488 cs.lpszClass = className;
1489 cs.dwExStyle = exStyle;
1491 if (!IS_INTRESOURCE(className))
1495 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1497 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1501 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1503 ERR( "bad atom %x\n", LOWORD(className));
1506 cs.lpszClass = buffer;
1507 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1512 /***********************************************************************
1513 * CreateWindowExA (USER32.@)
1515 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1516 LPCSTR windowName, DWORD style, INT x,
1517 INT y, INT width, INT height,
1518 HWND parent, HMENU menu,
1519 HINSTANCE instance, LPVOID data )
1523 cs.lpCreateParams = data;
1524 cs.hInstance = instance;
1526 cs.hwndParent = parent;
1532 cs.lpszName = windowName;
1533 cs.lpszClass = className;
1534 cs.dwExStyle = exStyle;
1536 if (!IS_INTRESOURCE(className))
1539 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1541 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1543 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1547 /***********************************************************************
1548 * CreateWindowExW (USER32.@)
1550 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1551 LPCWSTR windowName, DWORD style, INT x,
1552 INT y, INT width, INT height,
1553 HWND parent, HMENU menu,
1554 HINSTANCE instance, LPVOID data )
1558 cs.lpCreateParams = data;
1559 cs.hInstance = instance;
1561 cs.hwndParent = parent;
1567 cs.lpszName = windowName;
1568 cs.lpszClass = className;
1569 cs.dwExStyle = exStyle;
1571 /* Note: we rely on the fact that CREATESTRUCTA and */
1572 /* CREATESTRUCTW have the same layout. */
1573 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1577 /***********************************************************************
1578 * WIN_SendDestroyMsg
1580 static void WIN_SendDestroyMsg( HWND hwnd )
1584 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1586 if (hwnd == info.hwndCaret) DestroyCaret();
1587 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1591 * Send the WM_DESTROY to the window.
1593 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1596 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1597 * make sure that the window still exists when we come back.
1604 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1606 for (i = 0; pWndArray[i]; i++)
1608 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1610 HeapFree( GetProcessHeap(), 0, pWndArray );
1613 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1617 /***********************************************************************
1618 * DestroyWindow (USER32.@)
1620 BOOL WINAPI DestroyWindow( HWND hwnd )
1624 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1626 SetLastError( ERROR_ACCESS_DENIED );
1630 TRACE("(%p)\n", hwnd);
1634 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1636 if (MENU_IsMenuActive() == hwnd)
1639 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1643 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1644 send_parent_notify( hwnd, WM_DESTROY );
1646 else if (!GetWindow( hwnd, GW_OWNER ))
1648 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1649 /* FIXME: clean up palette - see "Internals" p.352 */
1652 if (!IsWindow(hwnd)) return TRUE;
1654 /* Hide the window */
1655 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1657 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1659 ShowWindow( hwnd, SW_HIDE );
1661 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1662 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1665 if (!IsWindow(hwnd)) return TRUE;
1667 /* Recursively destroy owned windows */
1674 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1677 for (i = 0; list[i]; i++)
1679 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1680 if (WIN_IsCurrentThread( list[i] ))
1682 DestroyWindow( list[i] );
1686 WIN_SetOwner( list[i], 0 );
1688 HeapFree( GetProcessHeap(), 0, list );
1690 if (!got_one) break;
1694 /* Send destroy messages */
1696 WIN_SendDestroyMsg( hwnd );
1697 if (!IsWindow( hwnd )) return TRUE;
1699 if (GetClipboardOwner() == hwnd)
1700 CLIPBOARD_ReleaseOwner();
1702 /* Destroy the window storage */
1704 WIN_DestroyWindow( hwnd );
1709 /***********************************************************************
1710 * CloseWindow (USER32.@)
1712 BOOL WINAPI CloseWindow( HWND hwnd )
1714 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1715 ShowWindow( hwnd, SW_MINIMIZE );
1720 /***********************************************************************
1721 * OpenIcon (USER32.@)
1723 BOOL WINAPI OpenIcon( HWND hwnd )
1725 if (!IsIconic( hwnd )) return FALSE;
1726 ShowWindow( hwnd, SW_SHOWNORMAL );
1731 /***********************************************************************
1732 * FindWindowExW (USER32.@)
1734 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1739 WCHAR *buffer = NULL;
1741 if (!parent && child) parent = GetDesktopWindow();
1742 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1746 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1747 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1750 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1754 child = WIN_GetFullHandle( child );
1755 while (list[i] && list[i] != child) i++;
1756 if (!list[i]) goto done;
1757 i++; /* start from next window */
1764 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1771 HeapFree( GetProcessHeap(), 0, list );
1772 HeapFree( GetProcessHeap(), 0, buffer );
1778 /***********************************************************************
1779 * FindWindowA (USER32.@)
1781 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1783 HWND ret = FindWindowExA( 0, 0, className, title );
1784 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1789 /***********************************************************************
1790 * FindWindowExA (USER32.@)
1792 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1794 LPWSTR titleW = NULL;
1799 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1800 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1801 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1804 if (!IS_INTRESOURCE(className))
1807 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1808 hwnd = FindWindowExW( parent, child, classW, titleW );
1812 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1815 HeapFree( GetProcessHeap(), 0, titleW );
1820 /***********************************************************************
1821 * FindWindowW (USER32.@)
1823 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1825 return FindWindowExW( 0, 0, className, title );
1829 /**********************************************************************
1830 * GetDesktopWindow (USER32.@)
1832 HWND WINAPI GetDesktopWindow(void)
1834 struct user_thread_info *thread_info = get_user_thread_info();
1836 if (thread_info->top_window) return thread_info->top_window;
1838 SERVER_START_REQ( get_desktop_window )
1841 if (!wine_server_call( req ))
1843 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1844 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1849 if (!thread_info->top_window)
1851 USEROBJECTFLAGS flags;
1852 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1853 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1855 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1856 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1858 PROCESS_INFORMATION pi;
1859 WCHAR windir[MAX_PATH];
1860 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1861 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1863 memset( &si, 0, sizeof(si) );
1865 si.dwFlags = STARTF_USESTDHANDLES;
1868 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1870 GetWindowsDirectoryW( windir, MAX_PATH );
1871 strcpyW( app, windir );
1872 strcatW( app, explorer );
1873 strcpyW( cmdline, app );
1874 strcatW( cmdline, args );
1875 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1876 NULL, windir, &si, &pi ))
1878 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1879 WaitForInputIdle( pi.hProcess, 10000 );
1880 CloseHandle( pi.hThread );
1881 CloseHandle( pi.hProcess );
1883 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1885 else TRACE( "not starting explorer since winstation is not visible\n" );
1887 SERVER_START_REQ( get_desktop_window )
1890 if (!wine_server_call( req ))
1892 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1893 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1899 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1900 ERR( "failed to create desktop window\n" );
1902 return thread_info->top_window;
1906 /*******************************************************************
1907 * EnableWindow (USER32.@)
1909 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1914 if (is_broadcast(hwnd))
1916 SetLastError( ERROR_INVALID_PARAMETER );
1920 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1921 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1925 TRACE("( %p, %d )\n", hwnd, enable);
1927 retvalue = !IsWindowEnabled( hwnd );
1929 if (enable && retvalue)
1931 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1932 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1934 else if (!enable && !retvalue)
1938 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1940 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1942 if (hwnd == GetFocus())
1943 SetFocus( 0 ); /* A disabled window can't have the focus */
1945 capture_wnd = GetCapture();
1946 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1947 ReleaseCapture(); /* A disabled window can't capture the mouse */
1949 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1955 /***********************************************************************
1956 * IsWindowEnabled (USER32.@)
1958 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1960 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1964 /***********************************************************************
1965 * IsWindowUnicode (USER32.@)
1967 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1970 BOOL retvalue = FALSE;
1972 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1974 if (wndPtr == WND_DESKTOP) return TRUE;
1976 if (wndPtr != WND_OTHER_PROCESS)
1978 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1979 WIN_ReleasePtr( wndPtr );
1983 SERVER_START_REQ( get_window_info )
1985 req->handle = wine_server_user_handle( hwnd );
1986 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1994 /**********************************************************************
1997 * Helper function for GetWindowLong().
1999 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2001 LONG_PTR retvalue = 0;
2004 if (offset == GWLP_HWNDPARENT)
2006 HWND parent = GetAncestor( hwnd, GA_PARENT );
2007 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2008 return (ULONG_PTR)parent;
2011 if (!(wndPtr = WIN_GetPtr( hwnd )))
2013 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2017 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2019 if (offset == GWLP_WNDPROC)
2021 SetLastError( ERROR_ACCESS_DENIED );
2024 SERVER_START_REQ( set_window_info )
2026 req->handle = wine_server_user_handle( hwnd );
2027 req->flags = 0; /* don't set anything, just retrieve */
2028 req->extra_offset = (offset >= 0) ? offset : -1;
2029 req->extra_size = (offset >= 0) ? size : 0;
2030 if (!wine_server_call_err( req ))
2034 case GWL_STYLE: retvalue = reply->old_style; break;
2035 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2036 case GWLP_ID: retvalue = reply->old_id; break;
2037 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2038 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2040 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2041 else SetLastError( ERROR_INVALID_INDEX );
2050 /* now we have a valid wndPtr */
2054 if (offset > (int)(wndPtr->cbWndExtra - size))
2056 WARN("Invalid offset %d\n", offset );
2057 WIN_ReleasePtr( wndPtr );
2058 SetLastError( ERROR_INVALID_INDEX );
2061 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2063 /* Special case for dialog window procedure */
2064 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2065 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2066 WIN_ReleasePtr( wndPtr );
2072 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2073 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2074 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2075 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2076 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2078 /* This looks like a hack only for the edit control (see tests). This makes these controls
2079 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2080 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2082 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2083 retvalue = (ULONG_PTR)wndPtr->winproc;
2085 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2088 WARN("Unknown offset %d\n", offset );
2089 SetLastError( ERROR_INVALID_INDEX );
2092 WIN_ReleasePtr(wndPtr);
2097 /**********************************************************************
2100 * Helper function for SetWindowLong().
2102 * 0 is the failure code. However, in the case of failure SetLastError
2103 * must be set to distinguish between a 0 return value and a failure.
2105 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2109 LONG_PTR retval = 0;
2112 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2114 if (is_broadcast(hwnd))
2116 SetLastError( ERROR_INVALID_PARAMETER );
2120 if (!(wndPtr = WIN_GetPtr( hwnd )))
2122 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2125 if (wndPtr == WND_DESKTOP)
2127 /* can't change anything on the desktop window */
2128 SetLastError( ERROR_ACCESS_DENIED );
2131 if (wndPtr == WND_OTHER_PROCESS)
2133 if (offset == GWLP_WNDPROC)
2135 SetLastError( ERROR_ACCESS_DENIED );
2138 if (offset > 32767 || offset < -32767)
2140 SetLastError( ERROR_INVALID_INDEX );
2143 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2146 /* first some special cases */
2152 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2153 style.styleNew = newval;
2154 WIN_ReleasePtr( wndPtr );
2155 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2156 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2157 newval = style.styleNew;
2159 case GWLP_HWNDPARENT:
2160 if (wndPtr->parent == GetDesktopWindow())
2162 WIN_ReleasePtr( wndPtr );
2163 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2167 WIN_ReleasePtr( wndPtr );
2168 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2173 UINT old_flags = wndPtr->flags;
2174 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2175 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2176 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2177 if (proc) wndPtr->winproc = proc;
2178 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2179 else wndPtr->flags &= ~WIN_ISUNICODE;
2180 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2182 WIN_ReleasePtr( wndPtr );
2185 /* update is_unicode flag on the server side */
2189 case GWLP_HINSTANCE:
2193 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2194 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2196 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2197 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2198 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2199 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2200 WIN_ReleasePtr( wndPtr );
2205 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2207 WARN("Invalid offset %d\n", offset );
2208 WIN_ReleasePtr( wndPtr );
2209 SetLastError( ERROR_INVALID_INDEX );
2212 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2214 /* already set to the same value */
2215 WIN_ReleasePtr( wndPtr );
2221 SERVER_START_REQ( set_window_info )
2223 req->handle = wine_server_user_handle( hwnd );
2224 req->extra_offset = -1;
2228 req->flags = SET_WIN_STYLE;
2229 req->style = newval;
2232 req->flags = SET_WIN_EXSTYLE;
2233 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2234 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2235 req->ex_style = newval;
2238 req->flags = SET_WIN_ID;
2241 case GWLP_HINSTANCE:
2242 req->flags = SET_WIN_INSTANCE;
2243 req->instance = wine_server_client_ptr( (void *)newval );
2246 req->flags = SET_WIN_UNICODE;
2247 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2250 req->flags = SET_WIN_USERDATA;
2251 req->user_data = newval;
2254 req->flags = SET_WIN_EXTRA;
2255 req->extra_offset = offset;
2256 req->extra_size = size;
2257 set_win_data( &req->extra_value, newval, size );
2259 if ((ok = !wine_server_call_err( req )))
2264 wndPtr->dwStyle = newval;
2265 retval = reply->old_style;
2268 wndPtr->dwExStyle = newval;
2269 retval = reply->old_ex_style;
2272 wndPtr->wIDmenu = newval;
2273 retval = reply->old_id;
2275 case GWLP_HINSTANCE:
2276 wndPtr->hInstance = (HINSTANCE)newval;
2277 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2282 wndPtr->userdata = newval;
2283 retval = reply->old_user_data;
2286 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2287 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2293 WIN_ReleasePtr( wndPtr );
2297 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2299 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2300 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2307 /**********************************************************************
2308 * GetWindowLong (USER.135)
2310 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2314 BOOL is_winproc = (offset == GWLP_WNDPROC);
2318 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2320 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2323 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2325 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2328 * Some programs try to access last element from 16 bit
2329 * code using illegal offset value. Hopefully this is
2330 * what those programs really expect.
2332 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2334 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2335 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2340 WARN("Invalid offset %d\n", offset );
2341 WIN_ReleasePtr( wndPtr );
2342 SetLastError( ERROR_INVALID_INDEX );
2346 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2347 WIN_ReleasePtr( wndPtr );
2350 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2351 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2356 /**********************************************************************
2357 * GetWindowWord (USER32.@)
2359 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2364 case GWLP_HINSTANCE:
2365 case GWLP_HWNDPARENT:
2370 WARN("Invalid offset %d\n", offset );
2371 SetLastError( ERROR_INVALID_INDEX );
2376 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2380 /**********************************************************************
2381 * GetWindowLongA (USER32.@)
2383 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2385 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2389 /**********************************************************************
2390 * GetWindowLongW (USER32.@)
2392 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2394 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2398 /**********************************************************************
2399 * SetWindowLong (USER.136)
2401 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2404 BOOL is_winproc = (offset == GWLP_WNDPROC);
2406 if (offset == DWLP_DLGPROC)
2408 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2410 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2413 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2415 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2416 (wndPtr->flags & WIN_ISDIALOG));
2417 WIN_ReleasePtr( wndPtr );
2423 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2424 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2425 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2427 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2431 /**********************************************************************
2432 * SetWindowWord (USER32.@)
2434 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2439 case GWLP_HINSTANCE:
2440 case GWLP_HWNDPARENT:
2445 WARN("Invalid offset %d\n", offset );
2446 SetLastError( ERROR_INVALID_INDEX );
2451 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2455 /**********************************************************************
2456 * SetWindowLongA (USER32.@)
2458 * See SetWindowLongW.
2460 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2462 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2466 /**********************************************************************
2467 * SetWindowLongW (USER32.@) Set window attribute
2469 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2470 * value in a window's extra memory.
2472 * The _hwnd_ parameter specifies the window. is the handle to a
2473 * window that has extra memory. The _newval_ parameter contains the
2474 * new attribute or extra memory value. If positive, the _offset_
2475 * parameter is the byte-addressed location in the window's extra
2476 * memory to set. If negative, _offset_ specifies the window
2477 * attribute to set, and should be one of the following values:
2479 * GWL_EXSTYLE The window's extended window style
2481 * GWL_STYLE The window's window style.
2483 * GWLP_WNDPROC Pointer to the window's window procedure.
2485 * GWLP_HINSTANCE The window's pplication instance handle.
2487 * GWLP_ID The window's identifier.
2489 * GWLP_USERDATA The window's user-specified data.
2491 * If the window is a dialog box, the _offset_ parameter can be one of
2492 * the following values:
2494 * DWLP_DLGPROC The address of the window's dialog box procedure.
2496 * DWLP_MSGRESULT The return value of a message
2497 * that the dialog box procedure processed.
2499 * DWLP_USER Application specific information.
2503 * If successful, returns the previous value located at _offset_. Otherwise,
2508 * Extra memory for a window class is specified by a nonzero cbWndExtra
2509 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2510 * time of class creation.
2512 * Using GWL_WNDPROC to set a new window procedure effectively creates
2513 * a window subclass. Use CallWindowProc() in the new windows procedure
2514 * to pass messages to the superclass's window procedure.
2516 * The user data is reserved for use by the application which created
2519 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2520 * instead, call the EnableWindow() function to change the window's
2523 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2524 * SetParent() instead.
2527 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2528 * it sends WM_STYLECHANGING before changing the settings
2529 * and WM_STYLECHANGED afterwards.
2530 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2532 LONG WINAPI SetWindowLongW(
2533 HWND hwnd, /* [in] window to alter */
2534 INT offset, /* [in] offset, in bytes, of location to alter */
2535 LONG newval /* [in] new value of location */
2537 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2541 /*******************************************************************
2542 * GetWindowTextA (USER32.@)
2544 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2548 if (!lpString) return 0;
2550 if (WIN_IsCurrentProcess( hwnd ))
2551 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2553 /* when window belongs to other process, don't send a message */
2554 if (nMaxCount <= 0) return 0;
2555 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2556 get_server_window_text( hwnd, buffer, nMaxCount );
2557 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2558 lpString[nMaxCount-1] = 0;
2559 HeapFree( GetProcessHeap(), 0, buffer );
2560 return strlen(lpString);
2564 /*******************************************************************
2565 * InternalGetWindowText (USER32.@)
2567 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2571 if (nMaxCount <= 0) return 0;
2572 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2573 if (win == WND_DESKTOP) lpString[0] = 0;
2574 else if (win != WND_OTHER_PROCESS)
2576 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2577 else lpString[0] = 0;
2578 WIN_ReleasePtr( win );
2582 get_server_window_text( hwnd, lpString, nMaxCount );
2584 return strlenW(lpString);
2588 /*******************************************************************
2589 * GetWindowTextW (USER32.@)
2591 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2593 if (!lpString) return 0;
2595 if (WIN_IsCurrentProcess( hwnd ))
2596 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2598 /* when window belongs to other process, don't send a message */
2599 if (nMaxCount <= 0) return 0;
2600 get_server_window_text( hwnd, lpString, nMaxCount );
2601 return strlenW(lpString);
2605 /*******************************************************************
2606 * SetWindowTextA (USER32.@)
2607 * SetWindowText (USER32.@)
2609 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2611 if (is_broadcast(hwnd))
2613 SetLastError( ERROR_INVALID_PARAMETER );
2616 if (!WIN_IsCurrentProcess( hwnd ))
2617 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2618 debugstr_a(lpString), hwnd );
2619 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2623 /*******************************************************************
2624 * SetWindowTextW (USER32.@)
2626 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2628 if (is_broadcast(hwnd))
2630 SetLastError( ERROR_INVALID_PARAMETER );
2633 if (!WIN_IsCurrentProcess( hwnd ))
2634 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2635 debugstr_w(lpString), hwnd );
2636 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2640 /*******************************************************************
2641 * GetWindowTextLengthA (USER32.@)
2643 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2645 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2648 /*******************************************************************
2649 * GetWindowTextLengthW (USER32.@)
2651 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2653 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2657 /*******************************************************************
2658 * IsWindow (USER32.@)
2660 BOOL WINAPI IsWindow( HWND hwnd )
2665 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2666 if (ptr == WND_DESKTOP) return TRUE;
2668 if (ptr != WND_OTHER_PROCESS)
2670 WIN_ReleasePtr( ptr );
2674 /* check other processes */
2675 SERVER_START_REQ( get_window_info )
2677 req->handle = wine_server_user_handle( hwnd );
2678 ret = !wine_server_call_err( req );
2685 /***********************************************************************
2686 * GetWindowThreadProcessId (USER32.@)
2688 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2693 if (!(ptr = WIN_GetPtr( hwnd )))
2695 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2699 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2701 /* got a valid window */
2703 if (process) *process = GetCurrentProcessId();
2704 WIN_ReleasePtr( ptr );
2708 /* check other processes */
2709 SERVER_START_REQ( get_window_info )
2711 req->handle = wine_server_user_handle( hwnd );
2712 if (!wine_server_call_err( req ))
2714 tid = (DWORD)reply->tid;
2715 if (process) *process = (DWORD)reply->pid;
2723 /*****************************************************************
2724 * GetParent (USER32.@)
2726 HWND WINAPI GetParent( HWND hwnd )
2731 if (!(wndPtr = WIN_GetPtr( hwnd )))
2733 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2736 if (wndPtr == WND_DESKTOP) return 0;
2737 if (wndPtr == WND_OTHER_PROCESS)
2739 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2740 if (style & (WS_POPUP | WS_CHILD))
2742 SERVER_START_REQ( get_window_tree )
2744 req->handle = wine_server_user_handle( hwnd );
2745 if (!wine_server_call_err( req ))
2747 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2748 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2756 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2757 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2758 WIN_ReleasePtr( wndPtr );
2764 /*****************************************************************
2765 * GetAncestor (USER32.@)
2767 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2770 HWND *list, ret = 0;
2775 if (!(win = WIN_GetPtr( hwnd )))
2777 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2780 if (win == WND_DESKTOP) return 0;
2781 if (win != WND_OTHER_PROCESS)
2784 WIN_ReleasePtr( win );
2786 else /* need to query the server */
2788 SERVER_START_REQ( get_window_tree )
2790 req->handle = wine_server_user_handle( hwnd );
2791 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2798 if (!(list = list_window_parents( hwnd ))) return 0;
2800 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2804 while (list[count]) count++;
2805 ret = list[count - 2]; /* get the one before the desktop */
2807 HeapFree( GetProcessHeap(), 0, list );
2811 if (is_desktop_window( hwnd )) return 0;
2812 ret = WIN_GetFullHandle( hwnd );
2815 HWND parent = GetParent( ret );
2825 /*****************************************************************
2826 * SetParent (USER32.@)
2828 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2831 HWND old_parent = 0;
2836 if (is_broadcast(hwnd) || is_broadcast(parent))
2838 SetLastError(ERROR_INVALID_PARAMETER);
2842 if (!parent) parent = GetDesktopWindow();
2843 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2844 else parent = WIN_GetFullHandle( parent );
2846 if (!IsWindow( parent ))
2848 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2852 /* Some applications try to set a child as a parent */
2853 if (IsChild(hwnd, parent))
2855 SetLastError( ERROR_INVALID_PARAMETER );
2859 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2860 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2862 /* Windows hides the window first, then shows it again
2863 * including the WM_SHOWWINDOW messages and all */
2864 was_visible = ShowWindow( hwnd, SW_HIDE );
2866 wndPtr = WIN_GetPtr( hwnd );
2867 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2869 SERVER_START_REQ( set_parent )
2871 req->handle = wine_server_user_handle( hwnd );
2872 req->parent = wine_server_user_handle( parent );
2873 if ((ret = !wine_server_call( req )))
2875 old_parent = wine_server_ptr_handle( reply->old_parent );
2876 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2881 WIN_ReleasePtr( wndPtr );
2884 USER_Driver->pSetParent( full_handle, parent, old_parent );
2886 /* SetParent additionally needs to make hwnd the topmost window
2887 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2888 WM_WINDOWPOSCHANGED notification messages.
2890 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2891 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2892 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2893 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2899 /*******************************************************************
2900 * IsChild (USER32.@)
2902 BOOL WINAPI IsChild( HWND parent, HWND child )
2904 HWND *list = list_window_parents( child );
2908 if (!list) return FALSE;
2909 parent = WIN_GetFullHandle( parent );
2910 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2911 ret = list[i] && list[i+1];
2912 HeapFree( GetProcessHeap(), 0, list );
2917 /***********************************************************************
2918 * IsWindowVisible (USER32.@)
2920 BOOL WINAPI IsWindowVisible( HWND hwnd )
2926 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2927 if (!(list = list_window_parents( hwnd ))) return TRUE;
2930 for (i = 0; list[i+1]; i++)
2931 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2932 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2934 HeapFree( GetProcessHeap(), 0, list );
2939 /***********************************************************************
2940 * WIN_IsWindowDrawable
2942 * hwnd is drawable when it is visible, all parents are not
2943 * minimized, and it is itself not minimized unless we are
2944 * trying to draw its default class icon.
2946 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2951 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2953 if (!(style & WS_VISIBLE)) return FALSE;
2954 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2956 if (!(list = list_window_parents( hwnd ))) return TRUE;
2959 for (i = 0; list[i+1]; i++)
2960 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2962 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2964 HeapFree( GetProcessHeap(), 0, list );
2969 /*******************************************************************
2970 * GetTopWindow (USER32.@)
2972 HWND WINAPI GetTopWindow( HWND hwnd )
2974 if (!hwnd) hwnd = GetDesktopWindow();
2975 return GetWindow( hwnd, GW_CHILD );
2979 /*******************************************************************
2980 * GetWindow (USER32.@)
2982 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2986 if (rel == GW_OWNER) /* this one may be available locally */
2988 WND *wndPtr = WIN_GetPtr( hwnd );
2991 SetLastError( ERROR_INVALID_HANDLE );
2994 if (wndPtr == WND_DESKTOP) return 0;
2995 if (wndPtr != WND_OTHER_PROCESS)
2997 retval = wndPtr->owner;
2998 WIN_ReleasePtr( wndPtr );
3001 /* else fall through to server call */
3004 SERVER_START_REQ( get_window_tree )
3006 req->handle = wine_server_user_handle( hwnd );
3007 if (!wine_server_call_err( req ))
3012 retval = wine_server_ptr_handle( reply->first_sibling );
3015 retval = wine_server_ptr_handle( reply->last_sibling );
3018 retval = wine_server_ptr_handle( reply->next_sibling );
3021 retval = wine_server_ptr_handle( reply->prev_sibling );
3024 retval = wine_server_ptr_handle( reply->owner );
3027 retval = wine_server_ptr_handle( reply->first_child );
3037 /*******************************************************************
3038 * ShowOwnedPopups (USER32.@)
3040 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3044 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3046 if (!win_array) return TRUE;
3048 while (win_array[count]) count++;
3049 while (--count >= 0)
3051 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3052 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3053 if (pWnd == WND_OTHER_PROCESS) continue;
3056 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3058 WIN_ReleasePtr( pWnd );
3059 /* In Windows, ShowOwnedPopups(TRUE) generates
3060 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3061 * regardless of the state of the owner
3063 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3069 if (pWnd->dwStyle & WS_VISIBLE)
3071 WIN_ReleasePtr( pWnd );
3072 /* In Windows, ShowOwnedPopups(FALSE) generates
3073 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3074 * regardless of the state of the owner
3076 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3080 WIN_ReleasePtr( pWnd );
3082 HeapFree( GetProcessHeap(), 0, win_array );
3087 /*******************************************************************
3088 * GetLastActivePopup (USER32.@)
3090 HWND WINAPI GetLastActivePopup( HWND hwnd )
3094 SERVER_START_REQ( get_window_info )
3096 req->handle = wine_server_user_handle( hwnd );
3097 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3104 /*******************************************************************
3107 * Build an array of the children of a given window. The array must be
3108 * freed with HeapFree. Returns NULL when no windows are found.
3110 HWND *WIN_ListChildren( HWND hwnd )
3114 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3117 return list_window_children( 0, hwnd, NULL, 0 );
3121 /*******************************************************************
3122 * EnumWindows (USER32.@)
3124 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3130 USER_CheckNotLock();
3132 /* We have to build a list of all windows first, to avoid */
3133 /* unpleasant side-effects, for instance if the callback */
3134 /* function changes the Z-order of the windows. */
3136 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3138 /* Now call the callback function for every window */
3140 for (i = 0; list[i]; i++)
3142 /* Make sure that the window still exists */
3143 if (!IsWindow( list[i] )) continue;
3144 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3146 HeapFree( GetProcessHeap(), 0, list );
3151 /**********************************************************************
3152 * EnumThreadWindows (USER32.@)
3154 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3160 USER_CheckNotLock();
3162 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3164 /* Now call the callback function for every window */
3166 for (i = 0; list[i]; i++)
3167 if (!(ret = func( list[i], lParam ))) break;
3168 HeapFree( GetProcessHeap(), 0, list );
3173 /***********************************************************************
3174 * EnumDesktopWindows (USER32.@)
3176 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3181 USER_CheckNotLock();
3183 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3185 for (i = 0; list[i]; i++)
3186 if (!func( list[i], lparam )) break;
3187 HeapFree( GetProcessHeap(), 0, list );
3192 /**********************************************************************
3193 * WIN_EnumChildWindows
3195 * Helper function for EnumChildWindows().
3197 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3202 for ( ; *list; list++)
3204 /* Make sure that the window still exists */
3205 if (!IsWindow( *list )) continue;
3206 /* Build children list first */
3207 childList = WIN_ListChildren( *list );
3209 ret = func( *list, lParam );
3213 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3214 HeapFree( GetProcessHeap(), 0, childList );
3216 if (!ret) return FALSE;
3222 /**********************************************************************
3223 * EnumChildWindows (USER32.@)
3225 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3230 USER_CheckNotLock();
3232 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3233 ret = WIN_EnumChildWindows( list, func, lParam );
3234 HeapFree( GetProcessHeap(), 0, list );
3239 /*******************************************************************
3240 * AnyPopup (USER.52)
3242 BOOL16 WINAPI AnyPopup16(void)
3248 /*******************************************************************
3249 * AnyPopup (USER32.@)
3251 BOOL WINAPI AnyPopup(void)
3255 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3257 if (!list) return FALSE;
3258 for (i = 0; list[i]; i++)
3260 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3262 retvalue = (list[i] != 0);
3263 HeapFree( GetProcessHeap(), 0, list );
3268 /*******************************************************************
3269 * FlashWindow (USER32.@)
3271 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3275 TRACE("%p\n", hWnd);
3277 if (IsIconic( hWnd ))
3279 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3281 wndPtr = WIN_GetPtr(hWnd);
3282 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3283 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3285 wndPtr->flags |= WIN_NCACTIVATED;
3289 wndPtr->flags &= ~WIN_NCACTIVATED;
3291 WIN_ReleasePtr( wndPtr );
3298 wndPtr = WIN_GetPtr(hWnd);
3299 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3300 hWnd = wndPtr->obj.handle; /* make it a full handle */
3302 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3303 else wparam = (hWnd == GetForegroundWindow());
3305 WIN_ReleasePtr( wndPtr );
3306 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3311 /*******************************************************************
3312 * FlashWindowEx (USER32.@)
3314 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3316 FIXME("%p\n", pfwi);
3320 /*******************************************************************
3321 * GetWindowContextHelpId (USER32.@)
3323 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3326 WND *wnd = WIN_GetPtr( hwnd );
3327 if (!wnd || wnd == WND_DESKTOP) return 0;
3328 if (wnd == WND_OTHER_PROCESS)
3330 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3333 retval = wnd->helpContext;
3334 WIN_ReleasePtr( wnd );
3339 /*******************************************************************
3340 * SetWindowContextHelpId (USER32.@)
3342 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3344 WND *wnd = WIN_GetPtr( hwnd );
3345 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3346 if (wnd == WND_OTHER_PROCESS)
3348 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3351 wnd->helpContext = id;
3352 WIN_ReleasePtr( wnd );
3357 /*******************************************************************
3358 * DragDetect (USER32.@)
3360 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3364 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3365 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3367 rect.left = pt.x - wDragWidth;
3368 rect.right = pt.x + wDragWidth;
3370 rect.top = pt.y - wDragHeight;
3371 rect.bottom = pt.y + wDragHeight;
3377 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3379 if( msg.message == WM_LBUTTONUP )
3384 if( msg.message == WM_MOUSEMOVE )
3387 tmp.x = (short)LOWORD(msg.lParam);
3388 tmp.y = (short)HIWORD(msg.lParam);
3389 if( !PtInRect( &rect, tmp ))
3401 /******************************************************************************
3402 * GetWindowModuleFileNameA (USER32.@)
3404 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3409 TRACE( "%p, %p, %u\n", hwnd, module, size );
3411 win = WIN_GetPtr( hwnd );
3412 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3414 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3417 hinst = win->hInstance;
3418 WIN_ReleasePtr( win );
3420 return GetModuleFileNameA( hinst, module, size );
3423 /******************************************************************************
3424 * GetWindowModuleFileNameW (USER32.@)
3426 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3431 TRACE( "%p, %p, %u\n", hwnd, module, size );
3433 win = WIN_GetPtr( hwnd );
3434 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3436 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3439 hinst = win->hInstance;
3440 WIN_ReleasePtr( win );
3442 return GetModuleFileNameW( hinst, module, size );
3445 /******************************************************************************
3446 * GetWindowInfo (USER32.@)
3448 * Note: tests show that Windows doesn't check cbSize of the structure.
3450 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3452 if (!pwi) return FALSE;
3453 if (!IsWindow(hwnd)) return FALSE;
3455 GetWindowRect(hwnd, &pwi->rcWindow);
3456 GetClientRect(hwnd, &pwi->rcClient);
3457 /* translate to screen coordinates */
3458 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3460 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3461 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3462 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3464 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3465 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3467 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3468 pwi->wCreatorVersion = 0x0400;
3473 /******************************************************************************
3474 * SwitchDesktop (USER32.@)
3476 * NOTES: Sets the current input or interactive desktop.
3478 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3480 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3484 /*****************************************************************************
3485 * SetLayeredWindowAttributes (USER32.@)
3487 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3491 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3493 SERVER_START_REQ( set_window_layered_info )
3495 req->handle = wine_server_user_handle( hwnd );
3496 req->color_key = key;
3499 ret = !wine_server_call_err( req );
3503 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3509 /*****************************************************************************
3510 * GetLayeredWindowAttributes (USER32.@)
3512 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3516 SERVER_START_REQ( get_window_layered_info )
3518 req->handle = wine_server_user_handle( hwnd );
3519 if ((ret = !wine_server_call_err( req )))
3521 if (key) *key = reply->color_key;
3522 if (alpha) *alpha = reply->alpha;
3523 if (flags) *flags = reply->flags;
3532 /*****************************************************************************
3533 * UpdateLayeredWindowIndirect (USER32.@)
3535 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3539 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3541 int x = 0, y = 0, cx = 0, cy = 0;
3542 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3546 x = info->pptDst->x;
3547 y = info->pptDst->y;
3548 flags &= ~SWP_NOMOVE;
3552 cx = info->psize->cx;
3553 cy = info->psize->cy;
3554 flags &= ~SWP_NOSIZE;
3556 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3557 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3563 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3569 GetClientRect( hwnd, &rect );
3572 x = info->pptSrc->x;
3573 y = info->pptSrc->y;
3575 /* FIXME: intersect rect with info->prcDirty */
3576 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3577 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3578 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3579 ReleaseDC( hwnd, hdc );
3583 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3584 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3585 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3586 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3591 /*****************************************************************************
3592 * UpdateLayeredWindow (USER32.@)
3594 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3595 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3598 UPDATELAYEREDWINDOWINFO info;
3600 info.cbSize = sizeof(info);
3601 info.hdcDst = hdcDst;
3602 info.pptDst = pptDst;
3604 info.hdcSrc = hdcSrc;
3605 info.pptSrc = pptSrc;
3607 info.pblend = pblend;
3608 info.dwFlags = dwFlags;
3609 info.prcDirty = NULL;
3610 return UpdateLayeredWindowIndirect( hwnd, &info );
3613 /* 64bit versions */
3615 #ifdef GetWindowLongPtrW
3616 #undef GetWindowLongPtrW
3619 #ifdef GetWindowLongPtrA
3620 #undef GetWindowLongPtrA
3623 #ifdef SetWindowLongPtrW
3624 #undef SetWindowLongPtrW
3627 #ifdef SetWindowLongPtrA
3628 #undef SetWindowLongPtrA
3631 /*****************************************************************************
3632 * GetWindowLongPtrW (USER32.@)
3634 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3636 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3639 /*****************************************************************************
3640 * GetWindowLongPtrA (USER32.@)
3642 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3644 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3647 /*****************************************************************************
3648 * SetWindowLongPtrW (USER32.@)
3650 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3652 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3655 /*****************************************************************************
3656 * SetWindowLongPtrA (USER32.@)
3658 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3660 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );