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->text );
774 HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
775 wndPtr->pScroll = NULL;
776 WIN_ReleasePtr( wndPtr );
778 if (icon_title) DestroyWindow( icon_title );
779 if (menu) DestroyMenu( menu );
780 if (sys_menu) DestroyMenu( sys_menu );
782 USER_Driver->pDestroyWindow( hwnd );
784 free_window_handle( hwnd );
789 /***********************************************************************
790 * destroy_thread_window
792 * Destroy a window upon exit of its thread.
794 static void destroy_thread_window( HWND hwnd )
798 HMENU menu = 0, sys_menu = 0;
801 /* free child windows */
803 if ((list = WIN_ListChildren( hwnd )))
806 for (i = 0; list[i]; i++)
808 if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
809 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
811 HeapFree( GetProcessHeap(), 0, list );
814 /* destroy the client-side storage */
816 index = USER_HANDLE_TO_INDEX(hwnd);
817 if (index >= NB_USER_HANDLES) return;
819 if ((wndPtr = user_handles[index]))
821 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
822 sys_menu = wndPtr->hSysMenu;
823 free_dce( wndPtr->dce, hwnd );
824 user_handles[index] = NULL;
828 HeapFree( GetProcessHeap(), 0, wndPtr );
829 if (menu) DestroyMenu( menu );
830 if (sys_menu) DestroyMenu( sys_menu );
834 /***********************************************************************
835 * destroy_thread_child_windows
837 * Destroy child windows upon exit of its thread.
839 static void destroy_thread_child_windows( HWND hwnd )
844 if (WIN_IsCurrentThread( hwnd ))
846 destroy_thread_window( hwnd );
848 else if ((list = WIN_ListChildren( hwnd )))
850 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
851 HeapFree( GetProcessHeap(), 0, list );
856 /***********************************************************************
857 * WIN_DestroyThreadWindows
859 * Destroy all children of 'wnd' owned by the current thread.
861 void WIN_DestroyThreadWindows( HWND hwnd )
866 if (!(list = WIN_ListChildren( hwnd ))) return;
868 /* reset owners of top-level windows */
869 for (i = 0; list[i]; i++)
871 if (!WIN_IsCurrentThread( list[i] ))
873 HWND owner = GetWindow( list[i], GW_OWNER );
874 if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
878 for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
879 HeapFree( GetProcessHeap(), 0, list );
883 /***********************************************************************
886 * Fix the coordinates - Helper for WIN_CreateWindowEx.
887 * returns default show mode in sw.
889 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
891 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
894 if (cs->dwExStyle & WS_EX_MDICHILD)
898 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
899 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
901 TRACE("MDI child id %04x\n", id);
904 if (cs->style & (WS_CHILD | WS_POPUP))
906 if (cs->dwExStyle & WS_EX_MDICHILD)
908 if (IS_DEFAULT(cs->x))
913 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
914 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
918 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
919 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
922 else /* overlapped window */
925 MONITORINFO mon_info;
928 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
930 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
931 mon_info.cbSize = sizeof(mon_info);
932 GetMonitorInfoW( monitor, &mon_info );
933 GetStartupInfoW( &info );
935 if (IS_DEFAULT(cs->x))
937 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
938 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
939 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
942 if (IS_DEFAULT(cs->cx))
944 if (info.dwFlags & STARTF_USESIZE)
946 cs->cx = info.dwXSize;
947 cs->cy = info.dwYSize;
951 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
952 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
955 /* neither x nor cx are default. Check the y values .
956 * In the trace we see Outlook and Outlook Express using
957 * cy set to CW_USEDEFAULT when opening the address book.
959 else if (IS_DEFAULT(cs->cy))
961 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
962 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
968 /***********************************************************************
971 static void dump_window_styles( DWORD style, DWORD exstyle )
974 if(style & WS_POPUP) TRACE(" WS_POPUP");
975 if(style & WS_CHILD) TRACE(" WS_CHILD");
976 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
977 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
978 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
979 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
980 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
981 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
982 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
985 if(style & WS_BORDER) TRACE(" WS_BORDER");
986 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
988 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
989 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
990 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
991 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
992 if (style & WS_CHILD)
994 if(style & WS_GROUP) TRACE(" WS_GROUP");
995 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
999 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1000 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1003 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1004 #define DUMPED_STYLES \
1024 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
1026 #undef DUMPED_STYLES
1028 TRACE( "exstyle:" );
1029 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1030 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1031 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1032 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1033 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1034 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1035 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1036 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1037 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1038 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1039 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1040 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1041 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1042 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1043 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1044 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1045 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1046 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1048 #define DUMPED_EX_STYLES \
1049 (WS_EX_DLGMODALFRAME | \
1050 WS_EX_DRAGDETECT | \
1051 WS_EX_NOPARENTNOTIFY | \
1053 WS_EX_ACCEPTFILES | \
1054 WS_EX_TRANSPARENT | \
1056 WS_EX_TOOLWINDOW | \
1057 WS_EX_WINDOWEDGE | \
1058 WS_EX_CLIENTEDGE | \
1059 WS_EX_CONTEXTHELP | \
1061 WS_EX_RTLREADING | \
1062 WS_EX_LEFTSCROLLBAR | \
1063 WS_EX_CONTROLPARENT | \
1064 WS_EX_STATICEDGE | \
1068 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
1070 #undef DUMPED_EX_STYLES
1074 /***********************************************************************
1075 * WIN_CreateWindowEx
1077 * Implementation of CreateWindowEx().
1079 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
1081 INT cx, cy, style, sw = SW_SHOW;
1085 HWND hwnd, parent, owner, top_child = 0;
1086 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
1087 MDICREATESTRUCTA mdi_cs;
1088 CBT_CREATEWNDA cbtc;
1091 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1092 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1093 debugstr_w(className),
1094 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1095 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1096 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1098 /* Fix the styles for MDI children */
1099 if (cs->dwExStyle & WS_EX_MDICHILD)
1103 wndPtr = WIN_GetPtr(cs->hwndParent);
1104 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1106 flags = wndPtr->flags;
1107 WIN_ReleasePtr(wndPtr);
1110 if (!(flags & WIN_ISMDICLIENT))
1112 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1116 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1117 * MDICREATESTRUCT members have the originally passed values.
1119 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1120 * have the same layout.
1122 mdi_cs.szClass = cs->lpszClass;
1123 mdi_cs.szTitle = cs->lpszName;
1124 mdi_cs.hOwner = cs->hInstance;
1129 mdi_cs.style = cs->style;
1130 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1132 cs->lpCreateParams = &mdi_cs;
1134 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1136 if (cs->style & WS_POPUP)
1138 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1141 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1145 cs->style &= ~WS_POPUP;
1146 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1147 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1150 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1154 /* Restore current maximized child */
1155 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1157 TRACE("Restoring current maximized child %p\n", top_child);
1158 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1159 ShowWindow( top_child, SW_SHOWNORMAL );
1160 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1165 /* Find the parent window */
1167 parent = cs->hwndParent;
1170 if (cs->hwndParent == HWND_MESSAGE)
1172 cs->hwndParent = parent = get_hwnd_message_parent();
1174 else if (cs->hwndParent)
1176 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1178 parent = GetDesktopWindow();
1179 owner = cs->hwndParent;
1184 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1186 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1188 WARN("No parent for child window\n" );
1189 SetLastError(ERROR_TLW_WITH_WSCHILD);
1190 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1192 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1193 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1194 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1195 parent = GetDesktopWindow();
1198 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1200 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1201 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1202 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1203 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1205 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1207 /* Create the window structure */
1209 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1211 hwnd = wndPtr->obj.handle;
1213 /* Fill the window structure */
1215 wndPtr->tid = GetCurrentThreadId();
1216 wndPtr->hInstance = cs->hInstance;
1217 wndPtr->text = NULL;
1218 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1219 wndPtr->dwExStyle = cs->dwExStyle;
1220 wndPtr->wIDmenu = 0;
1221 wndPtr->helpContext = 0;
1222 wndPtr->pScroll = NULL;
1223 wndPtr->userdata = 0;
1225 wndPtr->hIconSmall = 0;
1226 wndPtr->hSysMenu = 0;
1227 wndPtr->flags |= (flags & WIN_ISWIN32);
1229 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1230 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1232 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1235 * Correct the window styles.
1237 * It affects only the style loaded into the WIN structure.
1240 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1242 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1243 if (!(wndPtr->dwStyle & WS_POPUP))
1244 wndPtr->dwStyle |= WS_CAPTION;
1248 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1249 * why does the user get to set it?
1252 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1253 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1254 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1256 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1258 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1259 wndPtr->flags |= WIN_NEED_SIZE;
1261 SERVER_START_REQ( set_window_info )
1263 req->handle = wine_server_user_handle( hwnd );
1264 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1265 req->style = wndPtr->dwStyle;
1266 req->ex_style = wndPtr->dwExStyle;
1267 req->instance = wine_server_client_ptr( wndPtr->hInstance );
1268 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1269 req->extra_offset = -1;
1270 wine_server_call( req );
1274 /* Set the window menu */
1276 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1280 if (!MENU_SetMenu(hwnd, cs->hMenu))
1282 WIN_ReleasePtr( wndPtr );
1283 free_window_handle( hwnd );
1289 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1292 if (!cs->hInstance || HIWORD(cs->hInstance))
1293 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1295 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1297 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1301 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1303 /* call the WH_CBT hook */
1305 /* the window style passed to the hook must be the real window style,
1306 * rather than just the window style that the caller to CreateWindowEx
1307 * passed in, so we have to copy the original CREATESTRUCT and get the
1308 * the real style. */
1310 cbcs.style = wndPtr->dwStyle;
1312 cbtc.hwndInsertAfter = HWND_TOP;
1313 WIN_ReleasePtr( wndPtr );
1314 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1316 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1320 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1322 POINT maxSize, maxPos, minTrack, maxTrack;
1323 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1324 if (maxTrack.x < cx) cx = maxTrack.x;
1325 if (maxTrack.y < cy) cy = maxTrack.y;
1326 if (minTrack.x > cx) cx = minTrack.x;
1327 if (minTrack.y > cy) cy = minTrack.y;
1332 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1333 /* check for wraparound */
1334 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1335 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1336 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1338 /* send WM_NCCREATE */
1340 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1342 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1344 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1347 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1351 /* send WM_NCCALCSIZE */
1353 if ((wndPtr = WIN_GetPtr(hwnd)))
1355 /* yes, even if the CBT hook was called with HWND_TOP */
1357 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1358 RECT window_rect = wndPtr->rectWindow;
1359 RECT client_rect = window_rect;
1360 WIN_ReleasePtr( wndPtr );
1362 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1364 MapWindowPoints( parent, 0, &pt, 1 );
1365 OffsetRect( &client_rect, pt.x, pt.y );
1366 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1367 OffsetRect( &client_rect, -pt.x, -pt.y );
1368 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1372 /* send WM_CREATE */
1375 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1377 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1378 if (result == -1) goto failed;
1380 /* call the driver */
1382 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1384 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1386 /* send the size messages */
1388 if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1389 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1390 if (!(wndPtr->flags & WIN_NEED_SIZE))
1392 rect = wndPtr->rectClient;
1393 WIN_ReleasePtr( wndPtr );
1394 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1395 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1396 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1398 else WIN_ReleasePtr( wndPtr );
1400 /* Show the window, maximizing or minimizing if needed */
1402 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1403 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1406 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1408 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1409 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1410 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1411 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1412 newPos.bottom - newPos.top, swFlag );
1415 /* Notify the parent window only */
1417 send_parent_notify( hwnd, WM_CREATE );
1418 if (!IsWindow( hwnd )) return 0;
1420 if (cs->style & WS_VISIBLE)
1422 if (cs->style & WS_MAXIMIZE)
1424 else if (cs->style & WS_MINIMIZE)
1425 sw = SW_SHOWMINIMIZED;
1427 ShowWindow( hwnd, sw );
1428 if (cs->dwExStyle & WS_EX_MDICHILD)
1430 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1431 /* ShowWindow won't activate child windows */
1432 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1436 /* Call WH_SHELL hook */
1438 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1439 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1441 TRACE("created window %p\n", hwnd);
1445 WIN_DestroyWindow( hwnd );
1450 /***********************************************************************
1451 * CreateWindow (USER.41)
1453 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1454 DWORD style, INT16 x, INT16 y, INT16 width,
1455 INT16 height, HWND16 parent, HMENU16 menu,
1456 HINSTANCE16 instance, LPVOID data )
1458 return CreateWindowEx16( 0, className, windowName, style,
1459 x, y, width, height, parent, menu, instance, data );
1463 /***********************************************************************
1464 * CreateWindowEx (USER.452)
1466 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1467 LPCSTR windowName, DWORD style, INT16 x,
1468 INT16 y, INT16 width, INT16 height,
1469 HWND16 parent, HMENU16 menu,
1470 HINSTANCE16 instance, LPVOID data )
1475 /* Fix the coordinates */
1477 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1478 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1479 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1480 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1482 /* Create the window */
1484 cs.lpCreateParams = data;
1485 cs.hInstance = HINSTANCE_32(instance);
1486 cs.hMenu = HMENU_32(menu);
1487 cs.hwndParent = WIN_Handle32( parent );
1489 cs.lpszName = windowName;
1490 cs.lpszClass = className;
1491 cs.dwExStyle = exStyle;
1493 if (!IS_INTRESOURCE(className))
1497 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1499 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1503 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1505 ERR( "bad atom %x\n", LOWORD(className));
1508 cs.lpszClass = buffer;
1509 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1514 /***********************************************************************
1515 * CreateWindowExA (USER32.@)
1517 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1518 LPCSTR windowName, DWORD style, INT x,
1519 INT y, INT width, INT height,
1520 HWND parent, HMENU menu,
1521 HINSTANCE instance, LPVOID data )
1525 cs.lpCreateParams = data;
1526 cs.hInstance = instance;
1528 cs.hwndParent = parent;
1534 cs.lpszName = windowName;
1535 cs.lpszClass = className;
1536 cs.dwExStyle = exStyle;
1538 if (!IS_INTRESOURCE(className))
1541 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1543 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1545 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1549 /***********************************************************************
1550 * CreateWindowExW (USER32.@)
1552 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1553 LPCWSTR windowName, DWORD style, INT x,
1554 INT y, INT width, INT height,
1555 HWND parent, HMENU menu,
1556 HINSTANCE instance, LPVOID data )
1560 cs.lpCreateParams = data;
1561 cs.hInstance = instance;
1563 cs.hwndParent = parent;
1569 cs.lpszName = windowName;
1570 cs.lpszClass = className;
1571 cs.dwExStyle = exStyle;
1573 /* Note: we rely on the fact that CREATESTRUCTA and */
1574 /* CREATESTRUCTW have the same layout. */
1575 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1579 /***********************************************************************
1580 * WIN_SendDestroyMsg
1582 static void WIN_SendDestroyMsg( HWND hwnd )
1586 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1588 if (hwnd == info.hwndCaret) DestroyCaret();
1589 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1593 * Send the WM_DESTROY to the window.
1595 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1598 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1599 * make sure that the window still exists when we come back.
1606 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1608 for (i = 0; pWndArray[i]; i++)
1610 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1612 HeapFree( GetProcessHeap(), 0, pWndArray );
1615 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1619 /***********************************************************************
1620 * DestroyWindow (USER32.@)
1622 BOOL WINAPI DestroyWindow( HWND hwnd )
1626 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1628 SetLastError( ERROR_ACCESS_DENIED );
1632 TRACE("(%p)\n", hwnd);
1636 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1638 if (MENU_IsMenuActive() == hwnd)
1641 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1645 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1646 send_parent_notify( hwnd, WM_DESTROY );
1648 else if (!GetWindow( hwnd, GW_OWNER ))
1650 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1651 /* FIXME: clean up palette - see "Internals" p.352 */
1654 if (!IsWindow(hwnd)) return TRUE;
1656 /* Hide the window */
1657 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1659 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1661 ShowWindow( hwnd, SW_HIDE );
1663 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1664 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1667 if (!IsWindow(hwnd)) return TRUE;
1669 /* Recursively destroy owned windows */
1676 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1679 for (i = 0; list[i]; i++)
1681 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1682 if (WIN_IsCurrentThread( list[i] ))
1684 DestroyWindow( list[i] );
1688 WIN_SetOwner( list[i], 0 );
1690 HeapFree( GetProcessHeap(), 0, list );
1692 if (!got_one) break;
1696 /* Send destroy messages */
1698 WIN_SendDestroyMsg( hwnd );
1699 if (!IsWindow( hwnd )) return TRUE;
1701 if (GetClipboardOwner() == hwnd)
1702 CLIPBOARD_ReleaseOwner();
1704 /* Destroy the window storage */
1706 WIN_DestroyWindow( hwnd );
1711 /***********************************************************************
1712 * CloseWindow (USER32.@)
1714 BOOL WINAPI CloseWindow( HWND hwnd )
1716 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1717 ShowWindow( hwnd, SW_MINIMIZE );
1722 /***********************************************************************
1723 * OpenIcon (USER32.@)
1725 BOOL WINAPI OpenIcon( HWND hwnd )
1727 if (!IsIconic( hwnd )) return FALSE;
1728 ShowWindow( hwnd, SW_SHOWNORMAL );
1733 /***********************************************************************
1734 * FindWindowExW (USER32.@)
1736 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1741 WCHAR *buffer = NULL;
1743 if (!parent && child) parent = GetDesktopWindow();
1744 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1748 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1749 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1752 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1756 child = WIN_GetFullHandle( child );
1757 while (list[i] && list[i] != child) i++;
1758 if (!list[i]) goto done;
1759 i++; /* start from next window */
1766 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1773 HeapFree( GetProcessHeap(), 0, list );
1774 HeapFree( GetProcessHeap(), 0, buffer );
1780 /***********************************************************************
1781 * FindWindowA (USER32.@)
1783 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1785 HWND ret = FindWindowExA( 0, 0, className, title );
1786 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1791 /***********************************************************************
1792 * FindWindowExA (USER32.@)
1794 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1796 LPWSTR titleW = NULL;
1801 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1802 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1803 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1806 if (!IS_INTRESOURCE(className))
1809 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1810 hwnd = FindWindowExW( parent, child, classW, titleW );
1814 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1817 HeapFree( GetProcessHeap(), 0, titleW );
1822 /***********************************************************************
1823 * FindWindowW (USER32.@)
1825 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1827 return FindWindowExW( 0, 0, className, title );
1831 /**********************************************************************
1832 * GetDesktopWindow (USER32.@)
1834 HWND WINAPI GetDesktopWindow(void)
1836 struct user_thread_info *thread_info = get_user_thread_info();
1838 if (thread_info->top_window) return thread_info->top_window;
1840 SERVER_START_REQ( get_desktop_window )
1843 if (!wine_server_call( req ))
1845 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1846 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1851 if (!thread_info->top_window)
1853 USEROBJECTFLAGS flags;
1854 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1855 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1857 static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1858 static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1860 PROCESS_INFORMATION pi;
1861 WCHAR windir[MAX_PATH];
1862 WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1863 WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1865 memset( &si, 0, sizeof(si) );
1867 si.dwFlags = STARTF_USESTDHANDLES;
1870 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1872 GetWindowsDirectoryW( windir, MAX_PATH );
1873 strcpyW( app, windir );
1874 strcatW( app, explorer );
1875 strcpyW( cmdline, app );
1876 strcatW( cmdline, args );
1877 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1878 NULL, windir, &si, &pi ))
1880 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1881 WaitForInputIdle( pi.hProcess, 10000 );
1882 CloseHandle( pi.hThread );
1883 CloseHandle( pi.hProcess );
1885 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1887 else TRACE( "not starting explorer since winstation is not visible\n" );
1889 SERVER_START_REQ( get_desktop_window )
1892 if (!wine_server_call( req ))
1894 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1895 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1901 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1902 ERR( "failed to create desktop window\n" );
1904 return thread_info->top_window;
1908 /*******************************************************************
1909 * EnableWindow (USER32.@)
1911 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1916 if (is_broadcast(hwnd))
1918 SetLastError( ERROR_INVALID_PARAMETER );
1922 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1923 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1927 TRACE("( %p, %d )\n", hwnd, enable);
1929 retvalue = !IsWindowEnabled( hwnd );
1931 if (enable && retvalue)
1933 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1934 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1936 else if (!enable && !retvalue)
1940 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1942 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1944 if (hwnd == GetFocus())
1945 SetFocus( 0 ); /* A disabled window can't have the focus */
1947 capture_wnd = GetCapture();
1948 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1949 ReleaseCapture(); /* A disabled window can't capture the mouse */
1951 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1957 /***********************************************************************
1958 * IsWindowEnabled (USER32.@)
1960 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1962 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1966 /***********************************************************************
1967 * IsWindowUnicode (USER32.@)
1969 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1972 BOOL retvalue = FALSE;
1974 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1976 if (wndPtr == WND_DESKTOP) return TRUE;
1978 if (wndPtr != WND_OTHER_PROCESS)
1980 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1981 WIN_ReleasePtr( wndPtr );
1985 SERVER_START_REQ( get_window_info )
1987 req->handle = wine_server_user_handle( hwnd );
1988 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1996 /**********************************************************************
1999 * Helper function for GetWindowLong().
2001 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2003 LONG_PTR retvalue = 0;
2006 if (offset == GWLP_HWNDPARENT)
2008 HWND parent = GetAncestor( hwnd, GA_PARENT );
2009 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2010 return (ULONG_PTR)parent;
2013 if (!(wndPtr = WIN_GetPtr( hwnd )))
2015 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2019 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2021 if (offset == GWLP_WNDPROC)
2023 SetLastError( ERROR_ACCESS_DENIED );
2026 SERVER_START_REQ( set_window_info )
2028 req->handle = wine_server_user_handle( hwnd );
2029 req->flags = 0; /* don't set anything, just retrieve */
2030 req->extra_offset = (offset >= 0) ? offset : -1;
2031 req->extra_size = (offset >= 0) ? size : 0;
2032 if (!wine_server_call_err( req ))
2036 case GWL_STYLE: retvalue = reply->old_style; break;
2037 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
2038 case GWLP_ID: retvalue = reply->old_id; break;
2039 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2040 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
2042 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2043 else SetLastError( ERROR_INVALID_INDEX );
2052 /* now we have a valid wndPtr */
2056 if (offset > (int)(wndPtr->cbWndExtra - size))
2058 WARN("Invalid offset %d\n", offset );
2059 WIN_ReleasePtr( wndPtr );
2060 SetLastError( ERROR_INVALID_INDEX );
2063 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2065 /* Special case for dialog window procedure */
2066 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2067 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2068 WIN_ReleasePtr( wndPtr );
2074 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
2075 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2076 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2077 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
2078 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2080 /* This looks like a hack only for the edit control (see tests). This makes these controls
2081 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2082 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2084 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2085 retvalue = (ULONG_PTR)wndPtr->winproc;
2087 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2090 WARN("Unknown offset %d\n", offset );
2091 SetLastError( ERROR_INVALID_INDEX );
2094 WIN_ReleasePtr(wndPtr);
2099 /**********************************************************************
2102 * Helper function for SetWindowLong().
2104 * 0 is the failure code. However, in the case of failure SetLastError
2105 * must be set to distinguish between a 0 return value and a failure.
2107 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2111 LONG_PTR retval = 0;
2114 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2116 if (is_broadcast(hwnd))
2118 SetLastError( ERROR_INVALID_PARAMETER );
2122 if (!(wndPtr = WIN_GetPtr( hwnd )))
2124 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2127 if (wndPtr == WND_DESKTOP)
2129 /* can't change anything on the desktop window */
2130 SetLastError( ERROR_ACCESS_DENIED );
2133 if (wndPtr == WND_OTHER_PROCESS)
2135 if (offset == GWLP_WNDPROC)
2137 SetLastError( ERROR_ACCESS_DENIED );
2140 if (offset > 32767 || offset < -32767)
2142 SetLastError( ERROR_INVALID_INDEX );
2145 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2148 /* first some special cases */
2154 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2155 style.styleNew = newval;
2156 WIN_ReleasePtr( wndPtr );
2157 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2158 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2159 newval = style.styleNew;
2161 case GWLP_HWNDPARENT:
2162 if (wndPtr->parent == GetDesktopWindow())
2164 WIN_ReleasePtr( wndPtr );
2165 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2169 WIN_ReleasePtr( wndPtr );
2170 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2175 UINT old_flags = wndPtr->flags;
2176 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2177 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2178 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2179 if (proc) wndPtr->winproc = proc;
2180 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2181 else wndPtr->flags &= ~WIN_ISUNICODE;
2182 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2184 WIN_ReleasePtr( wndPtr );
2187 /* update is_unicode flag on the server side */
2191 case GWLP_HINSTANCE:
2195 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2196 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2198 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2199 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2200 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2201 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2202 WIN_ReleasePtr( wndPtr );
2207 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2209 WARN("Invalid offset %d\n", offset );
2210 WIN_ReleasePtr( wndPtr );
2211 SetLastError( ERROR_INVALID_INDEX );
2214 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2216 /* already set to the same value */
2217 WIN_ReleasePtr( wndPtr );
2223 SERVER_START_REQ( set_window_info )
2225 req->handle = wine_server_user_handle( hwnd );
2226 req->extra_offset = -1;
2230 req->flags = SET_WIN_STYLE;
2231 req->style = newval;
2234 req->flags = SET_WIN_EXSTYLE;
2235 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2236 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2237 req->ex_style = newval;
2240 req->flags = SET_WIN_ID;
2243 case GWLP_HINSTANCE:
2244 req->flags = SET_WIN_INSTANCE;
2245 req->instance = wine_server_client_ptr( (void *)newval );
2248 req->flags = SET_WIN_UNICODE;
2249 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2252 req->flags = SET_WIN_USERDATA;
2253 req->user_data = newval;
2256 req->flags = SET_WIN_EXTRA;
2257 req->extra_offset = offset;
2258 req->extra_size = size;
2259 set_win_data( &req->extra_value, newval, size );
2261 if ((ok = !wine_server_call_err( req )))
2266 wndPtr->dwStyle = newval;
2267 retval = reply->old_style;
2270 wndPtr->dwExStyle = newval;
2271 retval = reply->old_ex_style;
2274 wndPtr->wIDmenu = newval;
2275 retval = reply->old_id;
2277 case GWLP_HINSTANCE:
2278 wndPtr->hInstance = (HINSTANCE)newval;
2279 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2284 wndPtr->userdata = newval;
2285 retval = reply->old_user_data;
2288 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2289 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2295 WIN_ReleasePtr( wndPtr );
2299 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2301 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2302 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2309 /**********************************************************************
2310 * GetWindowLong (USER.135)
2312 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2316 BOOL is_winproc = (offset == GWLP_WNDPROC);
2320 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2322 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2325 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2327 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2330 * Some programs try to access last element from 16 bit
2331 * code using illegal offset value. Hopefully this is
2332 * what those programs really expect.
2334 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2336 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2337 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2342 WARN("Invalid offset %d\n", offset );
2343 WIN_ReleasePtr( wndPtr );
2344 SetLastError( ERROR_INVALID_INDEX );
2348 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2349 WIN_ReleasePtr( wndPtr );
2352 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2353 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2358 /**********************************************************************
2359 * GetWindowWord (USER32.@)
2361 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2366 case GWLP_HINSTANCE:
2367 case GWLP_HWNDPARENT:
2372 WARN("Invalid offset %d\n", offset );
2373 SetLastError( ERROR_INVALID_INDEX );
2378 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2382 /**********************************************************************
2383 * GetWindowLongA (USER32.@)
2385 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2387 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2391 /**********************************************************************
2392 * GetWindowLongW (USER32.@)
2394 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2396 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2400 /**********************************************************************
2401 * SetWindowLong (USER.136)
2403 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2406 BOOL is_winproc = (offset == GWLP_WNDPROC);
2408 if (offset == DWLP_DLGPROC)
2410 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2412 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2415 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2417 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2418 (wndPtr->flags & WIN_ISDIALOG));
2419 WIN_ReleasePtr( wndPtr );
2425 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2426 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2427 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2429 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2433 /**********************************************************************
2434 * SetWindowWord (USER32.@)
2436 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2441 case GWLP_HINSTANCE:
2442 case GWLP_HWNDPARENT:
2447 WARN("Invalid offset %d\n", offset );
2448 SetLastError( ERROR_INVALID_INDEX );
2453 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2457 /**********************************************************************
2458 * SetWindowLongA (USER32.@)
2460 * See SetWindowLongW.
2462 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2464 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2468 /**********************************************************************
2469 * SetWindowLongW (USER32.@) Set window attribute
2471 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2472 * value in a window's extra memory.
2474 * The _hwnd_ parameter specifies the window. is the handle to a
2475 * window that has extra memory. The _newval_ parameter contains the
2476 * new attribute or extra memory value. If positive, the _offset_
2477 * parameter is the byte-addressed location in the window's extra
2478 * memory to set. If negative, _offset_ specifies the window
2479 * attribute to set, and should be one of the following values:
2481 * GWL_EXSTYLE The window's extended window style
2483 * GWL_STYLE The window's window style.
2485 * GWLP_WNDPROC Pointer to the window's window procedure.
2487 * GWLP_HINSTANCE The window's pplication instance handle.
2489 * GWLP_ID The window's identifier.
2491 * GWLP_USERDATA The window's user-specified data.
2493 * If the window is a dialog box, the _offset_ parameter can be one of
2494 * the following values:
2496 * DWLP_DLGPROC The address of the window's dialog box procedure.
2498 * DWLP_MSGRESULT The return value of a message
2499 * that the dialog box procedure processed.
2501 * DWLP_USER Application specific information.
2505 * If successful, returns the previous value located at _offset_. Otherwise,
2510 * Extra memory for a window class is specified by a nonzero cbWndExtra
2511 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2512 * time of class creation.
2514 * Using GWL_WNDPROC to set a new window procedure effectively creates
2515 * a window subclass. Use CallWindowProc() in the new windows procedure
2516 * to pass messages to the superclass's window procedure.
2518 * The user data is reserved for use by the application which created
2521 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2522 * instead, call the EnableWindow() function to change the window's
2525 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2526 * SetParent() instead.
2529 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2530 * it sends WM_STYLECHANGING before changing the settings
2531 * and WM_STYLECHANGED afterwards.
2532 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2534 LONG WINAPI SetWindowLongW(
2535 HWND hwnd, /* [in] window to alter */
2536 INT offset, /* [in] offset, in bytes, of location to alter */
2537 LONG newval /* [in] new value of location */
2539 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2543 /*******************************************************************
2544 * GetWindowTextA (USER32.@)
2546 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2550 if (!lpString) return 0;
2552 if (WIN_IsCurrentProcess( hwnd ))
2553 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2555 /* when window belongs to other process, don't send a message */
2556 if (nMaxCount <= 0) return 0;
2557 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2558 get_server_window_text( hwnd, buffer, nMaxCount );
2559 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2560 lpString[nMaxCount-1] = 0;
2561 HeapFree( GetProcessHeap(), 0, buffer );
2562 return strlen(lpString);
2566 /*******************************************************************
2567 * InternalGetWindowText (USER32.@)
2569 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2573 if (nMaxCount <= 0) return 0;
2574 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2575 if (win == WND_DESKTOP) lpString[0] = 0;
2576 else if (win != WND_OTHER_PROCESS)
2578 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2579 else lpString[0] = 0;
2580 WIN_ReleasePtr( win );
2584 get_server_window_text( hwnd, lpString, nMaxCount );
2586 return strlenW(lpString);
2590 /*******************************************************************
2591 * GetWindowTextW (USER32.@)
2593 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2595 if (!lpString) return 0;
2597 if (WIN_IsCurrentProcess( hwnd ))
2598 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2600 /* when window belongs to other process, don't send a message */
2601 if (nMaxCount <= 0) return 0;
2602 get_server_window_text( hwnd, lpString, nMaxCount );
2603 return strlenW(lpString);
2607 /*******************************************************************
2608 * SetWindowTextA (USER32.@)
2609 * SetWindowText (USER32.@)
2611 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2613 if (is_broadcast(hwnd))
2615 SetLastError( ERROR_INVALID_PARAMETER );
2618 if (!WIN_IsCurrentProcess( hwnd ))
2619 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2620 debugstr_a(lpString), hwnd );
2621 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2625 /*******************************************************************
2626 * SetWindowTextW (USER32.@)
2628 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2630 if (is_broadcast(hwnd))
2632 SetLastError( ERROR_INVALID_PARAMETER );
2635 if (!WIN_IsCurrentProcess( hwnd ))
2636 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2637 debugstr_w(lpString), hwnd );
2638 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2642 /*******************************************************************
2643 * GetWindowTextLengthA (USER32.@)
2645 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2647 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2650 /*******************************************************************
2651 * GetWindowTextLengthW (USER32.@)
2653 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2655 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2659 /*******************************************************************
2660 * IsWindow (USER32.@)
2662 BOOL WINAPI IsWindow( HWND hwnd )
2667 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2668 if (ptr == WND_DESKTOP) return TRUE;
2670 if (ptr != WND_OTHER_PROCESS)
2672 WIN_ReleasePtr( ptr );
2676 /* check other processes */
2677 SERVER_START_REQ( get_window_info )
2679 req->handle = wine_server_user_handle( hwnd );
2680 ret = !wine_server_call_err( req );
2687 /***********************************************************************
2688 * GetWindowThreadProcessId (USER32.@)
2690 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2695 if (!(ptr = WIN_GetPtr( hwnd )))
2697 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2701 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2703 /* got a valid window */
2705 if (process) *process = GetCurrentProcessId();
2706 WIN_ReleasePtr( ptr );
2710 /* check other processes */
2711 SERVER_START_REQ( get_window_info )
2713 req->handle = wine_server_user_handle( hwnd );
2714 if (!wine_server_call_err( req ))
2716 tid = (DWORD)reply->tid;
2717 if (process) *process = (DWORD)reply->pid;
2725 /*****************************************************************
2726 * GetParent (USER32.@)
2728 HWND WINAPI GetParent( HWND hwnd )
2733 if (!(wndPtr = WIN_GetPtr( hwnd )))
2735 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2738 if (wndPtr == WND_DESKTOP) return 0;
2739 if (wndPtr == WND_OTHER_PROCESS)
2741 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2742 if (style & (WS_POPUP | WS_CHILD))
2744 SERVER_START_REQ( get_window_tree )
2746 req->handle = wine_server_user_handle( hwnd );
2747 if (!wine_server_call_err( req ))
2749 if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2750 else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2758 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2759 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2760 WIN_ReleasePtr( wndPtr );
2766 /*****************************************************************
2767 * GetAncestor (USER32.@)
2769 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2772 HWND *list, ret = 0;
2777 if (!(win = WIN_GetPtr( hwnd )))
2779 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2782 if (win == WND_DESKTOP) return 0;
2783 if (win != WND_OTHER_PROCESS)
2786 WIN_ReleasePtr( win );
2788 else /* need to query the server */
2790 SERVER_START_REQ( get_window_tree )
2792 req->handle = wine_server_user_handle( hwnd );
2793 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2800 if (!(list = list_window_parents( hwnd ))) return 0;
2802 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2806 while (list[count]) count++;
2807 ret = list[count - 2]; /* get the one before the desktop */
2809 HeapFree( GetProcessHeap(), 0, list );
2813 if (is_desktop_window( hwnd )) return 0;
2814 ret = WIN_GetFullHandle( hwnd );
2817 HWND parent = GetParent( ret );
2827 /*****************************************************************
2828 * SetParent (USER32.@)
2830 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2833 HWND old_parent = 0;
2838 if (is_broadcast(hwnd) || is_broadcast(parent))
2840 SetLastError(ERROR_INVALID_PARAMETER);
2844 if (!parent) parent = GetDesktopWindow();
2845 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2846 else parent = WIN_GetFullHandle( parent );
2848 if (!IsWindow( parent ))
2850 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2854 /* Some applications try to set a child as a parent */
2855 if (IsChild(hwnd, parent))
2857 SetLastError( ERROR_INVALID_PARAMETER );
2861 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2862 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2864 /* Windows hides the window first, then shows it again
2865 * including the WM_SHOWWINDOW messages and all */
2866 was_visible = ShowWindow( hwnd, SW_HIDE );
2868 wndPtr = WIN_GetPtr( hwnd );
2869 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2871 SERVER_START_REQ( set_parent )
2873 req->handle = wine_server_user_handle( hwnd );
2874 req->parent = wine_server_user_handle( parent );
2875 if ((ret = !wine_server_call( req )))
2877 old_parent = wine_server_ptr_handle( reply->old_parent );
2878 wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2883 WIN_ReleasePtr( wndPtr );
2886 USER_Driver->pSetParent( full_handle, parent, old_parent );
2888 /* SetParent additionally needs to make hwnd the topmost window
2889 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2890 WM_WINDOWPOSCHANGED notification messages.
2892 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2893 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2894 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2895 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2901 /*******************************************************************
2902 * IsChild (USER32.@)
2904 BOOL WINAPI IsChild( HWND parent, HWND child )
2906 HWND *list = list_window_parents( child );
2910 if (!list) return FALSE;
2911 parent = WIN_GetFullHandle( parent );
2912 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2913 ret = list[i] && list[i+1];
2914 HeapFree( GetProcessHeap(), 0, list );
2919 /***********************************************************************
2920 * IsWindowVisible (USER32.@)
2922 BOOL WINAPI IsWindowVisible( HWND hwnd )
2928 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2929 if (!(list = list_window_parents( hwnd ))) return TRUE;
2932 for (i = 0; list[i+1]; i++)
2933 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2934 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2936 HeapFree( GetProcessHeap(), 0, list );
2941 /***********************************************************************
2942 * WIN_IsWindowDrawable
2944 * hwnd is drawable when it is visible, all parents are not
2945 * minimized, and it is itself not minimized unless we are
2946 * trying to draw its default class icon.
2948 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2953 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2955 if (!(style & WS_VISIBLE)) return FALSE;
2956 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2958 if (!(list = list_window_parents( hwnd ))) return TRUE;
2961 for (i = 0; list[i+1]; i++)
2962 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2964 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2966 HeapFree( GetProcessHeap(), 0, list );
2971 /*******************************************************************
2972 * GetTopWindow (USER32.@)
2974 HWND WINAPI GetTopWindow( HWND hwnd )
2976 if (!hwnd) hwnd = GetDesktopWindow();
2977 return GetWindow( hwnd, GW_CHILD );
2981 /*******************************************************************
2982 * GetWindow (USER32.@)
2984 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2988 if (rel == GW_OWNER) /* this one may be available locally */
2990 WND *wndPtr = WIN_GetPtr( hwnd );
2993 SetLastError( ERROR_INVALID_HANDLE );
2996 if (wndPtr == WND_DESKTOP) return 0;
2997 if (wndPtr != WND_OTHER_PROCESS)
2999 retval = wndPtr->owner;
3000 WIN_ReleasePtr( wndPtr );
3003 /* else fall through to server call */
3006 SERVER_START_REQ( get_window_tree )
3008 req->handle = wine_server_user_handle( hwnd );
3009 if (!wine_server_call_err( req ))
3014 retval = wine_server_ptr_handle( reply->first_sibling );
3017 retval = wine_server_ptr_handle( reply->last_sibling );
3020 retval = wine_server_ptr_handle( reply->next_sibling );
3023 retval = wine_server_ptr_handle( reply->prev_sibling );
3026 retval = wine_server_ptr_handle( reply->owner );
3029 retval = wine_server_ptr_handle( reply->first_child );
3039 /*******************************************************************
3040 * ShowOwnedPopups (USER32.@)
3042 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3046 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3048 if (!win_array) return TRUE;
3050 while (win_array[count]) count++;
3051 while (--count >= 0)
3053 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3054 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3055 if (pWnd == WND_OTHER_PROCESS) continue;
3058 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3060 WIN_ReleasePtr( pWnd );
3061 /* In Windows, ShowOwnedPopups(TRUE) generates
3062 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3063 * regardless of the state of the owner
3065 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3071 if (pWnd->dwStyle & WS_VISIBLE)
3073 WIN_ReleasePtr( pWnd );
3074 /* In Windows, ShowOwnedPopups(FALSE) generates
3075 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3076 * regardless of the state of the owner
3078 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3082 WIN_ReleasePtr( pWnd );
3084 HeapFree( GetProcessHeap(), 0, win_array );
3089 /*******************************************************************
3090 * GetLastActivePopup (USER32.@)
3092 HWND WINAPI GetLastActivePopup( HWND hwnd )
3096 SERVER_START_REQ( get_window_info )
3098 req->handle = wine_server_user_handle( hwnd );
3099 if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3106 /*******************************************************************
3109 * Build an array of the children of a given window. The array must be
3110 * freed with HeapFree. Returns NULL when no windows are found.
3112 HWND *WIN_ListChildren( HWND hwnd )
3116 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3119 return list_window_children( 0, hwnd, NULL, 0 );
3123 /*******************************************************************
3124 * EnumWindows (USER32.@)
3126 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3132 USER_CheckNotLock();
3134 /* We have to build a list of all windows first, to avoid */
3135 /* unpleasant side-effects, for instance if the callback */
3136 /* function changes the Z-order of the windows. */
3138 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3140 /* Now call the callback function for every window */
3142 for (i = 0; list[i]; i++)
3144 /* Make sure that the window still exists */
3145 if (!IsWindow( list[i] )) continue;
3146 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3148 HeapFree( GetProcessHeap(), 0, list );
3153 /**********************************************************************
3154 * EnumThreadWindows (USER32.@)
3156 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3162 USER_CheckNotLock();
3164 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3166 /* Now call the callback function for every window */
3168 for (i = 0; list[i]; i++)
3169 if (!(ret = func( list[i], lParam ))) break;
3170 HeapFree( GetProcessHeap(), 0, list );
3175 /***********************************************************************
3176 * EnumDesktopWindows (USER32.@)
3178 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3183 USER_CheckNotLock();
3185 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3187 for (i = 0; list[i]; i++)
3188 if (!func( list[i], lparam )) break;
3189 HeapFree( GetProcessHeap(), 0, list );
3194 /**********************************************************************
3195 * WIN_EnumChildWindows
3197 * Helper function for EnumChildWindows().
3199 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3204 for ( ; *list; list++)
3206 /* Make sure that the window still exists */
3207 if (!IsWindow( *list )) continue;
3208 /* Build children list first */
3209 childList = WIN_ListChildren( *list );
3211 ret = func( *list, lParam );
3215 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3216 HeapFree( GetProcessHeap(), 0, childList );
3218 if (!ret) return FALSE;
3224 /**********************************************************************
3225 * EnumChildWindows (USER32.@)
3227 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3232 USER_CheckNotLock();
3234 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3235 ret = WIN_EnumChildWindows( list, func, lParam );
3236 HeapFree( GetProcessHeap(), 0, list );
3241 /*******************************************************************
3242 * AnyPopup (USER.52)
3244 BOOL16 WINAPI AnyPopup16(void)
3250 /*******************************************************************
3251 * AnyPopup (USER32.@)
3253 BOOL WINAPI AnyPopup(void)
3257 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3259 if (!list) return FALSE;
3260 for (i = 0; list[i]; i++)
3262 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3264 retvalue = (list[i] != 0);
3265 HeapFree( GetProcessHeap(), 0, list );
3270 /*******************************************************************
3271 * FlashWindow (USER32.@)
3273 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3277 TRACE("%p\n", hWnd);
3279 if (IsIconic( hWnd ))
3281 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3283 wndPtr = WIN_GetPtr(hWnd);
3284 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3285 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3287 wndPtr->flags |= WIN_NCACTIVATED;
3291 wndPtr->flags &= ~WIN_NCACTIVATED;
3293 WIN_ReleasePtr( wndPtr );
3300 wndPtr = WIN_GetPtr(hWnd);
3301 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3302 hWnd = wndPtr->obj.handle; /* make it a full handle */
3304 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3305 else wparam = (hWnd == GetForegroundWindow());
3307 WIN_ReleasePtr( wndPtr );
3308 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3313 /*******************************************************************
3314 * FlashWindowEx (USER32.@)
3316 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3318 FIXME("%p\n", pfwi);
3322 /*******************************************************************
3323 * GetWindowContextHelpId (USER32.@)
3325 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3328 WND *wnd = WIN_GetPtr( hwnd );
3329 if (!wnd || wnd == WND_DESKTOP) return 0;
3330 if (wnd == WND_OTHER_PROCESS)
3332 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3335 retval = wnd->helpContext;
3336 WIN_ReleasePtr( wnd );
3341 /*******************************************************************
3342 * SetWindowContextHelpId (USER32.@)
3344 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3346 WND *wnd = WIN_GetPtr( hwnd );
3347 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3348 if (wnd == WND_OTHER_PROCESS)
3350 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3353 wnd->helpContext = id;
3354 WIN_ReleasePtr( wnd );
3359 /*******************************************************************
3360 * DragDetect (USER32.@)
3362 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3366 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3367 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3369 rect.left = pt.x - wDragWidth;
3370 rect.right = pt.x + wDragWidth;
3372 rect.top = pt.y - wDragHeight;
3373 rect.bottom = pt.y + wDragHeight;
3379 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3381 if( msg.message == WM_LBUTTONUP )
3386 if( msg.message == WM_MOUSEMOVE )
3389 tmp.x = (short)LOWORD(msg.lParam);
3390 tmp.y = (short)HIWORD(msg.lParam);
3391 if( !PtInRect( &rect, tmp ))
3403 /******************************************************************************
3404 * GetWindowModuleFileNameA (USER32.@)
3406 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3411 TRACE( "%p, %p, %u\n", hwnd, module, size );
3413 win = WIN_GetPtr( hwnd );
3414 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3416 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3419 hinst = win->hInstance;
3420 WIN_ReleasePtr( win );
3422 return GetModuleFileNameA( hinst, module, size );
3425 /******************************************************************************
3426 * GetWindowModuleFileNameW (USER32.@)
3428 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3433 TRACE( "%p, %p, %u\n", hwnd, module, size );
3435 win = WIN_GetPtr( hwnd );
3436 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3438 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3441 hinst = win->hInstance;
3442 WIN_ReleasePtr( win );
3444 return GetModuleFileNameW( hinst, module, size );
3447 /******************************************************************************
3448 * GetWindowInfo (USER32.@)
3450 * Note: tests show that Windows doesn't check cbSize of the structure.
3452 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3454 if (!pwi) return FALSE;
3455 if (!IsWindow(hwnd)) return FALSE;
3457 GetWindowRect(hwnd, &pwi->rcWindow);
3458 GetClientRect(hwnd, &pwi->rcClient);
3459 /* translate to screen coordinates */
3460 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3462 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3463 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3464 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3466 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3467 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3469 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3470 pwi->wCreatorVersion = 0x0400;
3475 /******************************************************************************
3476 * SwitchDesktop (USER32.@)
3478 * NOTES: Sets the current input or interactive desktop.
3480 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3482 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3486 /*****************************************************************************
3487 * SetLayeredWindowAttributes (USER32.@)
3489 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3493 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3495 SERVER_START_REQ( set_window_layered_info )
3497 req->handle = wine_server_user_handle( hwnd );
3498 req->color_key = key;
3501 ret = !wine_server_call_err( req );
3505 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3511 /*****************************************************************************
3512 * GetLayeredWindowAttributes (USER32.@)
3514 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3518 SERVER_START_REQ( get_window_layered_info )
3520 req->handle = wine_server_user_handle( hwnd );
3521 if ((ret = !wine_server_call_err( req )))
3523 if (key) *key = reply->color_key;
3524 if (alpha) *alpha = reply->alpha;
3525 if (flags) *flags = reply->flags;
3534 /*****************************************************************************
3535 * UpdateLayeredWindowIndirect (USER32.@)
3537 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3541 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3543 int x = 0, y = 0, cx = 0, cy = 0;
3544 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3548 x = info->pptDst->x;
3549 y = info->pptDst->y;
3550 flags &= ~SWP_NOMOVE;
3554 cx = info->psize->cx;
3555 cy = info->psize->cy;
3556 flags &= ~SWP_NOSIZE;
3558 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3559 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3565 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3571 GetClientRect( hwnd, &rect );
3574 x = info->pptSrc->x;
3575 y = info->pptSrc->y;
3577 /* FIXME: intersect rect with info->prcDirty */
3578 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3579 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3580 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3581 ReleaseDC( hwnd, hdc );
3585 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3586 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3587 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3588 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3593 /*****************************************************************************
3594 * UpdateLayeredWindow (USER32.@)
3596 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3597 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3600 UPDATELAYEREDWINDOWINFO info;
3602 info.cbSize = sizeof(info);
3603 info.hdcDst = hdcDst;
3604 info.pptDst = pptDst;
3606 info.hdcSrc = hdcSrc;
3607 info.pptSrc = pptSrc;
3609 info.pblend = pblend;
3610 info.dwFlags = dwFlags;
3611 info.prcDirty = NULL;
3612 return UpdateLayeredWindowIndirect( hwnd, &info );
3615 /* 64bit versions */
3617 #ifdef GetWindowLongPtrW
3618 #undef GetWindowLongPtrW
3621 #ifdef GetWindowLongPtrA
3622 #undef GetWindowLongPtrA
3625 #ifdef SetWindowLongPtrW
3626 #undef SetWindowLongPtrW
3629 #ifdef SetWindowLongPtrA
3630 #undef SetWindowLongPtrA
3633 /*****************************************************************************
3634 * GetWindowLongPtrW (USER32.@)
3636 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3638 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3641 /*****************************************************************************
3642 * GetWindowLongPtrA (USER32.@)
3644 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3646 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3649 /*****************************************************************************
3650 * SetWindowLongPtrW (USER32.@)
3652 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3654 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3657 /*****************************************************************************
3658 * SetWindowLongPtrA (USER32.@)
3660 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3662 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );