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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
39 #include "cursoricon.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(win);
46 WINE_DECLARE_DEBUG_CHANNEL(msg);
48 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
50 /**********************************************************************/
53 static WND *pWndDesktop = NULL;
55 static WORD wDragWidth = 4;
56 static WORD wDragHeight= 3;
58 static void *user_handles[NB_USER_HANDLES];
60 /***********************************************************************
61 * create_window_handle
63 * Create a window handle with the server.
65 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
66 HINSTANCE instance, WINDOWPROCTYPE type )
70 struct tagCLASS *class = NULL;
71 user_handle_t handle = 0;
74 /* if 16-bit instance, map to module handle */
75 if (instance && !HIWORD(instance))
76 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
78 SERVER_START_REQ( create_window )
83 req->instance = instance;
84 if (!wine_server_call_err( req ))
86 handle = reply->handle;
87 extra_bytes = reply->extra;
88 class = reply->class_ptr;
95 WARN( "error %ld creating window\n", GetLastError() );
99 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
101 SERVER_START_REQ( destroy_window )
103 req->handle = handle;
104 wine_server_call( req );
107 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
113 index = LOWORD(handle) - FIRST_USER_HANDLE;
114 assert( index < NB_USER_HANDLES );
115 user_handles[index] = win;
116 win->hwndSelf = handle;
117 win->dwMagic = WND_MAGIC;
119 win->cbWndExtra = extra_bytes;
120 memset( win->wExtra, 0, extra_bytes );
121 CLASS_AddWindow( class, win, type );
126 /***********************************************************************
129 * Free a window handle.
131 static WND *free_window_handle( HWND hwnd )
134 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
136 if (index >= NB_USER_HANDLES) return NULL;
138 if ((ptr = user_handles[index]))
140 SERVER_START_REQ( destroy_window )
143 if (!wine_server_call_err( req ))
144 user_handles[index] = NULL;
151 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
156 /*******************************************************************
157 * list_window_children
159 * Build an array of the children of a given window. The array must be
160 * freed with HeapFree. Returns NULL when no windows are found.
162 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
171 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
173 SERVER_START_REQ( get_window_children )
178 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
179 if (!wine_server_call( req )) count = reply->count;
182 if (count && count < size)
187 HeapFree( GetProcessHeap(), 0, list );
189 size = count + 1; /* restart with a large enough buffer */
195 /*******************************************************************
198 static void send_parent_notify( HWND hwnd, UINT msg )
200 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
201 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
202 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
203 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
207 /*******************************************************************
208 * get_server_window_text
210 * Retrieve the window text from the server.
212 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
216 SERVER_START_REQ( get_window_text )
219 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
220 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
223 text[len / sizeof(WCHAR)] = 0;
227 /***********************************************************************
230 * Return a pointer to the WND structure if local to the process,
231 * or WND_OTHER_PROCESS if handle may be valid in other process.
232 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
234 WND *WIN_GetPtr( HWND hwnd )
237 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
239 if (index >= NB_USER_HANDLES) return NULL;
242 if ((ptr = user_handles[index]))
244 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
248 else ptr = WND_OTHER_PROCESS;
254 /***********************************************************************
255 * WIN_IsCurrentProcess
257 * Check whether a given window belongs to the current process (and return the full handle).
259 HWND WIN_IsCurrentProcess( HWND hwnd )
264 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
266 WIN_ReleasePtr( ptr );
271 /***********************************************************************
272 * WIN_IsCurrentThread
274 * Check whether a given window belongs to the current thread (and return the full handle).
276 HWND WIN_IsCurrentThread( HWND hwnd )
281 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
283 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
284 WIN_ReleasePtr( ptr );
290 /***********************************************************************
293 * Convert a 16-bit window handle to a full 32-bit handle.
295 HWND WIN_Handle32( HWND16 hwnd16 )
298 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
300 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
301 /* do sign extension for -2 and -3 */
302 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
304 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
306 if (ptr != WND_OTHER_PROCESS)
308 hwnd = ptr->hwndSelf;
309 WIN_ReleasePtr( ptr );
311 else /* may belong to another process */
313 SERVER_START_REQ( get_window_info )
316 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
324 /***********************************************************************
327 * Return a pointer to the WND structure corresponding to a HWND.
329 WND * WIN_FindWndPtr( HWND hwnd )
333 if (!hwnd) return NULL;
335 if ((ptr = WIN_GetPtr( hwnd )))
337 if (ptr != WND_OTHER_PROCESS)
339 /* increment destruction monitoring */
343 if (IsWindow( hwnd )) /* check other processes */
345 ERR( "window %p belongs to other process\n", hwnd );
346 /* DbgBreakPoint(); */
349 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
354 /***********************************************************************
357 * Release the pointer to the WND structure.
359 void WIN_ReleaseWndPtr(WND *wndPtr)
363 /* Decrement destruction monitoring value */
365 /* Check if it's time to release the memory */
366 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
369 free_window_handle( wndPtr->hwndSelf );
371 else if(wndPtr->irefCount < 0)
373 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
374 ERR("forgot a Lock on %p somewhere\n",wndPtr);
376 /* unlock all WND structures for thread safeness */
381 /***********************************************************************
384 * Remove a window from the siblings linked list.
386 void WIN_UnlinkWindow( HWND hwnd )
388 WIN_LinkWindow( hwnd, 0, 0 );
392 /***********************************************************************
395 * Insert a window into the siblings linked list.
396 * The window is inserted after the specified window, which can also
397 * be specified as HWND_TOP or HWND_BOTTOM.
398 * If parent is 0, window is unlinked from the tree.
400 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
402 WND *wndPtr = WIN_GetPtr( hwnd );
405 if (wndPtr == WND_OTHER_PROCESS)
407 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
411 SERVER_START_REQ( link_window )
414 req->parent = parent;
415 req->previous = hwndInsertAfter;
416 if (!wine_server_call( req ))
418 if (reply->full_parent) wndPtr->parent = reply->full_parent;
423 WIN_ReleasePtr( wndPtr );
427 /***********************************************************************
430 * Change the owner of a window.
432 HWND WIN_SetOwner( HWND hwnd, HWND owner )
434 WND *win = WIN_GetPtr( hwnd );
438 if (win == WND_OTHER_PROCESS)
440 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
443 SERVER_START_REQ( set_window_owner )
447 if (!wine_server_call( req ))
449 win->owner = reply->full_owner;
450 ret = reply->prev_owner;
454 WIN_ReleasePtr( win );
459 /***********************************************************************
462 * Change the style of a window.
464 LONG WIN_SetStyle( HWND hwnd, LONG style )
468 WND *win = WIN_GetPtr( hwnd );
471 if (win == WND_OTHER_PROCESS)
474 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
477 if (style == win->dwStyle)
479 WIN_ReleasePtr( win );
482 SERVER_START_REQ( set_window_info )
485 req->flags = SET_WIN_STYLE;
487 req->extra_offset = -1;
488 if ((ok = !wine_server_call( req )))
490 ret = reply->old_style;
491 win->dwStyle = style;
495 WIN_ReleasePtr( win );
496 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
501 /***********************************************************************
504 * Change the extended style of a window.
506 LONG WIN_SetExStyle( HWND hwnd, LONG style )
509 WND *win = WIN_GetPtr( hwnd );
512 if (win == WND_OTHER_PROCESS)
515 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
518 if (style == win->dwExStyle)
520 WIN_ReleasePtr( win );
523 SERVER_START_REQ( set_window_info )
526 req->flags = SET_WIN_EXSTYLE;
527 req->ex_style = style;
528 req->extra_offset = -1;
529 if (!wine_server_call( req ))
531 ret = reply->old_ex_style;
532 win->dwExStyle = style;
536 WIN_ReleasePtr( win );
541 /***********************************************************************
544 * Set the window and client rectangles.
546 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
548 WND *win = WIN_GetPtr( hwnd );
552 if (win == WND_OTHER_PROCESS)
554 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
557 SERVER_START_REQ( set_window_rectangles )
560 req->window.left = rectWindow->left;
561 req->window.top = rectWindow->top;
562 req->window.right = rectWindow->right;
563 req->window.bottom = rectWindow->bottom;
564 req->client.left = rectClient->left;
565 req->client.top = rectClient->top;
566 req->client.right = rectClient->right;
567 req->client.bottom = rectClient->bottom;
568 ret = !wine_server_call( req );
573 win->rectWindow = *rectWindow;
574 win->rectClient = *rectClient;
576 TRACE( "win %p window (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", hwnd,
577 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
578 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
580 WIN_ReleasePtr( win );
584 /***********************************************************************
587 * Get the window and client rectangles.
589 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
591 WND *win = WIN_GetPtr( hwnd );
594 if (!win) return FALSE;
595 if (win == WND_OTHER_PROCESS)
597 SERVER_START_REQ( get_window_rectangles )
600 if ((ret = !wine_server_call( req )))
604 rectWindow->left = reply->window.left;
605 rectWindow->top = reply->window.top;
606 rectWindow->right = reply->window.right;
607 rectWindow->bottom = reply->window.bottom;
611 rectClient->left = reply->client.left;
612 rectClient->top = reply->client.top;
613 rectClient->right = reply->client.right;
614 rectClient->bottom = reply->client.bottom;
622 if (rectWindow) *rectWindow = win->rectWindow;
623 if (rectClient) *rectClient = win->rectClient;
624 WIN_ReleasePtr( win );
630 /***********************************************************************
633 * Destroy storage associated to a window. "Internals" p.358
635 LRESULT WIN_DestroyWindow( HWND hwnd )
640 TRACE("%p\n", hwnd );
642 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
644 ERR( "window doesn't belong to current thread\n" );
648 /* free child windows */
649 if ((list = WIN_ListChildren( hwnd )))
652 for (i = 0; list[i]; i++)
654 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
655 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
657 HeapFree( GetProcessHeap(), 0, list );
661 * Clear the update region to make sure no WM_PAINT messages will be
662 * generated for this window while processing the WM_NCDESTROY.
664 RedrawWindow( hwnd, NULL, 0,
665 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
668 * Send the WM_NCDESTROY to the window being destroyed.
670 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
672 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
674 WINPOS_CheckInternalPos( hwnd );
675 if( hwnd == GetCapture()) ReleaseCapture();
677 /* free resources associated with the window */
679 TIMER_RemoveWindowTimers( hwnd );
681 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
683 if (!(wndPtr->dwStyle & WS_CHILD))
685 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
686 if (menu) DestroyMenu( menu );
688 if (wndPtr->hSysMenu)
690 DestroyMenu( wndPtr->hSysMenu );
691 wndPtr->hSysMenu = 0;
693 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
694 USER_Driver.pDestroyWindow( hwnd );
695 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
696 wndPtr->class = NULL;
697 wndPtr->dwMagic = 0; /* Mark it as invalid */
698 WIN_ReleaseWndPtr( wndPtr );
702 /***********************************************************************
703 * WIN_DestroyThreadWindows
705 * Destroy all children of 'wnd' owned by the current thread.
706 * Return TRUE if something was done.
708 void WIN_DestroyThreadWindows( HWND hwnd )
713 if (!(list = WIN_ListChildren( hwnd ))) return;
714 for (i = 0; list[i]; i++)
716 if (WIN_IsCurrentThread( list[i] ))
717 DestroyWindow( list[i] );
719 WIN_DestroyThreadWindows( list[i] );
721 HeapFree( GetProcessHeap(), 0, list );
724 /***********************************************************************
725 * WIN_CreateDesktopWindow
727 * Create the desktop window.
729 BOOL WIN_CreateDesktopWindow(void)
735 TRACE("Creating desktop window\n");
737 if (!WINPOS_CreateInternalPosAtom()) return FALSE;
739 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
740 if (!pWndDesktop) return FALSE;
741 hwndDesktop = pWndDesktop->hwndSelf;
743 pWndDesktop->tid = 0; /* nobody owns the desktop */
744 pWndDesktop->parent = 0;
745 pWndDesktop->owner = 0;
746 pWndDesktop->text = NULL;
747 pWndDesktop->hrgnUpdate = 0;
748 pWndDesktop->pVScroll = NULL;
749 pWndDesktop->pHScroll = NULL;
750 pWndDesktop->helpContext = 0;
751 pWndDesktop->flags = 0;
752 pWndDesktop->hSysMenu = 0;
754 cs.lpCreateParams = NULL;
760 cs.cx = GetSystemMetrics( SM_CXSCREEN );
761 cs.cy = GetSystemMetrics( SM_CYSCREEN );
762 cs.style = pWndDesktop->dwStyle;
763 cs.dwExStyle = pWndDesktop->dwExStyle;
765 cs.lpszClass = DESKTOP_CLASS_ATOM;
767 SetRect( &rect, 0, 0, cs.cx, cs.cy );
768 WIN_SetRectangles( hwndDesktop, &rect, &rect );
770 SERVER_START_REQ( set_window_info )
772 req->handle = hwndDesktop;
773 req->flags = 0; /* don't set anything, just retrieve */
774 req->extra_offset = -1;
775 wine_server_call( req );
776 pWndDesktop->dwStyle = reply->old_style;
777 pWndDesktop->dwExStyle = reply->old_ex_style;
778 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
779 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
780 pWndDesktop->wIDmenu = reply->old_id;
784 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
786 WIN_ReleaseWndPtr( pWndDesktop );
790 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
791 WIN_ReleaseWndPtr( pWndDesktop );
796 /***********************************************************************
799 * Fix the coordinates - Helper for WIN_CreateWindowEx.
800 * returns default show mode in sw.
801 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
803 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
805 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
806 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
808 if (cs->style & (WS_CHILD | WS_POPUP))
810 if (cs->dwExStyle & WS_EX_MDICHILD)
814 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
816 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
821 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
823 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
828 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
830 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
834 else /* overlapped window */
838 GetStartupInfoA( &info );
840 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
842 /* Never believe Microsoft's documentation... CreateWindowEx doc says
843 * that if an overlapped window is created with WS_VISIBLE style bit
844 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
845 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
848 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
849 * 2) it does not ignore the y parameter as the docs claim; instead, it
850 * uses it as second parameter to ShowWindow() unless y is either
851 * CW_USEDEFAULT or CW_USEDEFAULT16.
853 * The fact that we didn't do 2) caused bogus windows pop up when wine
854 * was running apps that were using this obscure feature. Example -
855 * calc.exe that comes with Win98 (only Win98, it's different from
856 * the one that comes with Win95 and NT)
858 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
859 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
860 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
863 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
865 if (info.dwFlags & STARTF_USESIZE)
867 cs->cx = info.dwXSize;
868 cs->cy = info.dwYSize;
870 else /* if no other hint from the app, pick 3/4 of the screen real estate */
873 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
874 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
875 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
882 /* neither x nor cx are default. Check the y values .
883 * In the trace we see Outlook and Outlook Express using
884 * cy set to CW_USEDEFAULT when opening the address book.
886 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
888 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
889 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
890 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
895 /***********************************************************************
898 static void dump_window_styles( DWORD style, DWORD exstyle )
901 if(style & WS_POPUP) TRACE(" WS_POPUP");
902 if(style & WS_CHILD) TRACE(" WS_CHILD");
903 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
904 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
905 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
906 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
907 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
908 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
909 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
912 if(style & WS_BORDER) TRACE(" WS_BORDER");
913 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
915 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
916 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
917 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
918 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
919 if(style & WS_GROUP) TRACE(" WS_GROUP");
920 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
921 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
922 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
924 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
925 #define DUMPED_STYLES \
945 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
950 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
951 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
952 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
953 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
954 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
955 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
956 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
957 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
958 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
959 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
960 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
961 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
962 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
963 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
964 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
965 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
966 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
967 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
969 #define DUMPED_EX_STYLES \
970 (WS_EX_DLGMODALFRAME | \
972 WS_EX_NOPARENTNOTIFY | \
974 WS_EX_ACCEPTFILES | \
975 WS_EX_TRANSPARENT | \
980 WS_EX_CONTEXTHELP | \
983 WS_EX_LEFTSCROLLBAR | \
984 WS_EX_CONTROLPARENT | \
989 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
991 #undef DUMPED_EX_STYLES
995 /***********************************************************************
998 * Implementation of CreateWindowEx().
1000 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
1001 WINDOWPROCTYPE type )
1005 HWND hwnd, parent, owner, top_child = 0;
1006 BOOL unicode = (type == WIN_PROC_32W);
1008 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1009 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1010 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1011 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1012 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1014 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1016 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1017 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1019 /* Fix the styles for MDI children */
1020 if (cs->dwExStyle & WS_EX_MDICHILD)
1022 MDICREATESTRUCTA mdi_cs;
1025 wndPtr = WIN_GetPtr(cs->hwndParent);
1026 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
1028 flags = wndPtr->flags;
1029 WIN_ReleasePtr(wndPtr);
1032 if (!(flags & WIN_ISMDICLIENT))
1034 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1038 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1039 * MDICREATESTRUCT members have the originally passed values.
1041 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1042 * have the same layout.
1044 mdi_cs.szClass = cs->lpszClass;
1045 mdi_cs.szTitle = cs->lpszName;
1046 mdi_cs.hOwner = cs->hInstance;
1051 mdi_cs.style = cs->style;
1052 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1054 cs->lpCreateParams = (LPVOID)&mdi_cs;
1056 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1058 if (cs->style & WS_POPUP)
1060 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1063 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1067 cs->style &= ~WS_POPUP;
1068 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1069 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1072 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1075 /* Find the parent window */
1077 parent = GetDesktopWindow();
1080 if (cs->hwndParent == HWND_MESSAGE)
1082 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1083 * message window (style: WS_POPUP|WS_DISABLED)
1085 FIXME("Parent is HWND_MESSAGE\n");
1087 else if (cs->hwndParent)
1089 /* Make sure parent is valid */
1090 if (!IsWindow( cs->hwndParent ))
1092 WARN("Bad parent %p\n", cs->hwndParent );
1095 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1096 parent = WIN_GetFullHandle(cs->hwndParent);
1098 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1100 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1102 WARN("No parent for child window\n" );
1103 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1106 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1108 /* Correct the window styles.
1110 * It affects both the style loaded into the WIN structure and
1111 * passed in the CREATESTRUCT to the WM_[NC]CREATE.
1113 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1114 * why does the user get to set it?
1117 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1118 * tested for WS_POPUP
1120 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1121 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1122 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1123 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1125 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1127 if (!(cs->style & WS_CHILD))
1129 cs->style |= WS_CLIPSIBLINGS;
1130 if (!(cs->style & WS_POPUP))
1131 cs->style |= WS_CAPTION;
1134 /* Create the window structure */
1136 if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1138 TRACE("out of memory\n" );
1141 hwnd = wndPtr->hwndSelf;
1143 /* Fill the window structure */
1145 wndPtr->tid = GetCurrentThreadId();
1146 wndPtr->owner = owner;
1147 wndPtr->parent = parent;
1148 wndPtr->hInstance = cs->hInstance;
1149 wndPtr->text = NULL;
1150 wndPtr->hrgnUpdate = 0;
1151 wndPtr->hrgnWnd = 0;
1152 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1153 wndPtr->dwExStyle = cs->dwExStyle;
1154 wndPtr->wIDmenu = 0;
1155 wndPtr->helpContext = 0;
1156 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1157 wndPtr->pVScroll = NULL;
1158 wndPtr->pHScroll = NULL;
1159 wndPtr->userdata = 0;
1161 wndPtr->hIconSmall = 0;
1162 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1164 if (!(cs->style & (WS_CHILD | WS_POPUP)))
1165 wndPtr->flags |= WIN_NEED_SIZE;
1167 SERVER_START_REQ( set_window_info )
1170 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1171 req->style = wndPtr->dwStyle;
1172 req->ex_style = wndPtr->dwExStyle;
1173 req->instance = (void *)wndPtr->hInstance;
1174 req->extra_offset = -1;
1175 wine_server_call( req );
1179 /* Get class or window DC if needed */
1181 if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1183 /* Set the window menu */
1185 if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1186 (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1188 if (cs->hMenu) MENU_SetMenu(hwnd, cs->hMenu);
1191 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1194 if (HIWORD(cs->hInstance))
1195 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1197 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1199 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1203 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1204 WIN_ReleaseWndPtr( wndPtr );
1206 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1208 WIN_DestroyWindow( hwnd );
1212 /* Notify the parent window only */
1214 send_parent_notify( hwnd, WM_CREATE );
1215 if (!IsWindow( hwnd )) return 0;
1217 if (cs->dwExStyle & WS_EX_MDICHILD)
1221 /* Restore current maximized child */
1222 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1224 TRACE("Restoring current maximized child %p\n", top_child);
1225 ShowWindow(top_child, SW_SHOWNOACTIVATE);
1229 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1232 if (cs->style & WS_VISIBLE)
1234 /* in case WS_VISIBLE got set in the meantime */
1235 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1236 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1237 WIN_ReleasePtr( wndPtr );
1238 ShowWindow( hwnd, sw );
1241 /* Call WH_SHELL hook */
1243 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1244 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1246 TRACE("created window %p\n", hwnd);
1251 /***********************************************************************
1252 * CreateWindow (USER.41)
1254 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1255 DWORD style, INT16 x, INT16 y, INT16 width,
1256 INT16 height, HWND16 parent, HMENU16 menu,
1257 HINSTANCE16 instance, LPVOID data )
1259 return CreateWindowEx16( 0, className, windowName, style,
1260 x, y, width, height, parent, menu, instance, data );
1264 /***********************************************************************
1265 * CreateWindowEx (USER.452)
1267 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1268 LPCSTR windowName, DWORD style, INT16 x,
1269 INT16 y, INT16 width, INT16 height,
1270 HWND16 parent, HMENU16 menu,
1271 HINSTANCE16 instance, LPVOID data )
1277 /* Find the class atom */
1279 if (HIWORD(className))
1281 if (!(classAtom = GlobalFindAtomA( className )))
1283 ERR( "bad class name %s\n", debugstr_a(className) );
1289 classAtom = LOWORD(className);
1290 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1292 ERR( "bad atom %x\n", classAtom);
1298 /* Fix the coordinates */
1300 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1301 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1302 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1303 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1305 /* Create the window */
1307 cs.lpCreateParams = data;
1308 cs.hInstance = HINSTANCE_32(instance);
1309 cs.hMenu = HMENU_32(menu);
1310 cs.hwndParent = WIN_Handle32( parent );
1312 cs.lpszName = windowName;
1313 cs.lpszClass = className;
1314 cs.dwExStyle = exStyle;
1316 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1320 /***********************************************************************
1321 * CreateWindowExA (USER32.@)
1323 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1324 LPCSTR windowName, DWORD style, INT x,
1325 INT y, INT width, INT height,
1326 HWND parent, HMENU menu,
1327 HINSTANCE instance, LPVOID data )
1333 /* Find the class atom */
1335 if (HIWORD(className))
1337 if (!(classAtom = GlobalFindAtomA( className )))
1339 ERR( "bad class name %s\n", debugstr_a(className) );
1345 classAtom = LOWORD(className);
1346 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1348 ERR( "bad atom %x\n", classAtom);
1354 /* Create the window */
1356 cs.lpCreateParams = data;
1357 cs.hInstance = instance;
1359 cs.hwndParent = parent;
1365 cs.lpszName = windowName;
1366 cs.lpszClass = className;
1367 cs.dwExStyle = exStyle;
1369 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1373 /***********************************************************************
1374 * CreateWindowExW (USER32.@)
1376 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1377 LPCWSTR windowName, DWORD style, INT x,
1378 INT y, INT width, INT height,
1379 HWND parent, HMENU menu,
1380 HINSTANCE instance, LPVOID data )
1386 /* Find the class atom */
1388 if (HIWORD(className))
1390 if (!(classAtom = GlobalFindAtomW( className )))
1392 ERR( "bad class name %s\n", debugstr_w(className) );
1398 classAtom = LOWORD(className);
1399 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1401 ERR( "bad atom %x\n", classAtom);
1407 /* Create the window */
1409 cs.lpCreateParams = data;
1410 cs.hInstance = instance;
1412 cs.hwndParent = parent;
1418 cs.lpszName = windowName;
1419 cs.lpszClass = className;
1420 cs.dwExStyle = exStyle;
1422 /* Note: we rely on the fact that CREATESTRUCTA and */
1423 /* CREATESTRUCTW have the same layout. */
1424 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1428 /***********************************************************************
1429 * WIN_SendDestroyMsg
1431 static void WIN_SendDestroyMsg( HWND hwnd )
1435 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1437 if (hwnd == info.hwndCaret) DestroyCaret();
1439 if (USER_Driver.pResetSelectionOwner)
1440 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1443 * Send the WM_DESTROY to the window.
1445 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1448 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1449 * make sure that the window still exists when we come back.
1456 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1458 /* start from the end (FIXME: is this needed?) */
1459 for (i = 0; pWndArray[i]; i++) ;
1463 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1465 HeapFree( GetProcessHeap(), 0, pWndArray );
1468 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1472 /***********************************************************************
1473 * DestroyWindow (USER32.@)
1475 BOOL WINAPI DestroyWindow( HWND hwnd )
1480 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1482 SetLastError( ERROR_ACCESS_DENIED );
1486 TRACE("(%p)\n", hwnd);
1488 /* Look whether the focus is within the tree of windows we will
1492 if (h == hwnd || IsChild( hwnd, h ))
1494 HWND parent = GetAncestor( hwnd, GA_PARENT );
1495 if (parent == GetDesktopWindow()) parent = 0;
1499 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1500 SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
1504 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1506 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1510 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1511 send_parent_notify( hwnd, WM_DESTROY );
1513 else if (!GetWindow( hwnd, GW_OWNER ))
1515 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1516 /* FIXME: clean up palette - see "Internals" p.352 */
1519 if (!IsWindow(hwnd)) return TRUE;
1521 if (USER_Driver.pResetSelectionOwner)
1522 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1524 /* Hide the window */
1526 if (!ShowWindow( hwnd, SW_HIDE ))
1528 if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1530 if (!IsWindow(hwnd)) return TRUE;
1532 /* Recursively destroy owned windows */
1539 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1542 for (i = 0; list[i]; i++)
1544 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1545 if (WIN_IsCurrentThread( list[i] ))
1547 DestroyWindow( list[i] );
1551 WIN_SetOwner( list[i], 0 );
1553 HeapFree( GetProcessHeap(), 0, list );
1555 if (!got_one) break;
1559 /* Send destroy messages */
1561 WIN_SendDestroyMsg( hwnd );
1562 if (!IsWindow( hwnd )) return TRUE;
1564 if (GetClipboardOwner() == hwnd)
1565 CLIPBOARD_ReleaseOwner();
1567 /* Unlink now so we won't bother with the children later on */
1569 WIN_UnlinkWindow( hwnd );
1571 /* Destroy the window storage */
1573 WIN_DestroyWindow( hwnd );
1578 /***********************************************************************
1579 * CloseWindow (USER32.@)
1581 BOOL WINAPI CloseWindow( HWND hwnd )
1583 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1584 ShowWindow( hwnd, SW_MINIMIZE );
1589 /***********************************************************************
1590 * OpenIcon (USER32.@)
1592 BOOL WINAPI OpenIcon( HWND hwnd )
1594 if (!IsIconic( hwnd )) return FALSE;
1595 ShowWindow( hwnd, SW_SHOWNORMAL );
1600 /***********************************************************************
1603 * Implementation of FindWindow() and FindWindowEx().
1605 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1610 WCHAR *buffer = NULL;
1612 if (!parent) parent = GetDesktopWindow();
1615 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1616 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1619 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1623 child = WIN_GetFullHandle( child );
1624 while (list[i] && list[i] != child) i++;
1625 if (!list[i]) goto done;
1626 i++; /* start from next window */
1633 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1640 if (list) HeapFree( GetProcessHeap(), 0, list );
1641 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1647 /***********************************************************************
1648 * FindWindowA (USER32.@)
1650 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1652 HWND ret = FindWindowExA( 0, 0, className, title );
1653 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1658 /***********************************************************************
1659 * FindWindowExA (USER32.@)
1661 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1662 LPCSTR className, LPCSTR title )
1671 /* If the atom doesn't exist, then no class */
1672 /* with this name exists either. */
1673 if (!(atom = GlobalFindAtomA( className )))
1675 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1679 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1681 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1682 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1683 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1684 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1685 HeapFree( GetProcessHeap(), 0, buffer );
1690 /***********************************************************************
1691 * FindWindowExW (USER32.@)
1693 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1694 LPCWSTR className, LPCWSTR title )
1700 /* If the atom doesn't exist, then no class */
1701 /* with this name exists either. */
1702 if (!(atom = GlobalFindAtomW( className )))
1704 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1708 return WIN_FindWindow( parent, child, atom, title );
1712 /***********************************************************************
1713 * FindWindowW (USER32.@)
1715 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1717 return FindWindowExW( 0, 0, className, title );
1721 /**********************************************************************
1722 * GetDesktopWindow (USER32.@)
1724 HWND WINAPI GetDesktopWindow(void)
1726 if (pWndDesktop) return pWndDesktop->hwndSelf;
1727 ERR( "Wine init error: either you're trying to use an invalid native USER.EXE config, or some graphics/GUI libraries or DLLs didn't initialize properly. Aborting.\n" );
1733 /*******************************************************************
1734 * EnableWindow (USER32.@)
1736 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1743 if (is_broadcast(hwnd))
1745 SetLastError( ERROR_INVALID_PARAMETER );
1749 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1750 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1754 TRACE("( %p, %d )\n", hwnd, enable);
1756 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1757 style = wndPtr->dwStyle;
1758 retvalue = ((style & WS_DISABLED) != 0);
1759 WIN_ReleasePtr( wndPtr );
1761 if (enable && retvalue)
1763 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1764 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1766 else if (!enable && !retvalue)
1768 HWND focus_wnd, capture_wnd;
1770 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1772 WIN_SetStyle( hwnd, style | WS_DISABLED );
1774 focus_wnd = GetFocus();
1775 if (hwnd == focus_wnd || IsChild(hwnd, focus_wnd))
1776 SetFocus( 0 ); /* A disabled window can't have the focus */
1778 capture_wnd = GetCapture();
1779 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1780 ReleaseCapture(); /* A disabled window can't capture the mouse */
1782 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1788 /***********************************************************************
1789 * IsWindowEnabled (USER32.@)
1791 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1793 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1797 /***********************************************************************
1798 * IsWindowUnicode (USER32.@)
1800 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1805 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1806 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1807 WIN_ReleaseWndPtr(wndPtr);
1812 /**********************************************************************
1813 * GetWindowWord (USER32.@)
1815 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1820 WND *wndPtr = WIN_GetPtr( hwnd );
1823 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1826 if (wndPtr == WND_OTHER_PROCESS)
1828 SERVER_START_REQ( set_window_info )
1831 req->flags = 0; /* don't set anything, just retrieve */
1832 req->extra_offset = offset;
1833 req->extra_size = sizeof(retvalue);
1834 if (!wine_server_call_err( req ))
1835 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1840 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1842 WARN("Invalid offset %d\n", offset );
1843 SetLastError( ERROR_INVALID_INDEX );
1845 else memcpy( &retvalue, (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1846 WIN_ReleasePtr( wndPtr );
1852 case GWL_HWNDPARENT:
1853 return GetWindowLongW( hwnd, offset );
1857 LONG ret = GetWindowLongW( hwnd, offset );
1859 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1863 WARN("Invalid offset %d\n", offset );
1869 /**********************************************************************
1870 * SetWindowWord (USER32.@)
1872 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1881 case GWL_HWNDPARENT:
1882 return SetWindowLongW( hwnd, offset, (UINT)newval );
1886 WARN("Invalid offset %d\n", offset );
1887 SetLastError( ERROR_INVALID_INDEX );
1892 wndPtr = WIN_GetPtr( hwnd );
1893 if (wndPtr == WND_OTHER_PROCESS)
1896 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1897 offset, newval, hwnd );
1902 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1906 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1908 WARN("Invalid offset %d\n", offset );
1909 WIN_ReleasePtr(wndPtr);
1910 SetLastError( ERROR_INVALID_INDEX );
1914 SERVER_START_REQ( set_window_info )
1917 req->flags = SET_WIN_EXTRA;
1918 req->extra_offset = offset;
1919 req->extra_size = sizeof(newval);
1920 memcpy( &req->extra_value, &newval, sizeof(newval) );
1921 if (!wine_server_call_err( req ))
1923 void *ptr = (char *)wndPtr->wExtra + offset;
1924 memcpy( &retval, ptr, sizeof(retval) );
1925 memcpy( ptr, &newval, sizeof(newval) );
1929 WIN_ReleasePtr( wndPtr );
1934 /**********************************************************************
1937 * Helper function for GetWindowLong().
1939 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1944 if (offset == GWL_HWNDPARENT)
1946 HWND parent = GetAncestor( hwnd, GA_PARENT );
1947 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1948 return (LONG)parent;
1951 if (!(wndPtr = WIN_GetPtr( hwnd )))
1953 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1957 if (wndPtr == WND_OTHER_PROCESS)
1959 if (offset == GWL_WNDPROC)
1961 SetLastError( ERROR_ACCESS_DENIED );
1964 SERVER_START_REQ( set_window_info )
1967 req->flags = 0; /* don't set anything, just retrieve */
1968 req->extra_offset = (offset >= 0) ? offset : -1;
1969 req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1970 if (!wine_server_call_err( req ))
1974 case GWL_STYLE: retvalue = reply->old_style; break;
1975 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1976 case GWL_ID: retvalue = reply->old_id; break;
1977 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1978 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1980 if (offset >= 0) retvalue = reply->old_extra_value;
1981 else SetLastError( ERROR_INVALID_INDEX );
1990 /* now we have a valid wndPtr */
1994 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1997 * Some programs try to access last element from 16 bit
1998 * code using illegal offset value. Hopefully this is
1999 * what those programs really expect.
2001 if (type == WIN_PROC_16 &&
2002 wndPtr->cbWndExtra >= 4 &&
2003 offset == wndPtr->cbWndExtra - sizeof(WORD))
2005 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2007 ERR( "- replaced invalid offset %d with %d\n",
2010 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
2011 WIN_ReleasePtr( wndPtr );
2014 WARN("Invalid offset %d\n", offset );
2015 WIN_ReleasePtr( wndPtr );
2016 SetLastError( ERROR_INVALID_INDEX );
2019 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2020 /* Special case for dialog window procedure */
2021 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2022 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2023 WIN_ReleasePtr( wndPtr );
2029 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
2030 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2031 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2032 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
2033 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2034 case GWL_HINSTANCE: retvalue = (LONG)wndPtr->hInstance; break;
2036 WARN("Unknown offset %d\n", offset );
2037 SetLastError( ERROR_INVALID_INDEX );
2040 WIN_ReleasePtr(wndPtr);
2045 /**********************************************************************
2048 * Helper function for SetWindowLong().
2050 * 0 is the failure code. However, in the case of failure SetLastError
2051 * must be set to distinguish between a 0 return value and a failure.
2053 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2054 WINDOWPROCTYPE type )
2061 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2063 if (is_broadcast(hwnd))
2065 SetLastError( ERROR_INVALID_PARAMETER );
2068 if (!WIN_IsCurrentProcess( hwnd ))
2070 if (offset == GWL_WNDPROC)
2072 SetLastError( ERROR_ACCESS_DENIED );
2075 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2078 wndPtr = WIN_GetPtr( hwnd );
2079 if (wndPtr->hwndSelf == GetDesktopWindow())
2081 /* can't change anything on the desktop window */
2082 WIN_ReleasePtr( wndPtr );
2083 SetLastError( ERROR_ACCESS_DENIED );
2087 /* first some special cases */
2093 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2094 style.styleNew = newval;
2095 WIN_ReleasePtr( wndPtr );
2096 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2097 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2098 newval = style.styleNew;
2100 case GWL_HWNDPARENT:
2101 if (wndPtr->parent == GetDesktopWindow())
2103 WIN_ReleasePtr( wndPtr );
2104 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2108 WIN_ReleasePtr( wndPtr );
2109 return (LONG)SetParent( hwnd, (HWND)newval );
2112 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2113 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2114 WIN_ReleasePtr( wndPtr );
2121 if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2123 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2124 retval = (LONG)WINPROC_GetProc( *ptr, type );
2125 WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2126 WIN_ReleasePtr( wndPtr );
2131 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2133 WARN("Invalid offset %d\n", offset );
2134 WIN_ReleasePtr( wndPtr );
2135 SetLastError( ERROR_INVALID_INDEX );
2140 LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2141 if (*ptr == newval) /* already set to the same value */
2143 WIN_ReleasePtr( wndPtr );
2150 SERVER_START_REQ( set_window_info )
2153 req->extra_offset = -1;
2157 req->flags = SET_WIN_STYLE;
2158 req->style = newval;
2161 req->flags = SET_WIN_EXSTYLE;
2162 req->ex_style = newval;
2165 req->flags = SET_WIN_ID;
2169 req->flags = SET_WIN_INSTANCE;
2170 req->instance = (void *)newval;
2173 req->flags = SET_WIN_USERDATA;
2174 req->user_data = (void *)newval;
2177 req->flags = SET_WIN_EXTRA;
2178 req->extra_offset = offset;
2179 req->extra_size = sizeof(newval);
2180 memcpy( &req->extra_value, &newval, sizeof(newval) );
2182 if ((ok = !wine_server_call_err( req )))
2187 wndPtr->dwStyle = newval;
2188 retval = reply->old_style;
2191 wndPtr->dwExStyle = newval;
2192 retval = reply->old_ex_style;
2195 wndPtr->wIDmenu = newval;
2196 retval = reply->old_id;
2199 wndPtr->hInstance = (HINSTANCE)newval;
2200 retval = (ULONG_PTR)reply->old_instance;
2203 wndPtr->userdata = newval;
2204 retval = (ULONG_PTR)reply->old_user_data;
2208 void *ptr = (char *)wndPtr->wExtra + offset;
2209 memcpy( &retval, ptr, sizeof(retval) );
2210 memcpy( ptr, &newval, sizeof(newval) );
2217 WIN_ReleasePtr( wndPtr );
2221 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2222 USER_Driver.pSetWindowStyle( hwnd, retval );
2224 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2225 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2231 /**********************************************************************
2232 * GetWindowLong (USER.135)
2234 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2236 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2240 /**********************************************************************
2241 * GetWindowLongA (USER32.@)
2243 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2245 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2249 /**********************************************************************
2250 * GetWindowLongW (USER32.@)
2252 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2254 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2258 /**********************************************************************
2259 * SetWindowLong (USER.136)
2261 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2263 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2267 /**********************************************************************
2268 * SetWindowLongA (USER32.@)
2270 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2272 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2276 /**********************************************************************
2277 * SetWindowLongW (USER32.@) Set window attribute
2279 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2280 * value in a window's extra memory.
2282 * The _hwnd_ parameter specifies the window. is the handle to a
2283 * window that has extra memory. The _newval_ parameter contains the
2284 * new attribute or extra memory value. If positive, the _offset_
2285 * parameter is the byte-addressed location in the window's extra
2286 * memory to set. If negative, _offset_ specifies the window
2287 * attribute to set, and should be one of the following values:
2289 * GWL_EXSTYLE The window's extended window style
2291 * GWL_STYLE The window's window style.
2293 * GWL_WNDPROC Pointer to the window's window procedure.
2295 * GWL_HINSTANCE The window's pplication instance handle.
2297 * GWL_ID The window's identifier.
2299 * GWL_USERDATA The window's user-specified data.
2301 * If the window is a dialog box, the _offset_ parameter can be one of
2302 * the following values:
2304 * DWL_DLGPROC The address of the window's dialog box procedure.
2306 * DWL_MSGRESULT The return value of a message
2307 * that the dialog box procedure processed.
2309 * DWL_USER Application specific information.
2313 * If successful, returns the previous value located at _offset_. Otherwise,
2318 * Extra memory for a window class is specified by a nonzero cbWndExtra
2319 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2320 * time of class creation.
2322 * Using GWL_WNDPROC to set a new window procedure effectively creates
2323 * a window subclass. Use CallWindowProc() in the new windows procedure
2324 * to pass messages to the superclass's window procedure.
2326 * The user data is reserved for use by the application which created
2329 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2330 * instead, call the EnableWindow() function to change the window's
2333 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2334 * SetParent() instead.
2337 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2338 * it sends WM_STYLECHANGING before changing the settings
2339 * and WM_STYLECHANGED afterwards.
2340 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2342 LONG WINAPI SetWindowLongW(
2343 HWND hwnd, /* [in] window to alter */
2344 INT offset, /* [in] offset, in bytes, of location to alter */
2345 LONG newval /* [in] new value of location */
2347 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2351 /*******************************************************************
2352 * GetWindowTextA (USER32.@)
2354 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2358 if (WIN_IsCurrentProcess( hwnd ))
2359 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2361 /* when window belongs to other process, don't send a message */
2362 if (nMaxCount <= 0) return 0;
2363 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2364 get_server_window_text( hwnd, buffer, nMaxCount );
2365 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2366 lpString[nMaxCount-1] = 0;
2367 HeapFree( GetProcessHeap(), 0, buffer );
2368 return strlen(lpString);
2372 /*******************************************************************
2373 * InternalGetWindowText (USER32.@)
2375 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2379 if (nMaxCount <= 0) return 0;
2380 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2381 if (win != WND_OTHER_PROCESS)
2383 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2384 else lpString[0] = 0;
2385 WIN_ReleasePtr( win );
2389 get_server_window_text( hwnd, lpString, nMaxCount );
2391 return strlenW(lpString);
2395 /*******************************************************************
2396 * GetWindowTextW (USER32.@)
2398 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2400 if (WIN_IsCurrentProcess( hwnd ))
2401 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2403 /* when window belongs to other process, don't send a message */
2404 if (nMaxCount <= 0) return 0;
2405 get_server_window_text( hwnd, lpString, nMaxCount );
2406 return strlenW(lpString);
2410 /*******************************************************************
2411 * SetWindowText (USER32.@)
2412 * SetWindowTextA (USER32.@)
2414 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2416 if (is_broadcast(hwnd))
2418 SetLastError( ERROR_INVALID_PARAMETER );
2421 if (!WIN_IsCurrentProcess( hwnd ))
2423 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2424 SetLastError( ERROR_ACCESS_DENIED );
2427 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2431 /*******************************************************************
2432 * SetWindowTextW (USER32.@)
2434 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2436 if (is_broadcast(hwnd))
2438 SetLastError( ERROR_INVALID_PARAMETER );
2441 if (!WIN_IsCurrentProcess( hwnd ))
2443 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2444 SetLastError( ERROR_ACCESS_DENIED );
2447 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2451 /*******************************************************************
2452 * GetWindowTextLengthA (USER32.@)
2454 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2456 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2459 /*******************************************************************
2460 * GetWindowTextLengthW (USER32.@)
2462 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2464 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2468 /*******************************************************************
2469 * IsWindow (USER32.@)
2471 BOOL WINAPI IsWindow( HWND hwnd )
2476 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2478 if (ptr != WND_OTHER_PROCESS)
2480 WIN_ReleasePtr( ptr );
2484 /* check other processes */
2485 SERVER_START_REQ( get_window_info )
2488 ret = !wine_server_call_err( req );
2495 /***********************************************************************
2496 * GetWindowThreadProcessId (USER32.@)
2498 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2503 if (!(ptr = WIN_GetPtr( hwnd )))
2505 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2509 if (ptr != WND_OTHER_PROCESS)
2511 /* got a valid window */
2513 if (process) *process = GetCurrentProcessId();
2514 WIN_ReleasePtr( ptr );
2518 /* check other processes */
2519 SERVER_START_REQ( get_window_info )
2522 if (!wine_server_call_err( req ))
2524 tid = (DWORD)reply->tid;
2525 if (process) *process = (DWORD)reply->pid;
2533 /*****************************************************************
2534 * GetParent (USER32.@)
2536 HWND WINAPI GetParent( HWND hwnd )
2541 if (!(wndPtr = WIN_GetPtr( hwnd )))
2543 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2546 if (wndPtr == WND_OTHER_PROCESS)
2548 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2549 if (style & (WS_POPUP | WS_CHILD))
2551 SERVER_START_REQ( get_window_tree )
2554 if (!wine_server_call_err( req ))
2556 if (style & WS_POPUP) retvalue = reply->owner;
2557 else if (style & WS_CHILD) retvalue = reply->parent;
2565 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2566 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2567 WIN_ReleasePtr( wndPtr );
2573 /*****************************************************************
2574 * GetAncestor (USER32.@)
2576 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2579 HWND *list, ret = 0;
2584 if (!(win = WIN_GetPtr( hwnd )))
2586 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2589 if (win != WND_OTHER_PROCESS)
2592 WIN_ReleasePtr( win );
2594 else /* need to query the server */
2596 SERVER_START_REQ( get_window_tree )
2599 if (!wine_server_call_err( req )) ret = reply->parent;
2606 if (!(list = WIN_ListParents( hwnd ))) return 0;
2608 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2612 while (list[count]) count++;
2613 ret = list[count - 2]; /* get the one before the desktop */
2615 HeapFree( GetProcessHeap(), 0, list );
2619 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2622 HWND parent = GetParent( ret );
2632 /*****************************************************************
2633 * SetParent (USER32.@)
2635 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2638 HWND retvalue, full_handle;
2641 if (is_broadcast(hwnd) || is_broadcast(parent))
2643 SetLastError(ERROR_INVALID_PARAMETER);
2647 if (!parent) parent = GetDesktopWindow();
2648 else parent = WIN_GetFullHandle( parent );
2650 if (!IsWindow( parent ))
2652 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2656 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2657 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2661 if (USER_Driver.pSetParent)
2662 return USER_Driver.pSetParent( hwnd, parent );
2664 /* Windows hides the window first, then shows it again
2665 * including the WM_SHOWWINDOW messages and all */
2666 was_visible = ShowWindow( hwnd, SW_HIDE );
2668 if (!IsWindow( parent )) return 0;
2669 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2671 retvalue = wndPtr->parent; /* old parent */
2672 if (parent != retvalue)
2674 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2676 if (parent != GetDesktopWindow()) /* a child window */
2678 if (!(wndPtr->dwStyle & WS_CHILD))
2680 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2681 if (menu) DestroyMenu( menu );
2685 WIN_ReleasePtr( wndPtr );
2687 /* SetParent additionally needs to make hwnd the topmost window
2688 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2689 WM_WINDOWPOSCHANGED notification messages.
2691 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2692 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2693 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2694 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2699 /*******************************************************************
2700 * IsChild (USER32.@)
2702 BOOL WINAPI IsChild( HWND parent, HWND child )
2704 HWND *list = WIN_ListParents( child );
2708 if (!list) return FALSE;
2709 parent = WIN_GetFullHandle( parent );
2710 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2711 ret = (list[i] != 0);
2712 HeapFree( GetProcessHeap(), 0, list );
2717 /***********************************************************************
2718 * IsWindowVisible (USER32.@)
2720 BOOL WINAPI IsWindowVisible( HWND hwnd )
2726 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2727 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2728 for (i = 0; list[i]; i++)
2729 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2731 HeapFree( GetProcessHeap(), 0, list );
2736 /***********************************************************************
2737 * WIN_IsWindowDrawable
2739 * hwnd is drawable when it is visible, all parents are not
2740 * minimized, and it is itself not minimized unless we are
2741 * trying to draw its default class icon.
2743 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2748 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2750 if (!(style & WS_VISIBLE)) return FALSE;
2751 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2753 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2754 for (i = 0; list[i]; i++)
2755 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2758 HeapFree( GetProcessHeap(), 0, list );
2763 /*******************************************************************
2764 * GetTopWindow (USER32.@)
2766 HWND WINAPI GetTopWindow( HWND hwnd )
2768 if (!hwnd) hwnd = GetDesktopWindow();
2769 return GetWindow( hwnd, GW_CHILD );
2773 /*******************************************************************
2774 * GetWindow (USER32.@)
2776 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2780 if (rel == GW_OWNER) /* this one may be available locally */
2782 WND *wndPtr = WIN_GetPtr( hwnd );
2785 SetLastError( ERROR_INVALID_HANDLE );
2788 if (wndPtr != WND_OTHER_PROCESS)
2790 retval = wndPtr->owner;
2791 WIN_ReleasePtr( wndPtr );
2794 /* else fall through to server call */
2797 SERVER_START_REQ( get_window_tree )
2800 if (!wine_server_call_err( req ))
2805 retval = reply->first_sibling;
2808 retval = reply->last_sibling;
2811 retval = reply->next_sibling;
2814 retval = reply->prev_sibling;
2817 retval = reply->owner;
2820 retval = reply->first_child;
2830 /***********************************************************************
2831 * WIN_InternalShowOwnedPopups
2833 * Internal version of ShowOwnedPopups; Wine functions should use this
2834 * to avoid interfering with application calls to ShowOwnedPopups
2835 * and to make sure the application can't prevent showing/hiding.
2837 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2841 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2845 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2847 if (!win_array) return TRUE;
2850 * Show windows Lowest first, Highest last to preserve Z-Order
2852 while (win_array[count]) count++;
2853 while (--count >= 0)
2855 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2856 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2858 if (pWnd->dwStyle & WS_POPUP)
2862 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2863 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2866 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2868 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2869 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2874 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2875 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2876 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2879 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2881 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2882 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2883 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2887 WIN_ReleaseWndPtr( pWnd );
2889 HeapFree( GetProcessHeap(), 0, win_array );
2894 /*******************************************************************
2895 * ShowOwnedPopups (USER32.@)
2897 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2901 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2903 if (!win_array) return TRUE;
2905 while (win_array[count]) count++;
2906 while (--count >= 0)
2908 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2909 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2911 if (pWnd->dwStyle & WS_POPUP)
2915 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2917 /* In Windows, ShowOwnedPopups(TRUE) generates
2918 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2919 * regardless of the state of the owner
2921 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2922 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2927 if (IsWindowVisible(pWnd->hwndSelf))
2929 /* In Windows, ShowOwnedPopups(FALSE) generates
2930 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2931 * regardless of the state of the owner
2933 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2934 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2938 WIN_ReleaseWndPtr( pWnd );
2940 HeapFree( GetProcessHeap(), 0, win_array );
2945 /*******************************************************************
2946 * GetLastActivePopup (USER32.@)
2948 HWND WINAPI GetLastActivePopup( HWND hwnd )
2952 SERVER_START_REQ( get_window_info )
2955 if (!wine_server_call_err( req )) retval = reply->last_active;
2962 /*******************************************************************
2965 * Build an array of all parents of a given window, starting with
2966 * the immediate parent. The array must be freed with HeapFree.
2967 * Returns NULL if window is a top-level window.
2969 HWND *WIN_ListParents( HWND hwnd )
2972 HWND current, *list;
2973 int pos = 0, size = 16, count = 0;
2975 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2980 if (!(win = WIN_GetPtr( current ))) goto empty;
2981 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2982 list[pos] = win->parent;
2983 WIN_ReleasePtr( win );
2984 if (!(current = list[pos]))
2986 if (!pos) goto empty;
2989 if (++pos == size - 1)
2991 /* need to grow the list */
2992 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2993 if (!new_list) goto empty;
2999 /* at least one parent belongs to another process, have to query the server */
3004 SERVER_START_REQ( get_window_parents )
3007 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
3008 if (!wine_server_call( req )) count = reply->count;
3011 if (!count) goto empty;
3017 HeapFree( GetProcessHeap(), 0, list );
3019 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3023 HeapFree( GetProcessHeap(), 0, list );
3028 /*******************************************************************
3031 * Build an array of the children of a given window. The array must be
3032 * freed with HeapFree. Returns NULL when no windows are found.
3034 HWND *WIN_ListChildren( HWND hwnd )
3036 return list_window_children( hwnd, 0, 0 );
3040 /*******************************************************************
3041 * EnumWindows (USER32.@)
3043 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3049 /* We have to build a list of all windows first, to avoid */
3050 /* unpleasant side-effects, for instance if the callback */
3051 /* function changes the Z-order of the windows. */
3053 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3055 /* Now call the callback function for every window */
3057 iWndsLocks = WIN_SuspendWndsLock();
3058 for (i = 0; list[i]; i++)
3060 /* Make sure that the window still exists */
3061 if (!IsWindow( list[i] )) continue;
3062 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3064 WIN_RestoreWndsLock(iWndsLocks);
3065 HeapFree( GetProcessHeap(), 0, list );
3070 /**********************************************************************
3071 * EnumThreadWindows (USER32.@)
3073 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3078 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3080 /* Now call the callback function for every window */
3082 iWndsLocks = WIN_SuspendWndsLock();
3083 for (i = 0; list[i]; i++)
3084 if (!func( list[i], lParam )) break;
3085 WIN_RestoreWndsLock(iWndsLocks);
3086 HeapFree( GetProcessHeap(), 0, list );
3091 /**********************************************************************
3092 * WIN_EnumChildWindows
3094 * Helper function for EnumChildWindows().
3096 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3101 for ( ; *list; list++)
3103 /* Make sure that the window still exists */
3104 if (!IsWindow( *list )) continue;
3105 /* skip owned windows */
3106 if (GetWindow( *list, GW_OWNER )) continue;
3107 /* Build children list first */
3108 childList = WIN_ListChildren( *list );
3110 ret = func( *list, lParam );
3114 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3115 HeapFree( GetProcessHeap(), 0, childList );
3117 if (!ret) return FALSE;
3123 /**********************************************************************
3124 * EnumChildWindows (USER32.@)
3126 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3131 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3132 iWndsLocks = WIN_SuspendWndsLock();
3133 WIN_EnumChildWindows( list, func, lParam );
3134 WIN_RestoreWndsLock(iWndsLocks);
3135 HeapFree( GetProcessHeap(), 0, list );
3140 /*******************************************************************
3141 * AnyPopup (USER.52)
3143 BOOL16 WINAPI AnyPopup16(void)
3149 /*******************************************************************
3150 * AnyPopup (USER32.@)
3152 BOOL WINAPI AnyPopup(void)
3156 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3158 if (!list) return FALSE;
3159 for (i = 0; list[i]; i++)
3161 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3163 retvalue = (list[i] != 0);
3164 HeapFree( GetProcessHeap(), 0, list );
3169 /*******************************************************************
3170 * FlashWindow (USER32.@)
3172 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3174 WND *wndPtr = WIN_FindWndPtr(hWnd);
3176 TRACE("%p\n", hWnd);
3178 if (!wndPtr) return FALSE;
3179 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3181 if (wndPtr->dwStyle & WS_MINIMIZE)
3183 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3185 HDC hDC = GetDC(hWnd);
3187 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3188 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3190 ReleaseDC( hWnd, hDC );
3191 wndPtr->flags |= WIN_NCACTIVATED;
3195 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3196 wndPtr->flags &= ~WIN_NCACTIVATED;
3198 WIN_ReleaseWndPtr(wndPtr);
3204 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3205 else wparam = (hWnd == GetForegroundWindow());
3207 WIN_ReleaseWndPtr(wndPtr);
3208 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3213 /*******************************************************************
3214 * FlashWindowEx (USER32.@)
3216 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3218 FIXME("%p\n", pfwi);
3222 /*******************************************************************
3223 * GetWindowContextHelpId (USER32.@)
3225 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3228 WND *wnd = WIN_FindWndPtr( hwnd );
3230 retval = wnd->helpContext;
3231 WIN_ReleaseWndPtr(wnd);
3236 /*******************************************************************
3237 * SetWindowContextHelpId (USER32.@)
3239 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3241 WND *wnd = WIN_FindWndPtr( hwnd );
3242 if (!wnd) return FALSE;
3243 wnd->helpContext = id;
3244 WIN_ReleaseWndPtr(wnd);
3249 /*******************************************************************
3250 * DragDetect (USER32.@)
3252 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3257 rect.left = pt.x - wDragWidth;
3258 rect.right = pt.x + wDragWidth;
3260 rect.top = pt.y - wDragHeight;
3261 rect.bottom = pt.y + wDragHeight;
3267 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3269 if( msg.message == WM_LBUTTONUP )
3274 if( msg.message == WM_MOUSEMOVE )
3277 tmp.x = LOWORD(msg.lParam);
3278 tmp.y = HIWORD(msg.lParam);
3279 if( !PtInRect( &rect, tmp ))
3291 /******************************************************************************
3292 * GetWindowModuleFileNameA (USER32.@)
3294 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3296 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3297 hwnd, lpszFileName, cchFileNameMax);
3301 /******************************************************************************
3302 * GetWindowModuleFileNameW (USER32.@)
3304 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3306 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3307 hwnd, lpszFileName, cchFileNameMax);
3311 /******************************************************************************
3312 * GetWindowInfo (USER32.@)
3315 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3316 * this may be because this structure changed over time. If this is the
3317 * the case, then please: FIXME.
3318 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3320 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3322 if (!pwi) return FALSE;
3323 if (pwi->cbSize != sizeof(WINDOWINFO))
3325 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3328 if (!IsWindow(hwnd)) return FALSE;
3330 GetWindowRect(hwnd, &pwi->rcWindow);
3331 GetClientRect(hwnd, &pwi->rcClient);
3332 /* translate to screen coordinates */
3333 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3335 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3336 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3337 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3339 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3340 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3342 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3343 pwi->wCreatorVersion = 0x0400;