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) >> 1)
49 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
51 /**********************************************************************/
54 static WND *pWndDesktop = NULL;
56 static WORD wDragWidth = 4;
57 static WORD wDragHeight= 3;
59 static void *user_handles[NB_USER_HANDLES];
61 /***********************************************************************
62 * create_window_handle
64 * Create a window handle with the server.
66 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
67 HINSTANCE instance, WINDOWPROCTYPE type )
71 struct tagCLASS *class = NULL;
72 user_handle_t handle = 0;
75 /* if 16-bit instance, map to module handle */
76 if (instance && !HIWORD(instance))
77 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
79 SERVER_START_REQ( create_window )
84 req->instance = instance;
85 if (!wine_server_call_err( req ))
87 handle = reply->handle;
88 extra_bytes = reply->extra;
89 class = reply->class_ptr;
96 WARN( "error %ld creating window\n", GetLastError() );
100 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
102 SERVER_START_REQ( destroy_window )
104 req->handle = handle;
105 wine_server_call( req );
108 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
114 index = USER_HANDLE_TO_INDEX(handle);
115 assert( index < NB_USER_HANDLES );
116 user_handles[index] = win;
117 win->hwndSelf = handle;
118 win->dwMagic = WND_MAGIC;
120 win->cbWndExtra = extra_bytes;
121 memset( win->wExtra, 0, extra_bytes );
122 CLASS_AddWindow( class, win, type );
127 /***********************************************************************
130 * Free a window handle.
132 static WND *free_window_handle( HWND hwnd )
135 WORD index = USER_HANDLE_TO_INDEX(hwnd);
137 if (index >= NB_USER_HANDLES) return NULL;
139 if ((ptr = user_handles[index]))
141 SERVER_START_REQ( destroy_window )
144 if (!wine_server_call_err( req ))
145 user_handles[index] = NULL;
152 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
157 /*******************************************************************
158 * list_window_children
160 * Build an array of the children of a given window. The array must be
161 * freed with HeapFree. Returns NULL when no windows are found.
163 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
172 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
174 SERVER_START_REQ( get_window_children )
179 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
180 if (!wine_server_call( req )) count = reply->count;
183 if (count && count < size)
188 HeapFree( GetProcessHeap(), 0, list );
190 size = count + 1; /* restart with a large enough buffer */
196 /*******************************************************************
199 static void send_parent_notify( HWND hwnd, UINT msg )
201 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
202 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
203 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
204 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
208 /*******************************************************************
209 * get_server_window_text
211 * Retrieve the window text from the server.
213 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
217 SERVER_START_REQ( get_window_text )
220 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
221 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
224 text[len / sizeof(WCHAR)] = 0;
228 /***********************************************************************
231 * Return a pointer to the WND structure if local to the process,
232 * or WND_OTHER_PROCESS if handle may be valid in other process.
233 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
235 WND *WIN_GetPtr( HWND hwnd )
238 WORD index = USER_HANDLE_TO_INDEX(hwnd);
240 if (index >= NB_USER_HANDLES) return NULL;
243 if ((ptr = user_handles[index]))
245 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
249 else ptr = WND_OTHER_PROCESS;
255 /***********************************************************************
256 * WIN_IsCurrentProcess
258 * Check whether a given window belongs to the current process (and return the full handle).
260 HWND WIN_IsCurrentProcess( HWND hwnd )
265 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
267 WIN_ReleasePtr( ptr );
272 /***********************************************************************
273 * WIN_IsCurrentThread
275 * Check whether a given window belongs to the current thread (and return the full handle).
277 HWND WIN_IsCurrentThread( HWND hwnd )
282 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
284 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
285 WIN_ReleasePtr( ptr );
291 /***********************************************************************
294 * Convert a 16-bit window handle to a full 32-bit handle.
296 HWND WIN_Handle32( HWND16 hwnd16 )
299 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
301 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
302 /* do sign extension for -2 and -3 */
303 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
305 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
307 if (ptr != WND_OTHER_PROCESS)
309 hwnd = ptr->hwndSelf;
310 WIN_ReleasePtr( ptr );
312 else /* may belong to another process */
314 SERVER_START_REQ( get_window_info )
317 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
325 /***********************************************************************
328 * Return a pointer to the WND structure corresponding to a HWND.
330 WND * WIN_FindWndPtr( HWND hwnd )
334 if (!hwnd) return NULL;
336 if ((ptr = WIN_GetPtr( hwnd )))
338 if (ptr != WND_OTHER_PROCESS)
340 /* increment destruction monitoring */
344 if (IsWindow( hwnd )) /* check other processes */
346 ERR( "window %p belongs to other process\n", hwnd );
347 /* DbgBreakPoint(); */
350 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
355 /***********************************************************************
358 * Release the pointer to the WND structure.
360 void WIN_ReleaseWndPtr(WND *wndPtr)
364 /* Decrement destruction monitoring value */
366 /* Check if it's time to release the memory */
367 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
370 free_window_handle( wndPtr->hwndSelf );
372 else if(wndPtr->irefCount < 0)
374 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
375 ERR("forgot a Lock on %p somewhere\n",wndPtr);
377 /* unlock all WND structures for thread safeness */
382 /***********************************************************************
385 * Remove a window from the siblings linked list.
387 void WIN_UnlinkWindow( HWND hwnd )
389 WIN_LinkWindow( hwnd, 0, 0 );
393 /***********************************************************************
396 * Insert a window into the siblings linked list.
397 * The window is inserted after the specified window, which can also
398 * be specified as HWND_TOP or HWND_BOTTOM.
399 * If parent is 0, window is unlinked from the tree.
401 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
403 WND *wndPtr = WIN_GetPtr( hwnd );
406 if (wndPtr == WND_OTHER_PROCESS)
408 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
412 SERVER_START_REQ( link_window )
415 req->parent = parent;
416 req->previous = hwndInsertAfter;
417 if (!wine_server_call( req ))
419 if (reply->full_parent) wndPtr->parent = reply->full_parent;
424 WIN_ReleasePtr( wndPtr );
428 /***********************************************************************
431 * Change the owner of a window.
433 HWND WIN_SetOwner( HWND hwnd, HWND owner )
435 WND *win = WIN_GetPtr( hwnd );
439 if (win == WND_OTHER_PROCESS)
441 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
444 SERVER_START_REQ( set_window_owner )
448 if (!wine_server_call( req ))
450 win->owner = reply->full_owner;
451 ret = reply->prev_owner;
455 WIN_ReleasePtr( win );
460 /***********************************************************************
463 * Change the style of a window.
465 LONG WIN_SetStyle( HWND hwnd, LONG style )
469 WND *win = WIN_GetPtr( hwnd );
472 if (win == WND_OTHER_PROCESS)
475 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
478 if (style == win->dwStyle)
480 WIN_ReleasePtr( win );
483 SERVER_START_REQ( set_window_info )
486 req->flags = SET_WIN_STYLE;
488 req->extra_offset = -1;
489 if ((ok = !wine_server_call( req )))
491 ret = reply->old_style;
492 win->dwStyle = style;
496 WIN_ReleasePtr( win );
497 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
502 /***********************************************************************
505 * Change the extended style of a window.
507 LONG WIN_SetExStyle( HWND hwnd, LONG style )
510 WND *win = WIN_GetPtr( hwnd );
513 if (win == WND_OTHER_PROCESS)
516 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
519 if (style == win->dwExStyle)
521 WIN_ReleasePtr( win );
524 SERVER_START_REQ( set_window_info )
527 req->flags = SET_WIN_EXSTYLE;
528 req->ex_style = style;
529 req->extra_offset = -1;
530 if (!wine_server_call( req ))
532 ret = reply->old_ex_style;
533 win->dwExStyle = style;
537 WIN_ReleasePtr( win );
542 /***********************************************************************
545 * Set the window and client rectangles.
547 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
549 WND *win = WIN_GetPtr( hwnd );
553 if (win == WND_OTHER_PROCESS)
555 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
558 SERVER_START_REQ( set_window_rectangles )
561 req->window.left = rectWindow->left;
562 req->window.top = rectWindow->top;
563 req->window.right = rectWindow->right;
564 req->window.bottom = rectWindow->bottom;
565 req->client.left = rectClient->left;
566 req->client.top = rectClient->top;
567 req->client.right = rectClient->right;
568 req->client.bottom = rectClient->bottom;
569 ret = !wine_server_call( req );
574 win->rectWindow = *rectWindow;
575 win->rectClient = *rectClient;
577 TRACE( "win %p window (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", hwnd,
578 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
579 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
581 WIN_ReleasePtr( win );
585 /***********************************************************************
588 * Get the window and client rectangles.
590 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
592 WND *win = WIN_GetPtr( hwnd );
595 if (!win) return FALSE;
596 if (win == WND_OTHER_PROCESS)
598 SERVER_START_REQ( get_window_rectangles )
601 if ((ret = !wine_server_call( req )))
605 rectWindow->left = reply->window.left;
606 rectWindow->top = reply->window.top;
607 rectWindow->right = reply->window.right;
608 rectWindow->bottom = reply->window.bottom;
612 rectClient->left = reply->client.left;
613 rectClient->top = reply->client.top;
614 rectClient->right = reply->client.right;
615 rectClient->bottom = reply->client.bottom;
623 if (rectWindow) *rectWindow = win->rectWindow;
624 if (rectClient) *rectClient = win->rectClient;
625 WIN_ReleasePtr( win );
631 /***********************************************************************
634 * Destroy storage associated to a window. "Internals" p.358
636 LRESULT WIN_DestroyWindow( HWND hwnd )
641 TRACE("%p\n", hwnd );
643 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
645 ERR( "window doesn't belong to current thread\n" );
649 /* free child windows */
650 if ((list = WIN_ListChildren( hwnd )))
653 for (i = 0; list[i]; i++)
655 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
656 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
658 HeapFree( GetProcessHeap(), 0, list );
662 * Clear the update region to make sure no WM_PAINT messages will be
663 * generated for this window while processing the WM_NCDESTROY.
665 RedrawWindow( hwnd, NULL, 0,
666 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
669 * Send the WM_NCDESTROY to the window being destroyed.
671 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
673 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
675 WINPOS_CheckInternalPos( hwnd );
676 if( hwnd == GetCapture()) ReleaseCapture();
678 /* free resources associated with the window */
680 TIMER_RemoveWindowTimers( hwnd );
682 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
684 if (!(wndPtr->dwStyle & WS_CHILD))
686 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
687 if (menu) DestroyMenu( menu );
689 if (wndPtr->hSysMenu)
691 DestroyMenu( wndPtr->hSysMenu );
692 wndPtr->hSysMenu = 0;
694 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
695 USER_Driver.pDestroyWindow( hwnd );
696 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
697 wndPtr->class = NULL;
698 wndPtr->dwMagic = 0; /* Mark it as invalid */
699 WIN_ReleaseWndPtr( wndPtr );
703 /***********************************************************************
704 * WIN_DestroyThreadWindows
706 * Destroy all children of 'wnd' owned by the current thread.
707 * Return TRUE if something was done.
709 void WIN_DestroyThreadWindows( HWND hwnd )
714 if (!(list = WIN_ListChildren( hwnd ))) return;
715 for (i = 0; list[i]; i++)
717 if (WIN_IsCurrentThread( list[i] ))
718 DestroyWindow( list[i] );
720 WIN_DestroyThreadWindows( list[i] );
722 HeapFree( GetProcessHeap(), 0, list );
725 /***********************************************************************
726 * WIN_CreateDesktopWindow
728 * Create the desktop window.
730 BOOL WIN_CreateDesktopWindow(void)
736 TRACE("Creating desktop window\n");
738 if (!WINPOS_CreateInternalPosAtom()) return FALSE;
740 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
741 if (!pWndDesktop) return FALSE;
742 hwndDesktop = pWndDesktop->hwndSelf;
744 pWndDesktop->tid = 0; /* nobody owns the desktop */
745 pWndDesktop->parent = 0;
746 pWndDesktop->owner = 0;
747 pWndDesktop->text = NULL;
748 pWndDesktop->hrgnUpdate = 0;
749 pWndDesktop->pVScroll = NULL;
750 pWndDesktop->pHScroll = NULL;
751 pWndDesktop->helpContext = 0;
752 pWndDesktop->flags = 0;
753 pWndDesktop->hSysMenu = 0;
755 cs.lpCreateParams = NULL;
761 cs.cx = GetSystemMetrics( SM_CXSCREEN );
762 cs.cy = GetSystemMetrics( SM_CYSCREEN );
763 cs.style = pWndDesktop->dwStyle;
764 cs.dwExStyle = pWndDesktop->dwExStyle;
766 cs.lpszClass = DESKTOP_CLASS_ATOM;
768 SetRect( &rect, 0, 0, cs.cx, cs.cy );
769 WIN_SetRectangles( hwndDesktop, &rect, &rect );
771 SERVER_START_REQ( set_window_info )
773 req->handle = hwndDesktop;
774 req->flags = 0; /* don't set anything, just retrieve */
775 req->extra_offset = -1;
776 wine_server_call( req );
777 pWndDesktop->dwStyle = reply->old_style;
778 pWndDesktop->dwExStyle = reply->old_ex_style;
779 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
780 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
781 pWndDesktop->wIDmenu = reply->old_id;
785 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
787 WIN_ReleaseWndPtr( pWndDesktop );
791 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
792 WIN_ReleaseWndPtr( pWndDesktop );
797 /***********************************************************************
800 * Fix the coordinates - Helper for WIN_CreateWindowEx.
801 * returns default show mode in sw.
802 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
804 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
806 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
807 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
809 if (cs->style & (WS_CHILD | WS_POPUP))
811 if (cs->dwExStyle & WS_EX_MDICHILD)
815 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
817 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
822 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
824 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
829 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
831 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
835 else /* overlapped window */
839 GetStartupInfoA( &info );
841 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
843 /* Never believe Microsoft's documentation... CreateWindowEx doc says
844 * that if an overlapped window is created with WS_VISIBLE style bit
845 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
846 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
849 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
850 * 2) it does not ignore the y parameter as the docs claim; instead, it
851 * uses it as second parameter to ShowWindow() unless y is either
852 * CW_USEDEFAULT or CW_USEDEFAULT16.
854 * The fact that we didn't do 2) caused bogus windows pop up when wine
855 * was running apps that were using this obscure feature. Example -
856 * calc.exe that comes with Win98 (only Win98, it's different from
857 * the one that comes with Win95 and NT)
859 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
860 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
861 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
864 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
866 if (info.dwFlags & STARTF_USESIZE)
868 cs->cx = info.dwXSize;
869 cs->cy = info.dwYSize;
871 else /* if no other hint from the app, pick 3/4 of the screen real estate */
874 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
875 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
876 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
883 /* neither x nor cx are default. Check the y values .
884 * In the trace we see Outlook and Outlook Express using
885 * cy set to CW_USEDEFAULT when opening the address book.
887 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
889 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
890 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
891 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
896 /***********************************************************************
899 static void dump_window_styles( DWORD style, DWORD exstyle )
902 if(style & WS_POPUP) TRACE(" WS_POPUP");
903 if(style & WS_CHILD) TRACE(" WS_CHILD");
904 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
905 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
906 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
907 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
908 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
909 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
910 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
913 if(style & WS_BORDER) TRACE(" WS_BORDER");
914 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
916 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
917 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
918 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
919 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
920 if(style & WS_GROUP) TRACE(" WS_GROUP");
921 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
922 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
923 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
925 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
926 #define DUMPED_STYLES \
946 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
951 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
952 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
953 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
954 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
955 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
956 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
957 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
958 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
959 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
960 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
961 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
962 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
963 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
964 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
965 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
966 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
967 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
968 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
970 #define DUMPED_EX_STYLES \
971 (WS_EX_DLGMODALFRAME | \
973 WS_EX_NOPARENTNOTIFY | \
975 WS_EX_ACCEPTFILES | \
976 WS_EX_TRANSPARENT | \
981 WS_EX_CONTEXTHELP | \
984 WS_EX_LEFTSCROLLBAR | \
985 WS_EX_CONTROLPARENT | \
990 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
992 #undef DUMPED_EX_STYLES
996 /***********************************************************************
999 * Implementation of CreateWindowEx().
1001 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
1002 WINDOWPROCTYPE type )
1006 HWND hwnd, parent, owner, top_child = 0;
1007 BOOL unicode = (type == WIN_PROC_32W);
1009 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1010 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1011 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1012 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1013 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1015 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1017 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1018 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1020 /* Fix the styles for MDI children */
1021 if (cs->dwExStyle & WS_EX_MDICHILD)
1023 MDICREATESTRUCTA mdi_cs;
1026 wndPtr = WIN_GetPtr(cs->hwndParent);
1027 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
1029 flags = wndPtr->flags;
1030 WIN_ReleasePtr(wndPtr);
1033 if (!(flags & WIN_ISMDICLIENT))
1035 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1039 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1040 * MDICREATESTRUCT members have the originally passed values.
1042 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1043 * have the same layout.
1045 mdi_cs.szClass = cs->lpszClass;
1046 mdi_cs.szTitle = cs->lpszName;
1047 mdi_cs.hOwner = cs->hInstance;
1052 mdi_cs.style = cs->style;
1053 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1055 cs->lpCreateParams = (LPVOID)&mdi_cs;
1057 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1059 if (cs->style & WS_POPUP)
1061 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1064 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1068 cs->style &= ~WS_POPUP;
1069 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1070 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1073 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1076 /* Find the parent window */
1078 parent = GetDesktopWindow();
1081 if (cs->hwndParent == HWND_MESSAGE)
1083 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1084 * message window (style: WS_POPUP|WS_DISABLED)
1086 FIXME("Parent is HWND_MESSAGE\n");
1088 else if (cs->hwndParent)
1090 /* Make sure parent is valid */
1091 if (!IsWindow( cs->hwndParent ))
1093 WARN("Bad parent %p\n", cs->hwndParent );
1096 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1097 parent = WIN_GetFullHandle(cs->hwndParent);
1099 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1101 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1103 WARN("No parent for child window\n" );
1104 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1107 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1109 /* Correct the window styles.
1111 * It affects both the style loaded into the WIN structure and
1112 * passed in the CREATESTRUCT to the WM_[NC]CREATE.
1114 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1115 * why does the user get to set it?
1118 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1119 * tested for WS_POPUP
1121 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1122 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1123 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1124 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1126 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1128 if (!(cs->style & WS_CHILD))
1130 cs->style |= WS_CLIPSIBLINGS;
1131 if (!(cs->style & WS_POPUP))
1132 cs->style |= WS_CAPTION;
1135 /* Create the window structure */
1137 if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1139 TRACE("out of memory\n" );
1142 hwnd = wndPtr->hwndSelf;
1144 /* Fill the window structure */
1146 wndPtr->tid = GetCurrentThreadId();
1147 wndPtr->owner = owner;
1148 wndPtr->parent = parent;
1149 wndPtr->hInstance = cs->hInstance;
1150 wndPtr->text = NULL;
1151 wndPtr->hrgnUpdate = 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)
1233 ShowWindow( hwnd, sw );
1235 /* Call WH_SHELL hook */
1237 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1238 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1240 TRACE("created window %p\n", hwnd);
1245 /***********************************************************************
1246 * CreateWindow (USER.41)
1248 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1249 DWORD style, INT16 x, INT16 y, INT16 width,
1250 INT16 height, HWND16 parent, HMENU16 menu,
1251 HINSTANCE16 instance, LPVOID data )
1253 return CreateWindowEx16( 0, className, windowName, style,
1254 x, y, width, height, parent, menu, instance, data );
1258 /***********************************************************************
1259 * CreateWindowEx (USER.452)
1261 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1262 LPCSTR windowName, DWORD style, INT16 x,
1263 INT16 y, INT16 width, INT16 height,
1264 HWND16 parent, HMENU16 menu,
1265 HINSTANCE16 instance, LPVOID data )
1271 /* Find the class atom */
1273 if (HIWORD(className))
1275 if (!(classAtom = GlobalFindAtomA( className )))
1277 ERR( "bad class name %s\n", debugstr_a(className) );
1283 classAtom = LOWORD(className);
1284 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1286 ERR( "bad atom %x\n", classAtom);
1292 /* Fix the coordinates */
1294 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1295 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1296 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1297 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1299 /* Create the window */
1301 cs.lpCreateParams = data;
1302 cs.hInstance = HINSTANCE_32(instance);
1303 cs.hMenu = HMENU_32(menu);
1304 cs.hwndParent = WIN_Handle32( parent );
1306 cs.lpszName = windowName;
1307 cs.lpszClass = className;
1308 cs.dwExStyle = exStyle;
1310 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1314 /***********************************************************************
1315 * CreateWindowExA (USER32.@)
1317 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1318 LPCSTR windowName, DWORD style, INT x,
1319 INT y, INT width, INT height,
1320 HWND parent, HMENU menu,
1321 HINSTANCE instance, LPVOID data )
1327 /* Find the class atom */
1329 if (HIWORD(className))
1331 if (!(classAtom = GlobalFindAtomA( className )))
1333 ERR( "bad class name %s\n", debugstr_a(className) );
1339 classAtom = LOWORD(className);
1340 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1342 ERR( "bad atom %x\n", classAtom);
1348 /* Create the window */
1350 cs.lpCreateParams = data;
1351 cs.hInstance = instance;
1353 cs.hwndParent = parent;
1359 cs.lpszName = windowName;
1360 cs.lpszClass = className;
1361 cs.dwExStyle = exStyle;
1363 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1367 /***********************************************************************
1368 * CreateWindowExW (USER32.@)
1370 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1371 LPCWSTR windowName, DWORD style, INT x,
1372 INT y, INT width, INT height,
1373 HWND parent, HMENU menu,
1374 HINSTANCE instance, LPVOID data )
1380 /* Find the class atom */
1382 if (HIWORD(className))
1384 if (!(classAtom = GlobalFindAtomW( className )))
1386 ERR( "bad class name %s\n", debugstr_w(className) );
1392 classAtom = LOWORD(className);
1393 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1395 ERR( "bad atom %x\n", classAtom);
1401 /* Create the window */
1403 cs.lpCreateParams = data;
1404 cs.hInstance = instance;
1406 cs.hwndParent = parent;
1412 cs.lpszName = windowName;
1413 cs.lpszClass = className;
1414 cs.dwExStyle = exStyle;
1416 /* Note: we rely on the fact that CREATESTRUCTA and */
1417 /* CREATESTRUCTW have the same layout. */
1418 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1422 /***********************************************************************
1423 * WIN_SendDestroyMsg
1425 static void WIN_SendDestroyMsg( HWND hwnd )
1429 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1431 if (hwnd == info.hwndCaret) DestroyCaret();
1432 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1434 if (USER_Driver.pResetSelectionOwner)
1435 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1438 * Send the WM_DESTROY to the window.
1440 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1443 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1444 * make sure that the window still exists when we come back.
1451 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1453 /* start from the end (FIXME: is this needed?) */
1454 for (i = 0; pWndArray[i]; i++) ;
1458 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1460 HeapFree( GetProcessHeap(), 0, pWndArray );
1463 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1467 /***********************************************************************
1468 * DestroyWindow (USER32.@)
1470 BOOL WINAPI DestroyWindow( HWND hwnd )
1474 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1476 SetLastError( ERROR_ACCESS_DENIED );
1480 TRACE("(%p)\n", hwnd);
1482 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1483 SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
1487 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1489 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1493 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1494 send_parent_notify( hwnd, WM_DESTROY );
1496 else if (!GetWindow( hwnd, GW_OWNER ))
1498 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1499 /* FIXME: clean up palette - see "Internals" p.352 */
1502 if (!IsWindow(hwnd)) return TRUE;
1504 if (USER_Driver.pResetSelectionOwner)
1505 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1507 /* Hide the window */
1509 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1511 ShowWindow( hwnd, SW_HIDE );
1513 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1514 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1516 if (!IsWindow(hwnd)) return TRUE;
1518 /* Recursively destroy owned windows */
1525 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1528 for (i = 0; list[i]; i++)
1530 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1531 if (WIN_IsCurrentThread( list[i] ))
1533 DestroyWindow( list[i] );
1537 WIN_SetOwner( list[i], 0 );
1539 HeapFree( GetProcessHeap(), 0, list );
1541 if (!got_one) break;
1545 /* Send destroy messages */
1547 WIN_SendDestroyMsg( hwnd );
1548 if (!IsWindow( hwnd )) return TRUE;
1550 if (GetClipboardOwner() == hwnd)
1551 CLIPBOARD_ReleaseOwner();
1553 /* Unlink now so we won't bother with the children later on */
1555 WIN_UnlinkWindow( hwnd );
1557 /* Destroy the window storage */
1559 WIN_DestroyWindow( hwnd );
1564 /***********************************************************************
1565 * CloseWindow (USER32.@)
1567 BOOL WINAPI CloseWindow( HWND hwnd )
1569 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1570 ShowWindow( hwnd, SW_MINIMIZE );
1575 /***********************************************************************
1576 * OpenIcon (USER32.@)
1578 BOOL WINAPI OpenIcon( HWND hwnd )
1580 if (!IsIconic( hwnd )) return FALSE;
1581 ShowWindow( hwnd, SW_SHOWNORMAL );
1586 /***********************************************************************
1589 * Implementation of FindWindow() and FindWindowEx().
1591 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1596 WCHAR *buffer = NULL;
1598 if (!parent) parent = GetDesktopWindow();
1601 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1602 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1605 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1609 child = WIN_GetFullHandle( child );
1610 while (list[i] && list[i] != child) i++;
1611 if (!list[i]) goto done;
1612 i++; /* start from next window */
1619 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1626 if (list) HeapFree( GetProcessHeap(), 0, list );
1627 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1633 /***********************************************************************
1634 * FindWindowA (USER32.@)
1636 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1638 HWND ret = FindWindowExA( 0, 0, className, title );
1639 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1644 /***********************************************************************
1645 * FindWindowExA (USER32.@)
1647 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1648 LPCSTR className, LPCSTR title )
1657 /* If the atom doesn't exist, then no class */
1658 /* with this name exists either. */
1659 if (!(atom = GlobalFindAtomA( className )))
1661 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1665 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1667 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1668 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1669 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1670 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1671 HeapFree( GetProcessHeap(), 0, buffer );
1676 /***********************************************************************
1677 * FindWindowExW (USER32.@)
1679 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1680 LPCWSTR className, LPCWSTR title )
1686 /* If the atom doesn't exist, then no class */
1687 /* with this name exists either. */
1688 if (!(atom = GlobalFindAtomW( className )))
1690 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1694 return WIN_FindWindow( parent, child, atom, title );
1698 /***********************************************************************
1699 * FindWindowW (USER32.@)
1701 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1703 return FindWindowExW( 0, 0, className, title );
1707 /**********************************************************************
1708 * GetDesktopWindow (USER32.@)
1710 HWND WINAPI GetDesktopWindow(void)
1712 if (pWndDesktop) return pWndDesktop->hwndSelf;
1713 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" );
1719 /*******************************************************************
1720 * EnableWindow (USER32.@)
1722 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1729 if (is_broadcast(hwnd))
1731 SetLastError( ERROR_INVALID_PARAMETER );
1735 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1736 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1740 TRACE("( %p, %d )\n", hwnd, enable);
1742 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1743 style = wndPtr->dwStyle;
1744 retvalue = ((style & WS_DISABLED) != 0);
1745 WIN_ReleasePtr( wndPtr );
1747 if (enable && retvalue)
1749 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1750 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1752 else if (!enable && !retvalue)
1756 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1758 WIN_SetStyle( hwnd, style | WS_DISABLED );
1760 if (hwnd == GetFocus())
1761 SetFocus( 0 ); /* A disabled window can't have the focus */
1763 capture_wnd = GetCapture();
1764 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1765 ReleaseCapture(); /* A disabled window can't capture the mouse */
1767 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1773 /***********************************************************************
1774 * IsWindowEnabled (USER32.@)
1776 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1778 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1782 /***********************************************************************
1783 * IsWindowUnicode (USER32.@)
1785 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1790 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1791 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1792 WIN_ReleaseWndPtr(wndPtr);
1797 /**********************************************************************
1798 * GetWindowWord (USER32.@)
1800 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1805 WND *wndPtr = WIN_GetPtr( hwnd );
1808 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1811 if (wndPtr == WND_OTHER_PROCESS)
1813 SERVER_START_REQ( set_window_info )
1816 req->flags = 0; /* don't set anything, just retrieve */
1817 req->extra_offset = offset;
1818 req->extra_size = sizeof(retvalue);
1819 if (!wine_server_call_err( req ))
1820 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1825 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1827 WARN("Invalid offset %d\n", offset );
1828 SetLastError( ERROR_INVALID_INDEX );
1830 else memcpy( &retvalue, (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1831 WIN_ReleasePtr( wndPtr );
1837 case GWL_HWNDPARENT:
1838 return GetWindowLongW( hwnd, offset );
1842 LONG ret = GetWindowLongW( hwnd, offset );
1844 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1848 WARN("Invalid offset %d\n", offset );
1854 /**********************************************************************
1855 * SetWindowWord (USER32.@)
1857 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1866 case GWL_HWNDPARENT:
1867 return SetWindowLongW( hwnd, offset, (UINT)newval );
1871 WARN("Invalid offset %d\n", offset );
1872 SetLastError( ERROR_INVALID_INDEX );
1877 wndPtr = WIN_GetPtr( hwnd );
1878 if (wndPtr == WND_OTHER_PROCESS)
1881 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1882 offset, newval, hwnd );
1887 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1891 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1893 WARN("Invalid offset %d\n", offset );
1894 WIN_ReleasePtr(wndPtr);
1895 SetLastError( ERROR_INVALID_INDEX );
1899 SERVER_START_REQ( set_window_info )
1902 req->flags = SET_WIN_EXTRA;
1903 req->extra_offset = offset;
1904 req->extra_size = sizeof(newval);
1905 memcpy( &req->extra_value, &newval, sizeof(newval) );
1906 if (!wine_server_call_err( req ))
1908 void *ptr = (char *)wndPtr->wExtra + offset;
1909 memcpy( &retval, ptr, sizeof(retval) );
1910 memcpy( ptr, &newval, sizeof(newval) );
1914 WIN_ReleasePtr( wndPtr );
1919 /**********************************************************************
1922 * Helper function for GetWindowLong().
1924 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1929 if (offset == GWL_HWNDPARENT)
1931 HWND parent = GetAncestor( hwnd, GA_PARENT );
1932 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1933 return (LONG)parent;
1936 if (!(wndPtr = WIN_GetPtr( hwnd )))
1938 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1942 if (wndPtr == WND_OTHER_PROCESS)
1944 if (offset == GWL_WNDPROC)
1946 SetLastError( ERROR_ACCESS_DENIED );
1949 SERVER_START_REQ( set_window_info )
1952 req->flags = 0; /* don't set anything, just retrieve */
1953 req->extra_offset = (offset >= 0) ? offset : -1;
1954 req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1955 if (!wine_server_call_err( req ))
1959 case GWL_STYLE: retvalue = reply->old_style; break;
1960 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1961 case GWL_ID: retvalue = reply->old_id; break;
1962 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1963 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1965 if (offset >= 0) retvalue = reply->old_extra_value;
1966 else SetLastError( ERROR_INVALID_INDEX );
1975 /* now we have a valid wndPtr */
1979 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1982 * Some programs try to access last element from 16 bit
1983 * code using illegal offset value. Hopefully this is
1984 * what those programs really expect.
1986 if (type == WIN_PROC_16 &&
1987 wndPtr->cbWndExtra >= 4 &&
1988 offset == wndPtr->cbWndExtra - sizeof(WORD))
1990 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1992 ERR( "- replaced invalid offset %d with %d\n",
1995 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1996 WIN_ReleasePtr( wndPtr );
1999 WARN("Invalid offset %d\n", offset );
2000 WIN_ReleasePtr( wndPtr );
2001 SetLastError( ERROR_INVALID_INDEX );
2004 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2005 /* Special case for dialog window procedure */
2006 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2007 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2008 WIN_ReleasePtr( wndPtr );
2014 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
2015 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2016 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2017 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
2018 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2019 case GWL_HINSTANCE: retvalue = (LONG)wndPtr->hInstance; break;
2021 WARN("Unknown offset %d\n", offset );
2022 SetLastError( ERROR_INVALID_INDEX );
2025 WIN_ReleasePtr(wndPtr);
2030 /**********************************************************************
2033 * Helper function for SetWindowLong().
2035 * 0 is the failure code. However, in the case of failure SetLastError
2036 * must be set to distinguish between a 0 return value and a failure.
2038 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2039 WINDOWPROCTYPE type )
2046 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2048 if (is_broadcast(hwnd))
2050 SetLastError( ERROR_INVALID_PARAMETER );
2053 if (!WIN_IsCurrentProcess( hwnd ))
2055 if (offset == GWL_WNDPROC)
2057 SetLastError( ERROR_ACCESS_DENIED );
2060 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2063 wndPtr = WIN_GetPtr( hwnd );
2064 if (wndPtr->hwndSelf == GetDesktopWindow())
2066 /* can't change anything on the desktop window */
2067 WIN_ReleasePtr( wndPtr );
2068 SetLastError( ERROR_ACCESS_DENIED );
2072 /* first some special cases */
2078 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2079 style.styleNew = newval;
2080 WIN_ReleasePtr( wndPtr );
2081 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2082 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2083 newval = style.styleNew;
2085 case GWL_HWNDPARENT:
2086 if (wndPtr->parent == GetDesktopWindow())
2088 WIN_ReleasePtr( wndPtr );
2089 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2093 WIN_ReleasePtr( wndPtr );
2094 return (LONG)SetParent( hwnd, (HWND)newval );
2097 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2098 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2099 WIN_ReleasePtr( wndPtr );
2106 if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2108 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2109 retval = (LONG)WINPROC_GetProc( *ptr, type );
2110 WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2111 WIN_ReleasePtr( wndPtr );
2116 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2118 WARN("Invalid offset %d\n", offset );
2119 WIN_ReleasePtr( wndPtr );
2120 SetLastError( ERROR_INVALID_INDEX );
2125 LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2126 if (*ptr == newval) /* already set to the same value */
2128 WIN_ReleasePtr( wndPtr );
2135 SERVER_START_REQ( set_window_info )
2138 req->extra_offset = -1;
2142 req->flags = SET_WIN_STYLE;
2143 req->style = newval;
2146 req->flags = SET_WIN_EXSTYLE;
2147 req->ex_style = newval;
2150 req->flags = SET_WIN_ID;
2154 req->flags = SET_WIN_INSTANCE;
2155 req->instance = (void *)newval;
2158 req->flags = SET_WIN_USERDATA;
2159 req->user_data = (void *)newval;
2162 req->flags = SET_WIN_EXTRA;
2163 req->extra_offset = offset;
2164 req->extra_size = sizeof(newval);
2165 memcpy( &req->extra_value, &newval, sizeof(newval) );
2167 if ((ok = !wine_server_call_err( req )))
2172 wndPtr->dwStyle = newval;
2173 retval = reply->old_style;
2176 wndPtr->dwExStyle = newval;
2177 retval = reply->old_ex_style;
2180 wndPtr->wIDmenu = newval;
2181 retval = reply->old_id;
2184 wndPtr->hInstance = (HINSTANCE)newval;
2185 retval = (ULONG_PTR)reply->old_instance;
2188 wndPtr->userdata = newval;
2189 retval = (ULONG_PTR)reply->old_user_data;
2193 void *ptr = (char *)wndPtr->wExtra + offset;
2194 memcpy( &retval, ptr, sizeof(retval) );
2195 memcpy( ptr, &newval, sizeof(newval) );
2202 WIN_ReleasePtr( wndPtr );
2206 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2207 USER_Driver.pSetWindowStyle( hwnd, retval );
2209 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2210 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2216 /**********************************************************************
2217 * GetWindowLong (USER.135)
2219 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2221 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2225 /**********************************************************************
2226 * GetWindowLongA (USER32.@)
2228 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2230 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2234 /**********************************************************************
2235 * GetWindowLongW (USER32.@)
2237 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2239 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2243 /**********************************************************************
2244 * SetWindowLong (USER.136)
2246 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2248 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2252 /**********************************************************************
2253 * SetWindowLongA (USER32.@)
2255 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2257 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2261 /**********************************************************************
2262 * SetWindowLongW (USER32.@) Set window attribute
2264 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2265 * value in a window's extra memory.
2267 * The _hwnd_ parameter specifies the window. is the handle to a
2268 * window that has extra memory. The _newval_ parameter contains the
2269 * new attribute or extra memory value. If positive, the _offset_
2270 * parameter is the byte-addressed location in the window's extra
2271 * memory to set. If negative, _offset_ specifies the window
2272 * attribute to set, and should be one of the following values:
2274 * GWL_EXSTYLE The window's extended window style
2276 * GWL_STYLE The window's window style.
2278 * GWL_WNDPROC Pointer to the window's window procedure.
2280 * GWL_HINSTANCE The window's pplication instance handle.
2282 * GWL_ID The window's identifier.
2284 * GWL_USERDATA The window's user-specified data.
2286 * If the window is a dialog box, the _offset_ parameter can be one of
2287 * the following values:
2289 * DWL_DLGPROC The address of the window's dialog box procedure.
2291 * DWL_MSGRESULT The return value of a message
2292 * that the dialog box procedure processed.
2294 * DWL_USER Application specific information.
2298 * If successful, returns the previous value located at _offset_. Otherwise,
2303 * Extra memory for a window class is specified by a nonzero cbWndExtra
2304 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2305 * time of class creation.
2307 * Using GWL_WNDPROC to set a new window procedure effectively creates
2308 * a window subclass. Use CallWindowProc() in the new windows procedure
2309 * to pass messages to the superclass's window procedure.
2311 * The user data is reserved for use by the application which created
2314 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2315 * instead, call the EnableWindow() function to change the window's
2318 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2319 * SetParent() instead.
2322 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2323 * it sends WM_STYLECHANGING before changing the settings
2324 * and WM_STYLECHANGED afterwards.
2325 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2327 LONG WINAPI SetWindowLongW(
2328 HWND hwnd, /* [in] window to alter */
2329 INT offset, /* [in] offset, in bytes, of location to alter */
2330 LONG newval /* [in] new value of location */
2332 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2336 /*******************************************************************
2337 * GetWindowTextA (USER32.@)
2339 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2343 if (WIN_IsCurrentProcess( hwnd ))
2344 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2346 /* when window belongs to other process, don't send a message */
2347 if (nMaxCount <= 0) return 0;
2348 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2349 get_server_window_text( hwnd, buffer, nMaxCount );
2350 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2351 lpString[nMaxCount-1] = 0;
2352 HeapFree( GetProcessHeap(), 0, buffer );
2353 return strlen(lpString);
2357 /*******************************************************************
2358 * InternalGetWindowText (USER32.@)
2360 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2364 if (nMaxCount <= 0) return 0;
2365 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2366 if (win != WND_OTHER_PROCESS)
2368 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2369 else lpString[0] = 0;
2370 WIN_ReleasePtr( win );
2374 get_server_window_text( hwnd, lpString, nMaxCount );
2376 return strlenW(lpString);
2380 /*******************************************************************
2381 * GetWindowTextW (USER32.@)
2383 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2385 if (WIN_IsCurrentProcess( hwnd ))
2386 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2388 /* when window belongs to other process, don't send a message */
2389 if (nMaxCount <= 0) return 0;
2390 get_server_window_text( hwnd, lpString, nMaxCount );
2391 return strlenW(lpString);
2395 /*******************************************************************
2396 * SetWindowText (USER32.@)
2397 * SetWindowTextA (USER32.@)
2399 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2401 if (is_broadcast(hwnd))
2403 SetLastError( ERROR_INVALID_PARAMETER );
2406 if (!WIN_IsCurrentProcess( hwnd ))
2408 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2409 SetLastError( ERROR_ACCESS_DENIED );
2412 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2416 /*******************************************************************
2417 * SetWindowTextW (USER32.@)
2419 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2421 if (is_broadcast(hwnd))
2423 SetLastError( ERROR_INVALID_PARAMETER );
2426 if (!WIN_IsCurrentProcess( hwnd ))
2428 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2429 SetLastError( ERROR_ACCESS_DENIED );
2432 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2436 /*******************************************************************
2437 * GetWindowTextLengthA (USER32.@)
2439 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2441 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2444 /*******************************************************************
2445 * GetWindowTextLengthW (USER32.@)
2447 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2449 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2453 /*******************************************************************
2454 * IsWindow (USER32.@)
2456 BOOL WINAPI IsWindow( HWND hwnd )
2461 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2463 if (ptr != WND_OTHER_PROCESS)
2465 WIN_ReleasePtr( ptr );
2469 /* check other processes */
2470 SERVER_START_REQ( get_window_info )
2473 ret = !wine_server_call_err( req );
2480 /***********************************************************************
2481 * GetWindowThreadProcessId (USER32.@)
2483 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2488 if (!(ptr = WIN_GetPtr( hwnd )))
2490 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2494 if (ptr != WND_OTHER_PROCESS)
2496 /* got a valid window */
2498 if (process) *process = GetCurrentProcessId();
2499 WIN_ReleasePtr( ptr );
2503 /* check other processes */
2504 SERVER_START_REQ( get_window_info )
2507 if (!wine_server_call_err( req ))
2509 tid = (DWORD)reply->tid;
2510 if (process) *process = (DWORD)reply->pid;
2518 /*****************************************************************
2519 * GetParent (USER32.@)
2521 HWND WINAPI GetParent( HWND hwnd )
2526 if (!(wndPtr = WIN_GetPtr( hwnd )))
2528 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2531 if (wndPtr == WND_OTHER_PROCESS)
2533 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2534 if (style & (WS_POPUP | WS_CHILD))
2536 SERVER_START_REQ( get_window_tree )
2539 if (!wine_server_call_err( req ))
2541 if (style & WS_POPUP) retvalue = reply->owner;
2542 else if (style & WS_CHILD) retvalue = reply->parent;
2550 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2551 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2552 WIN_ReleasePtr( wndPtr );
2558 /*****************************************************************
2559 * GetAncestor (USER32.@)
2561 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2564 HWND *list, ret = 0;
2569 if (!(win = WIN_GetPtr( hwnd )))
2571 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2574 if (win != WND_OTHER_PROCESS)
2577 WIN_ReleasePtr( win );
2579 else /* need to query the server */
2581 SERVER_START_REQ( get_window_tree )
2584 if (!wine_server_call_err( req )) ret = reply->parent;
2591 if (!(list = WIN_ListParents( hwnd ))) return 0;
2593 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2597 while (list[count]) count++;
2598 ret = list[count - 2]; /* get the one before the desktop */
2600 HeapFree( GetProcessHeap(), 0, list );
2604 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2607 HWND parent = GetParent( ret );
2617 /*****************************************************************
2618 * SetParent (USER32.@)
2620 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2623 HWND retvalue, full_handle;
2626 if (is_broadcast(hwnd) || is_broadcast(parent))
2628 SetLastError(ERROR_INVALID_PARAMETER);
2632 if (!parent) parent = GetDesktopWindow();
2633 else parent = WIN_GetFullHandle( parent );
2635 if (!IsWindow( parent ))
2637 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2641 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2642 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2646 if (USER_Driver.pSetParent)
2647 return USER_Driver.pSetParent( hwnd, parent );
2649 /* Windows hides the window first, then shows it again
2650 * including the WM_SHOWWINDOW messages and all */
2651 was_visible = ShowWindow( hwnd, SW_HIDE );
2653 if (!IsWindow( parent )) return 0;
2654 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2656 retvalue = wndPtr->parent; /* old parent */
2657 if (parent != retvalue)
2659 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2661 if (parent != GetDesktopWindow()) /* a child window */
2663 if (!(wndPtr->dwStyle & WS_CHILD))
2665 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2666 if (menu) DestroyMenu( menu );
2670 WIN_ReleasePtr( wndPtr );
2672 /* SetParent additionally needs to make hwnd the topmost window
2673 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2674 WM_WINDOWPOSCHANGED notification messages.
2676 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2677 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2678 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2679 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2684 /*******************************************************************
2685 * IsChild (USER32.@)
2687 BOOL WINAPI IsChild( HWND parent, HWND child )
2689 HWND *list = WIN_ListParents( child );
2693 if (!list) return FALSE;
2694 parent = WIN_GetFullHandle( parent );
2695 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2696 ret = (list[i] != 0);
2697 HeapFree( GetProcessHeap(), 0, list );
2702 /***********************************************************************
2703 * IsWindowVisible (USER32.@)
2705 BOOL WINAPI IsWindowVisible( HWND hwnd )
2711 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2712 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2713 for (i = 0; list[i]; i++)
2714 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2716 HeapFree( GetProcessHeap(), 0, list );
2721 /***********************************************************************
2722 * WIN_IsWindowDrawable
2724 * hwnd is drawable when it is visible, all parents are not
2725 * minimized, and it is itself not minimized unless we are
2726 * trying to draw its default class icon.
2728 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2733 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2735 if (!(style & WS_VISIBLE)) return FALSE;
2736 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2738 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2739 for (i = 0; list[i]; i++)
2740 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2743 HeapFree( GetProcessHeap(), 0, list );
2748 /*******************************************************************
2749 * GetTopWindow (USER32.@)
2751 HWND WINAPI GetTopWindow( HWND hwnd )
2753 if (!hwnd) hwnd = GetDesktopWindow();
2754 return GetWindow( hwnd, GW_CHILD );
2758 /*******************************************************************
2759 * GetWindow (USER32.@)
2761 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2765 if (rel == GW_OWNER) /* this one may be available locally */
2767 WND *wndPtr = WIN_GetPtr( hwnd );
2770 SetLastError( ERROR_INVALID_HANDLE );
2773 if (wndPtr != WND_OTHER_PROCESS)
2775 retval = wndPtr->owner;
2776 WIN_ReleasePtr( wndPtr );
2779 /* else fall through to server call */
2782 SERVER_START_REQ( get_window_tree )
2785 if (!wine_server_call_err( req ))
2790 retval = reply->first_sibling;
2793 retval = reply->last_sibling;
2796 retval = reply->next_sibling;
2799 retval = reply->prev_sibling;
2802 retval = reply->owner;
2805 retval = reply->first_child;
2815 /***********************************************************************
2816 * WIN_InternalShowOwnedPopups
2818 * Internal version of ShowOwnedPopups; Wine functions should use this
2819 * to avoid interfering with application calls to ShowOwnedPopups
2820 * and to make sure the application can't prevent showing/hiding.
2822 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2826 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2830 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2832 if (!win_array) return TRUE;
2835 * Show windows Lowest first, Highest last to preserve Z-Order
2837 while (win_array[count]) count++;
2838 while (--count >= 0)
2840 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2841 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2843 if (pWnd->dwStyle & WS_POPUP)
2847 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2848 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2851 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2853 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2854 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2859 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2860 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2861 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2864 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2866 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2867 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2868 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2872 WIN_ReleaseWndPtr( pWnd );
2874 HeapFree( GetProcessHeap(), 0, win_array );
2879 /*******************************************************************
2880 * ShowOwnedPopups (USER32.@)
2882 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2886 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2888 if (!win_array) return TRUE;
2890 while (win_array[count]) count++;
2891 while (--count >= 0)
2893 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2894 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2896 if (pWnd->dwStyle & WS_POPUP)
2900 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2902 /* In Windows, ShowOwnedPopups(TRUE) generates
2903 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2904 * regardless of the state of the owner
2906 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2907 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2912 if (IsWindowVisible(pWnd->hwndSelf))
2914 /* In Windows, ShowOwnedPopups(FALSE) generates
2915 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2916 * regardless of the state of the owner
2918 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2919 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2923 WIN_ReleaseWndPtr( pWnd );
2925 HeapFree( GetProcessHeap(), 0, win_array );
2930 /*******************************************************************
2931 * GetLastActivePopup (USER32.@)
2933 HWND WINAPI GetLastActivePopup( HWND hwnd )
2937 SERVER_START_REQ( get_window_info )
2940 if (!wine_server_call_err( req )) retval = reply->last_active;
2947 /*******************************************************************
2950 * Build an array of all parents of a given window, starting with
2951 * the immediate parent. The array must be freed with HeapFree.
2952 * Returns NULL if window is a top-level window.
2954 HWND *WIN_ListParents( HWND hwnd )
2957 HWND current, *list;
2958 int pos = 0, size = 16, count = 0;
2960 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2965 if (!(win = WIN_GetPtr( current ))) goto empty;
2966 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2967 list[pos] = win->parent;
2968 WIN_ReleasePtr( win );
2969 if (!(current = list[pos]))
2971 if (!pos) goto empty;
2974 if (++pos == size - 1)
2976 /* need to grow the list */
2977 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2978 if (!new_list) goto empty;
2984 /* at least one parent belongs to another process, have to query the server */
2989 SERVER_START_REQ( get_window_parents )
2992 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2993 if (!wine_server_call( req )) count = reply->count;
2996 if (!count) goto empty;
3002 HeapFree( GetProcessHeap(), 0, list );
3004 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3008 HeapFree( GetProcessHeap(), 0, list );
3013 /*******************************************************************
3016 * Build an array of the children of a given window. The array must be
3017 * freed with HeapFree. Returns NULL when no windows are found.
3019 HWND *WIN_ListChildren( HWND hwnd )
3021 return list_window_children( hwnd, 0, 0 );
3025 /*******************************************************************
3026 * EnumWindows (USER32.@)
3028 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3034 /* We have to build a list of all windows first, to avoid */
3035 /* unpleasant side-effects, for instance if the callback */
3036 /* function changes the Z-order of the windows. */
3038 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3040 /* Now call the callback function for every window */
3042 iWndsLocks = WIN_SuspendWndsLock();
3043 for (i = 0; list[i]; i++)
3045 /* Make sure that the window still exists */
3046 if (!IsWindow( list[i] )) continue;
3047 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3049 WIN_RestoreWndsLock(iWndsLocks);
3050 HeapFree( GetProcessHeap(), 0, list );
3055 /**********************************************************************
3056 * EnumThreadWindows (USER32.@)
3058 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3063 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3065 /* Now call the callback function for every window */
3067 iWndsLocks = WIN_SuspendWndsLock();
3068 for (i = 0; list[i]; i++)
3069 if (!func( list[i], lParam )) break;
3070 WIN_RestoreWndsLock(iWndsLocks);
3071 HeapFree( GetProcessHeap(), 0, list );
3076 /**********************************************************************
3077 * WIN_EnumChildWindows
3079 * Helper function for EnumChildWindows().
3081 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3086 for ( ; *list; list++)
3088 /* Make sure that the window still exists */
3089 if (!IsWindow( *list )) continue;
3090 /* skip owned windows */
3091 if (GetWindow( *list, GW_OWNER )) continue;
3092 /* Build children list first */
3093 childList = WIN_ListChildren( *list );
3095 ret = func( *list, lParam );
3099 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3100 HeapFree( GetProcessHeap(), 0, childList );
3102 if (!ret) return FALSE;
3108 /**********************************************************************
3109 * EnumChildWindows (USER32.@)
3111 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3116 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3117 iWndsLocks = WIN_SuspendWndsLock();
3118 WIN_EnumChildWindows( list, func, lParam );
3119 WIN_RestoreWndsLock(iWndsLocks);
3120 HeapFree( GetProcessHeap(), 0, list );
3125 /*******************************************************************
3126 * AnyPopup (USER.52)
3128 BOOL16 WINAPI AnyPopup16(void)
3134 /*******************************************************************
3135 * AnyPopup (USER32.@)
3137 BOOL WINAPI AnyPopup(void)
3141 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3143 if (!list) return FALSE;
3144 for (i = 0; list[i]; i++)
3146 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3148 retvalue = (list[i] != 0);
3149 HeapFree( GetProcessHeap(), 0, list );
3154 /*******************************************************************
3155 * FlashWindow (USER32.@)
3157 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3159 WND *wndPtr = WIN_FindWndPtr(hWnd);
3161 TRACE("%p\n", hWnd);
3163 if (!wndPtr) return FALSE;
3164 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3166 if (wndPtr->dwStyle & WS_MINIMIZE)
3168 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3170 HDC hDC = GetDC(hWnd);
3172 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3173 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3175 ReleaseDC( hWnd, hDC );
3176 wndPtr->flags |= WIN_NCACTIVATED;
3180 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3181 wndPtr->flags &= ~WIN_NCACTIVATED;
3183 WIN_ReleaseWndPtr(wndPtr);
3189 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3190 else wparam = (hWnd == GetForegroundWindow());
3192 WIN_ReleaseWndPtr(wndPtr);
3193 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3198 /*******************************************************************
3199 * FlashWindowEx (USER32.@)
3201 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3203 FIXME("%p\n", pfwi);
3207 /*******************************************************************
3208 * GetWindowContextHelpId (USER32.@)
3210 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3213 WND *wnd = WIN_FindWndPtr( hwnd );
3215 retval = wnd->helpContext;
3216 WIN_ReleaseWndPtr(wnd);
3221 /*******************************************************************
3222 * SetWindowContextHelpId (USER32.@)
3224 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3226 WND *wnd = WIN_FindWndPtr( hwnd );
3227 if (!wnd) return FALSE;
3228 wnd->helpContext = id;
3229 WIN_ReleaseWndPtr(wnd);
3234 /*******************************************************************
3235 * DragDetect (USER32.@)
3237 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3242 rect.left = pt.x - wDragWidth;
3243 rect.right = pt.x + wDragWidth;
3245 rect.top = pt.y - wDragHeight;
3246 rect.bottom = pt.y + wDragHeight;
3252 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3254 if( msg.message == WM_LBUTTONUP )
3259 if( msg.message == WM_MOUSEMOVE )
3262 tmp.x = LOWORD(msg.lParam);
3263 tmp.y = HIWORD(msg.lParam);
3264 if( !PtInRect( &rect, tmp ))
3276 /******************************************************************************
3277 * GetWindowModuleFileNameA (USER32.@)
3279 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3281 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3282 hwnd, lpszFileName, cchFileNameMax);
3286 /******************************************************************************
3287 * GetWindowModuleFileNameW (USER32.@)
3289 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3291 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3292 hwnd, lpszFileName, cchFileNameMax);
3296 /******************************************************************************
3297 * GetWindowInfo (USER32.@)
3299 * Note: tests show that Windows doesn't check cbSize of the structure.
3301 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3303 if (!pwi) return FALSE;
3304 if (!IsWindow(hwnd)) return FALSE;
3306 GetWindowRect(hwnd, &pwi->rcWindow);
3307 GetClientRect(hwnd, &pwi->rcClient);
3308 /* translate to screen coordinates */
3309 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3311 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3312 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3313 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3315 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3316 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3318 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3319 pwi->wCreatorVersion = 0x0400;