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
25 #include "wine/winbase16.h"
26 #include "wine/winuser16.h"
27 #include "wine/server.h"
28 #include "wine/unicode.h"
33 #include "cursoricon.h"
40 #include "stackframe.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(win);
44 WINE_DECLARE_DEBUG_CHANNEL(msg);
46 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
48 /**********************************************************************/
51 static WND *pWndDesktop = NULL;
53 static WORD wDragWidth = 4;
54 static WORD wDragHeight= 3;
56 static void *user_handles[NB_USER_HANDLES];
59 extern SYSLEVEL USER_SysLevel; /* FIXME */
61 /***********************************************************************
64 * Suspend the lock on WND structures.
65 * Returns the number of locks suspended
67 int WIN_SuspendWndsLock( void )
69 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
70 int count = isuspendedLocks;
73 _LeaveSysLevel( &USER_SysLevel );
75 return isuspendedLocks;
78 /***********************************************************************
81 * Restore the suspended locks on WND structures
83 void WIN_RestoreWndsLock( int ipreviousLocks )
85 while ( ipreviousLocks-- > 0 )
86 _EnterSysLevel( &USER_SysLevel );
89 /***********************************************************************
90 * create_window_handle
92 * Create a window handle with the server.
94 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
97 user_handle_t handle = 0;
99 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
101 if (!win) return NULL;
105 SERVER_START_REQ( create_window )
107 req->parent = parent;
110 if ((res = !wine_server_call_err( req ))) handle = reply->handle;
117 HeapFree( GetProcessHeap(), 0, win );
120 index = LOWORD(handle) - FIRST_USER_HANDLE;
121 assert( index < NB_USER_HANDLES );
122 user_handles[index] = win;
123 win->hwndSelf = handle;
124 win->dwMagic = WND_MAGIC;
130 /***********************************************************************
133 * Free a window handle.
135 static WND *free_window_handle( HWND hwnd )
138 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
140 if (index >= NB_USER_HANDLES) return NULL;
142 if ((ptr = user_handles[index]))
144 SERVER_START_REQ( destroy_window )
147 if (!wine_server_call_err( req ))
148 user_handles[index] = NULL;
155 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
160 /*******************************************************************
161 * list_window_children
163 * Build an array of the children of a given window. The array must be
164 * freed with HeapFree. Returns NULL when no windows are found.
166 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
175 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
177 SERVER_START_REQ( get_window_children )
181 req->tid = (void *)tid;
182 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
183 if (!wine_server_call( req )) count = reply->count;
186 if (count && count < size)
191 HeapFree( GetProcessHeap(), 0, list );
193 size = count + 1; /* restart with a large enough buffer */
199 /*******************************************************************
202 static void send_parent_notify( HWND hwnd, UINT msg )
204 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
205 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
206 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
207 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
211 /*******************************************************************
212 * get_server_window_text
214 * Retrieve the window text from the server.
216 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
220 SERVER_START_REQ( get_window_text )
223 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
224 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
227 text[len / sizeof(WCHAR)] = 0;
231 /***********************************************************************
234 * Return a pointer to the WND structure if local to the process,
235 * or WND_OTHER_PROCESS is handle may be valid in other process.
236 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
238 WND *WIN_GetPtr( HWND hwnd )
241 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
243 if (index >= NB_USER_HANDLES) return NULL;
246 if ((ptr = user_handles[index]))
248 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
252 else ptr = WND_OTHER_PROCESS;
258 /***********************************************************************
259 * WIN_IsCurrentProcess
261 * Check whether a given window belongs to the current process (and return the full handle).
263 HWND WIN_IsCurrentProcess( HWND hwnd )
268 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
270 WIN_ReleasePtr( ptr );
275 /***********************************************************************
276 * WIN_IsCurrentThread
278 * Check whether a given window belongs to the current thread (and return the full handle).
280 HWND WIN_IsCurrentThread( HWND hwnd )
285 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
287 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
288 WIN_ReleasePtr( ptr );
294 /***********************************************************************
297 * Convert a 16-bit window handle to a full 32-bit handle.
299 HWND WIN_Handle32( HWND16 hwnd16 )
302 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
304 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
305 /* do sign extension for -2 and -3 */
306 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
308 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
310 if (ptr != WND_OTHER_PROCESS)
312 hwnd = ptr->hwndSelf;
313 WIN_ReleasePtr( ptr );
315 else /* may belong to another process */
317 SERVER_START_REQ( get_window_info )
320 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
328 /***********************************************************************
331 * Return a pointer to the WND structure corresponding to a HWND.
333 WND * WIN_FindWndPtr( HWND hwnd )
337 if (!hwnd) return NULL;
339 if ((ptr = WIN_GetPtr( hwnd )))
341 if (ptr != WND_OTHER_PROCESS)
343 /* increment destruction monitoring */
347 if (IsWindow( hwnd )) /* check other processes */
349 ERR( "window %04x belongs to other process\n", hwnd );
350 /* DbgBreakPoint(); */
353 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
358 /***********************************************************************
361 * Release the pointer to the WND structure.
363 void WIN_ReleaseWndPtr(WND *wndPtr)
367 /* Decrement destruction monitoring value */
369 /* Check if it's time to release the memory */
370 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
373 free_window_handle( wndPtr->hwndSelf );
375 else if(wndPtr->irefCount < 0)
377 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
378 ERR("forgot a Lock on %p somewhere\n",wndPtr);
380 /* unlock all WND structures for thread safeness */
385 /***********************************************************************
388 * Remove a window from the siblings linked list.
390 void WIN_UnlinkWindow( HWND hwnd )
392 WIN_LinkWindow( hwnd, 0, 0 );
396 /***********************************************************************
399 * Insert a window into the siblings linked list.
400 * The window is inserted after the specified window, which can also
401 * be specified as HWND_TOP or HWND_BOTTOM.
402 * If parent is 0, window is unlinked from the tree.
404 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
406 WND *wndPtr = WIN_GetPtr( hwnd );
409 if (wndPtr == WND_OTHER_PROCESS)
411 if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
415 SERVER_START_REQ( link_window )
418 req->parent = parent;
419 req->previous = hwndInsertAfter;
420 if (!wine_server_call( req ))
422 if (reply->full_parent && reply->full_parent != wndPtr->parent)
424 wndPtr->owner = 0; /* reset owner when changing parent */
425 wndPtr->parent = reply->full_parent;
431 WIN_ReleasePtr( wndPtr );
435 /***********************************************************************
438 * Change the owner of a window.
440 void WIN_SetOwner( HWND hwnd, HWND owner )
442 WND *win = WIN_GetPtr( hwnd );
445 if (win == WND_OTHER_PROCESS)
447 if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
450 SERVER_START_REQ( set_window_owner )
454 if (!wine_server_call( req )) win->owner = reply->full_owner;
457 WIN_ReleasePtr( win );
461 /***********************************************************************
464 * Change the style of a window.
466 LONG WIN_SetStyle( HWND hwnd, LONG style )
470 WND *win = WIN_GetPtr( hwnd );
473 if (win == WND_OTHER_PROCESS)
476 ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
479 if (style == win->dwStyle)
481 WIN_ReleasePtr( win );
484 SERVER_START_REQ( set_window_info )
487 req->flags = SET_WIN_STYLE;
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 %x\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 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 %x\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 %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\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("%04x\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;
682 wndPtr->hmemTaskQ = 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 USER_Driver.pDestroyWindow( hwnd );
695 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
696 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
697 CLASS_RemoveWindow( wndPtr->class );
698 wndPtr->class = NULL;
699 wndPtr->dwMagic = 0; /* Mark it as invalid */
700 WIN_ReleaseWndPtr( wndPtr );
704 /***********************************************************************
705 * WIN_DestroyThreadWindows
707 * Destroy all children of 'wnd' owned by the current thread.
708 * Return TRUE if something was done.
710 void WIN_DestroyThreadWindows( HWND hwnd )
715 if (!(list = WIN_ListChildren( hwnd ))) return;
716 for (i = 0; list[i]; i++)
718 if (WIN_IsCurrentThread( list[i] ))
719 DestroyWindow( list[i] );
721 WIN_DestroyThreadWindows( list[i] );
723 HeapFree( GetProcessHeap(), 0, list );
726 /***********************************************************************
727 * WIN_CreateDesktopWindow
729 * Create the desktop window.
731 BOOL WIN_CreateDesktopWindow(void)
733 struct tagCLASS *class;
742 TRACE("Creating desktop window\n");
744 if (!WINPOS_CreateInternalPosAtom() ||
745 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
746 &wndExtra, &winproc, &clsStyle, &dce )))
749 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
750 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
751 if (!pWndDesktop) return FALSE;
752 hwndDesktop = pWndDesktop->hwndSelf;
754 pWndDesktop->tid = 0; /* nobody owns the desktop */
755 pWndDesktop->parent = 0;
756 pWndDesktop->owner = 0;
757 pWndDesktop->class = class;
758 pWndDesktop->hInstance = 0;
759 pWndDesktop->text = NULL;
760 pWndDesktop->hmemTaskQ = 0;
761 pWndDesktop->hrgnUpdate = 0;
762 pWndDesktop->hwndLastActive = hwndDesktop;
763 pWndDesktop->dwStyle = 0;
764 pWndDesktop->dwExStyle = 0;
765 pWndDesktop->clsStyle = clsStyle;
766 pWndDesktop->dce = NULL;
767 pWndDesktop->pVScroll = NULL;
768 pWndDesktop->pHScroll = NULL;
769 pWndDesktop->wIDmenu = 0;
770 pWndDesktop->helpContext = 0;
771 pWndDesktop->flags = 0;
772 pWndDesktop->hSysMenu = 0;
773 pWndDesktop->userdata = 0;
774 pWndDesktop->winproc = winproc;
775 pWndDesktop->cbWndExtra = wndExtra;
777 cs.lpCreateParams = NULL;
783 cs.cx = GetSystemMetrics( SM_CXSCREEN );
784 cs.cy = GetSystemMetrics( SM_CYSCREEN );
785 cs.style = pWndDesktop->dwStyle;
786 cs.dwExStyle = pWndDesktop->dwExStyle;
788 cs.lpszClass = DESKTOP_CLASS_ATOM;
790 SetRect( &rect, 0, 0, cs.cx, cs.cy );
791 WIN_SetRectangles( hwndDesktop, &rect, &rect );
792 WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
794 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
796 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
797 WIN_ReleaseWndPtr( pWndDesktop );
802 /***********************************************************************
805 * Fix the coordinates - Helper for WIN_CreateWindowEx.
806 * returns default show mode in sw.
807 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
809 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
811 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
812 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
814 if (cs->style & (WS_CHILD | WS_POPUP))
816 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
817 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
819 else /* overlapped window */
823 GetStartupInfoA( &info );
825 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
827 /* Never believe Microsoft's documentation... CreateWindowEx doc says
828 * that if an overlapped window is created with WS_VISIBLE style bit
829 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
830 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
833 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
834 * 2) it does not ignore the y parameter as the docs claim; instead, it
835 * uses it as second parameter to ShowWindow() unless y is either
836 * CW_USEDEFAULT or CW_USEDEFAULT16.
838 * The fact that we didn't do 2) caused bogus windows pop up when wine
839 * was running apps that were using this obscure feature. Example -
840 * calc.exe that comes with Win98 (only Win98, it's different from
841 * the one that comes with Win95 and NT)
843 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
844 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
845 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
848 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
850 if (info.dwFlags & STARTF_USESIZE)
852 cs->cx = info.dwXSize;
853 cs->cy = info.dwYSize;
855 else /* if no other hint from the app, pick 3/4 of the screen real estate */
858 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
859 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
860 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
867 /* neither x nor cx are default. Check the y values .
868 * In the trace we see Outlook and Outlook Express using
869 * cy set to CW_USEDEFAULT when opening the address book.
871 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
873 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
874 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
875 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
880 /***********************************************************************
883 static void dump_window_styles( DWORD style, DWORD exstyle )
886 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
887 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
888 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
889 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
890 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
891 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
892 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
893 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
894 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
897 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
898 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
900 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
901 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
902 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
903 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
904 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
905 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
906 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
907 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
909 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
910 #define DUMPED_STYLES \
930 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
935 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
936 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
937 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
938 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
939 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
940 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
941 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
942 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
943 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
944 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
945 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
946 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
947 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
948 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
949 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
950 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
951 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
952 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
954 #define DUMPED_EX_STYLES \
955 (WS_EX_DLGMODALFRAME | \
957 WS_EX_NOPARENTNOTIFY | \
959 WS_EX_ACCEPTFILES | \
960 WS_EX_TRANSPARENT | \
965 WS_EX_CONTEXTHELP | \
968 WS_EX_LEFTSCROLLBAR | \
969 WS_EX_CONTROLPARENT | \
974 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
976 #undef DUMPED_EX_STYLES
980 /***********************************************************************
983 * Implementation of CreateWindowEx().
985 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
986 WINDOWPROCTYPE type )
989 struct tagCLASS *classPtr;
991 HWND hwnd, parent, owner;
996 BOOL unicode = (type == WIN_PROC_32W);
998 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
999 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
1000 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
1001 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1002 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1004 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1006 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1007 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1009 /* Find the parent window */
1011 parent = GetDesktopWindow();
1015 /* Make sure parent is valid */
1016 if (!IsWindow( cs->hwndParent ))
1018 WARN("Bad parent %04x\n", cs->hwndParent );
1021 if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
1022 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
1024 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
1026 WARN("No parent for child window\n" );
1027 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1030 /* Find the window class */
1031 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1032 &wndExtra, &winproc, &clsStyle, &dce )))
1034 WARN("Bad class '%s'\n", cs->lpszClass );
1038 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1040 /* Correct the window style - stage 1
1042 * These are patches that appear to affect both the style loaded into the
1043 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1045 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1046 * why does the user get to set it?
1049 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1050 * tested for WS_POPUP
1052 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1053 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1054 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1055 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1057 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1059 /* Create the window structure */
1061 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1062 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1064 TRACE("out of memory\n" );
1067 hwnd = wndPtr->hwndSelf;
1069 /* Fill the window structure */
1071 wndPtr->tid = GetCurrentThreadId();
1072 wndPtr->owner = owner;
1073 wndPtr->parent = parent;
1074 wndPtr->class = classPtr;
1075 wndPtr->winproc = winproc;
1076 wndPtr->hInstance = cs->hInstance;
1077 wndPtr->text = NULL;
1078 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1079 wndPtr->hrgnUpdate = 0;
1080 wndPtr->hrgnWnd = 0;
1081 wndPtr->hwndLastActive = hwnd;
1082 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1083 wndPtr->dwExStyle = cs->dwExStyle;
1084 wndPtr->clsStyle = clsStyle;
1085 wndPtr->wIDmenu = 0;
1086 wndPtr->helpContext = 0;
1087 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1088 wndPtr->pVScroll = NULL;
1089 wndPtr->pHScroll = NULL;
1090 wndPtr->userdata = 0;
1091 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1092 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1093 wndPtr->cbWndExtra = wndExtra;
1095 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1097 /* Correct the window style - stage 2 */
1099 if (!(cs->style & WS_CHILD))
1101 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1102 if (!(cs->style & WS_POPUP))
1104 wndPtr->dwStyle |= WS_CAPTION;
1105 wndPtr->flags |= WIN_NEED_SIZE;
1108 SERVER_START_REQ( set_window_info )
1111 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1112 req->style = wndPtr->dwStyle;
1113 req->ex_style = wndPtr->dwExStyle;
1114 req->instance = (void *)wndPtr->hInstance;
1115 wine_server_call( req );
1119 /* Get class or window DC if needed */
1121 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1122 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1123 else wndPtr->dce = NULL;
1125 /* Set the window menu */
1127 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1129 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1132 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1135 if (HIWORD(cs->hInstance))
1136 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1138 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1140 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1144 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1145 WIN_ReleaseWndPtr( wndPtr );
1147 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1149 WIN_DestroyWindow( hwnd );
1153 /* Notify the parent window only */
1155 send_parent_notify( hwnd, WM_CREATE );
1156 if (!IsWindow( hwnd )) return 0;
1158 if (cs->style & WS_VISIBLE)
1160 /* in case WS_VISIBLE got set in the meantime */
1161 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1162 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1163 WIN_ReleasePtr( wndPtr );
1164 ShowWindow( hwnd, sw );
1167 /* Call WH_SHELL hook */
1169 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1170 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1172 TRACE("created window %04x\n", hwnd);
1177 /***********************************************************************
1178 * CreateWindow (USER.41)
1180 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1181 DWORD style, INT16 x, INT16 y, INT16 width,
1182 INT16 height, HWND16 parent, HMENU16 menu,
1183 HINSTANCE16 instance, LPVOID data )
1185 return CreateWindowEx16( 0, className, windowName, style,
1186 x, y, width, height, parent, menu, instance, data );
1190 /***********************************************************************
1191 * CreateWindowEx (USER.452)
1193 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1194 LPCSTR windowName, DWORD style, INT16 x,
1195 INT16 y, INT16 width, INT16 height,
1196 HWND16 parent, HMENU16 menu,
1197 HINSTANCE16 instance, LPVOID data )
1203 /* Find the class atom */
1205 if (HIWORD(className))
1207 if (!(classAtom = GlobalFindAtomA( className )))
1209 ERR( "bad class name %s\n", debugres_a(className) );
1215 classAtom = LOWORD(className);
1216 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1218 ERR( "bad atom %x\n", classAtom);
1224 /* Fix the coordinates */
1226 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1227 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1228 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1229 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1231 /* Create the window */
1233 cs.lpCreateParams = data;
1234 cs.hInstance = (HINSTANCE)instance;
1235 cs.hMenu = (HMENU)menu;
1236 cs.hwndParent = WIN_Handle32( parent );
1238 cs.lpszName = windowName;
1239 cs.lpszClass = className;
1240 cs.dwExStyle = exStyle;
1242 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1246 /***********************************************************************
1247 * CreateWindowExA (USER32.@)
1249 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1250 LPCSTR windowName, DWORD style, INT x,
1251 INT y, INT width, INT height,
1252 HWND parent, HMENU menu,
1253 HINSTANCE instance, LPVOID data )
1260 instance=GetModuleHandleA(NULL);
1262 if(exStyle & WS_EX_MDICHILD)
1263 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1265 /* Find the class atom */
1267 if (HIWORD(className))
1269 if (!(classAtom = GlobalFindAtomA( className )))
1271 ERR( "bad class name %s\n", debugres_a(className) );
1277 classAtom = LOWORD(className);
1278 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1280 ERR( "bad atom %x\n", classAtom);
1286 /* Create the window */
1288 cs.lpCreateParams = data;
1289 cs.hInstance = instance;
1291 cs.hwndParent = parent;
1297 cs.lpszName = windowName;
1298 cs.lpszClass = className;
1299 cs.dwExStyle = exStyle;
1301 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1305 /***********************************************************************
1306 * CreateWindowExW (USER32.@)
1308 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1309 LPCWSTR windowName, DWORD style, INT x,
1310 INT y, INT width, INT height,
1311 HWND parent, HMENU menu,
1312 HINSTANCE instance, LPVOID data )
1319 instance=GetModuleHandleA(NULL);
1321 if(exStyle & WS_EX_MDICHILD)
1322 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1324 /* Find the class atom */
1326 if (HIWORD(className))
1328 if (!(classAtom = GlobalFindAtomW( className )))
1330 ERR( "bad class name %s\n", debugres_w(className) );
1336 classAtom = LOWORD(className);
1337 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1339 ERR( "bad atom %x\n", classAtom);
1345 /* Create the window */
1347 cs.lpCreateParams = data;
1348 cs.hInstance = instance;
1350 cs.hwndParent = parent;
1356 cs.lpszName = windowName;
1357 cs.lpszClass = className;
1358 cs.dwExStyle = exStyle;
1360 /* Note: we rely on the fact that CREATESTRUCTA and */
1361 /* CREATESTRUCTW have the same layout. */
1362 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1366 /***********************************************************************
1367 * WIN_SendDestroyMsg
1369 static void WIN_SendDestroyMsg( HWND hwnd )
1371 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1372 if (USER_Driver.pResetSelectionOwner)
1373 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1376 * Send the WM_DESTROY to the window.
1378 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1381 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1382 * make sure that the window still exists when we come back.
1389 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1391 /* start from the end (FIXME: is this needed?) */
1392 for (i = 0; pWndArray[i]; i++) ;
1396 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1398 HeapFree( GetProcessHeap(), 0, pWndArray );
1401 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1405 /***********************************************************************
1406 * DestroyWindow (USER32.@)
1408 BOOL WINAPI DestroyWindow( HWND hwnd )
1413 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1415 SetLastError( ERROR_ACCESS_DENIED );
1419 TRACE("(%04x)\n", hwnd);
1421 /* Look whether the focus is within the tree of windows we will
1425 if (h == hwnd || IsChild( hwnd, h ))
1427 HWND parent = GetAncestor( hwnd, GA_PARENT );
1428 if (parent == GetDesktopWindow()) parent = 0;
1434 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1436 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1440 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1441 send_parent_notify( hwnd, WM_DESTROY );
1443 else if (!GetWindow( hwnd, GW_OWNER ))
1445 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1446 /* FIXME: clean up palette - see "Internals" p.352 */
1449 if (!IsWindow(hwnd)) return TRUE;
1451 if (USER_Driver.pResetSelectionOwner)
1452 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1454 /* Hide the window */
1456 ShowWindow( hwnd, SW_HIDE );
1457 if (!IsWindow(hwnd)) return TRUE;
1459 /* Recursively destroy owned windows */
1468 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1471 for (i = 0; list[i]; i++)
1473 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1474 if (WIN_IsCurrentThread( list[i] ))
1476 DestroyWindow( list[i] );
1480 WIN_SetOwner( list[i], 0 );
1482 HeapFree( GetProcessHeap(), 0, list );
1484 if (!got_one) break;
1487 WINPOS_ActivateOtherWindow( hwnd );
1489 if ((owner = GetWindow( hwnd, GW_OWNER )))
1491 WND *ptr = WIN_FindWndPtr( owner );
1494 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1495 WIN_ReleaseWndPtr( ptr );
1500 /* Send destroy messages */
1502 WIN_SendDestroyMsg( hwnd );
1503 if (!IsWindow( hwnd )) return TRUE;
1505 /* Unlink now so we won't bother with the children later on */
1507 WIN_UnlinkWindow( hwnd );
1509 /* Destroy the window storage */
1511 WIN_DestroyWindow( hwnd );
1516 /***********************************************************************
1517 * CloseWindow (USER32.@)
1519 BOOL WINAPI CloseWindow( HWND hwnd )
1521 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1522 ShowWindow( hwnd, SW_MINIMIZE );
1527 /***********************************************************************
1528 * OpenIcon (USER32.@)
1530 BOOL WINAPI OpenIcon( HWND hwnd )
1532 if (!IsIconic( hwnd )) return FALSE;
1533 ShowWindow( hwnd, SW_SHOWNORMAL );
1538 /***********************************************************************
1541 * Implementation of FindWindow() and FindWindowEx().
1543 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1548 WCHAR *buffer = NULL;
1550 if (!parent) parent = GetDesktopWindow();
1553 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1554 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1557 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1561 child = WIN_GetFullHandle( child );
1562 while (list[i] && list[i] != child) i++;
1563 if (!list[i]) goto done;
1564 i++; /* start from next window */
1571 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1578 if (list) HeapFree( GetProcessHeap(), 0, list );
1579 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1585 /***********************************************************************
1586 * FindWindowA (USER32.@)
1588 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1590 HWND ret = FindWindowExA( 0, 0, className, title );
1591 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1596 /***********************************************************************
1597 * FindWindowExA (USER32.@)
1599 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1600 LPCSTR className, LPCSTR title )
1609 /* If the atom doesn't exist, then no class */
1610 /* with this name exists either. */
1611 if (!(atom = GlobalFindAtomA( className )))
1613 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1617 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1619 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1620 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1621 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1622 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1623 HeapFree( GetProcessHeap(), 0, buffer );
1628 /***********************************************************************
1629 * FindWindowExW (USER32.@)
1631 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1632 LPCWSTR className, LPCWSTR title )
1638 /* If the atom doesn't exist, then no class */
1639 /* with this name exists either. */
1640 if (!(atom = GlobalFindAtomW( className )))
1642 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1646 return WIN_FindWindow( parent, child, atom, title );
1650 /***********************************************************************
1651 * FindWindowW (USER32.@)
1653 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1655 return FindWindowExW( 0, 0, className, title );
1659 /**********************************************************************
1660 * GetDesktopWindow (USER32.@)
1662 HWND WINAPI GetDesktopWindow(void)
1664 if (pWndDesktop) return pWndDesktop->hwndSelf;
1665 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" );
1671 /*******************************************************************
1672 * EnableWindow (USER32.@)
1674 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1681 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1682 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1686 TRACE("( %x, %d )\n", hwnd, enable);
1688 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1689 style = wndPtr->dwStyle;
1690 retvalue = ((style & WS_DISABLED) != 0);
1691 WIN_ReleasePtr( wndPtr );
1693 if (enable && retvalue)
1695 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1696 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1698 else if (!enable && !retvalue)
1700 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1702 WIN_SetStyle( hwnd, style | WS_DISABLED );
1704 if (hwnd == GetFocus())
1705 SetFocus( 0 ); /* A disabled window can't have the focus */
1707 if (hwnd == GetCapture())
1708 ReleaseCapture(); /* A disabled window can't capture the mouse */
1710 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1716 /***********************************************************************
1717 * IsWindowEnabled (USER32.@)
1719 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1721 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1725 /***********************************************************************
1726 * IsWindowUnicode (USER32.@)
1728 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1733 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1734 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1735 WIN_ReleaseWndPtr(wndPtr);
1740 /**********************************************************************
1741 * GetWindowWord (USER32.@)
1743 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1748 WND *wndPtr = WIN_GetPtr( hwnd );
1751 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1754 if (wndPtr == WND_OTHER_PROCESS)
1756 if (IsWindow( hwnd ))
1757 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1758 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1761 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1763 WARN("Invalid offset %d\n", offset );
1764 SetLastError( ERROR_INVALID_INDEX );
1766 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1767 WIN_ReleasePtr( wndPtr );
1773 case GWL_HWNDPARENT:
1774 return GetWindowLongW( hwnd, offset );
1778 LONG ret = GetWindowLongW( hwnd, offset );
1780 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1784 WARN("Invalid offset %d\n", offset );
1790 /**********************************************************************
1791 * SetWindowWord (USER32.@)
1793 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1802 case GWL_HWNDPARENT:
1803 return SetWindowLongW( hwnd, offset, (UINT)newval );
1807 WARN("Invalid offset %d\n", offset );
1808 SetLastError( ERROR_INVALID_INDEX );
1813 wndPtr = WIN_GetPtr( hwnd );
1814 if (wndPtr == WND_OTHER_PROCESS)
1817 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1818 offset, newval, hwnd );
1823 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1827 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1829 WARN("Invalid offset %d\n", offset );
1830 WIN_ReleasePtr(wndPtr);
1831 SetLastError( ERROR_INVALID_INDEX );
1834 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1837 WIN_ReleasePtr(wndPtr);
1842 /**********************************************************************
1845 * Helper function for GetWindowLong().
1847 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1852 if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1854 if (!(wndPtr = WIN_GetPtr( hwnd )))
1856 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1860 if (wndPtr == WND_OTHER_PROCESS)
1865 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1866 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1869 if (offset == GWL_WNDPROC)
1871 SetLastError( ERROR_ACCESS_DENIED );
1874 SERVER_START_REQ( set_window_info )
1877 req->flags = 0; /* don't set anything, just retrieve */
1878 if (!wine_server_call_err( req ))
1882 case GWL_STYLE: retvalue = reply->old_style; break;
1883 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1884 case GWL_ID: retvalue = reply->old_id; break;
1885 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1886 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1888 SetLastError( ERROR_INVALID_INDEX );
1897 /* now we have a valid wndPtr */
1901 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1904 * Some programs try to access last element from 16 bit
1905 * code using illegal offset value. Hopefully this is
1906 * what those programs really expect.
1908 if (type == WIN_PROC_16 &&
1909 wndPtr->cbWndExtra >= 4 &&
1910 offset == wndPtr->cbWndExtra - sizeof(WORD))
1912 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1914 ERR( "- replaced invalid offset %d with %d\n",
1917 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1918 WIN_ReleasePtr( wndPtr );
1921 WARN("Invalid offset %d\n", offset );
1922 WIN_ReleasePtr( wndPtr );
1923 SetLastError( ERROR_INVALID_INDEX );
1926 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1927 /* Special case for dialog window procedure */
1928 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1929 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1930 WIN_ReleasePtr( wndPtr );
1936 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1937 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1938 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1939 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1940 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1941 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1943 WARN("Unknown offset %d\n", offset );
1944 SetLastError( ERROR_INVALID_INDEX );
1947 WIN_ReleasePtr(wndPtr);
1952 /**********************************************************************
1955 * Helper function for SetWindowLong().
1957 * 0 is the failure code. However, in the case of failure SetLastError
1958 * must be set to distinguish between a 0 return value and a failure.
1960 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1961 WINDOWPROCTYPE type )
1966 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1968 if (!WIN_IsCurrentProcess( hwnd ))
1970 if (offset == GWL_WNDPROC)
1972 SetLastError( ERROR_ACCESS_DENIED );
1975 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1978 wndPtr = WIN_GetPtr( hwnd );
1982 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1983 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1985 WARN("Invalid offset %d\n", offset );
1986 WIN_ReleasePtr( wndPtr );
1987 SetLastError( ERROR_INVALID_INDEX );
1990 /* Special case for dialog window procedure */
1991 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1993 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1994 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1995 type, WIN_PROC_WINDOW );
1996 WIN_ReleasePtr( wndPtr );
2001 WIN_ReleasePtr( wndPtr );
2008 /* first some special cases */
2013 style.styleOld = wndPtr->dwStyle;
2014 style.styleNew = newval;
2015 WIN_ReleasePtr( wndPtr );
2016 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2017 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2018 newval = style.styleNew;
2020 case GWL_HWNDPARENT:
2021 WIN_ReleasePtr( wndPtr );
2022 return (LONG)SetParent( hwnd, (HWND)newval );
2024 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2025 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2026 type, WIN_PROC_WINDOW );
2027 WIN_ReleasePtr( wndPtr );
2034 WIN_ReleasePtr( wndPtr );
2035 WARN("Invalid offset %d\n", offset );
2036 SetLastError( ERROR_INVALID_INDEX );
2040 SERVER_START_REQ( set_window_info )
2046 req->flags = SET_WIN_STYLE;
2047 req->style = newval;
2050 req->flags = SET_WIN_EXSTYLE;
2051 req->ex_style = newval;
2054 req->flags = SET_WIN_ID;
2058 req->flags = SET_WIN_INSTANCE;
2059 req->instance = (void *)newval;
2062 req->flags = SET_WIN_USERDATA;
2063 req->user_data = (void *)newval;
2066 if ((ok = !wine_server_call_err( req )))
2071 wndPtr->dwStyle = newval;
2072 retval = reply->old_style;
2075 wndPtr->dwExStyle = newval;
2076 retval = reply->old_ex_style;
2079 wndPtr->wIDmenu = newval;
2080 retval = reply->old_id;
2083 wndPtr->hInstance = newval;
2084 retval = (HINSTANCE)reply->old_instance;
2087 wndPtr->userdata = newval;
2088 retval = (ULONG_PTR)reply->old_user_data;
2094 WIN_ReleasePtr( wndPtr );
2098 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2099 USER_Driver.pSetWindowStyle( hwnd, retval );
2101 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2102 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2109 /**********************************************************************
2110 * GetWindowLong (USER.135)
2112 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2114 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2118 /**********************************************************************
2119 * GetWindowLongA (USER32.@)
2121 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2123 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2127 /**********************************************************************
2128 * GetWindowLongW (USER32.@)
2130 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2132 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2136 /**********************************************************************
2137 * SetWindowLong (USER.136)
2139 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2141 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2145 /**********************************************************************
2146 * SetWindowLongA (USER32.@)
2148 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2150 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2154 /**********************************************************************
2155 * SetWindowLongW (USER32.@) Set window attribute
2157 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2158 * value in a window's extra memory.
2160 * The _hwnd_ parameter specifies the window. is the handle to a
2161 * window that has extra memory. The _newval_ parameter contains the
2162 * new attribute or extra memory value. If positive, the _offset_
2163 * parameter is the byte-addressed location in the window's extra
2164 * memory to set. If negative, _offset_ specifies the window
2165 * attribute to set, and should be one of the following values:
2167 * GWL_EXSTYLE The window's extended window style
2169 * GWL_STYLE The window's window style.
2171 * GWL_WNDPROC Pointer to the window's window procedure.
2173 * GWL_HINSTANCE The window's pplication instance handle.
2175 * GWL_ID The window's identifier.
2177 * GWL_USERDATA The window's user-specified data.
2179 * If the window is a dialog box, the _offset_ parameter can be one of
2180 * the following values:
2182 * DWL_DLGPROC The address of the window's dialog box procedure.
2184 * DWL_MSGRESULT The return value of a message
2185 * that the dialog box procedure processed.
2187 * DWL_USER Application specific information.
2191 * If successful, returns the previous value located at _offset_. Otherwise,
2196 * Extra memory for a window class is specified by a nonzero cbWndExtra
2197 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2198 * time of class creation.
2200 * Using GWL_WNDPROC to set a new window procedure effectively creates
2201 * a window subclass. Use CallWindowProc() in the new windows procedure
2202 * to pass messages to the superclass's window procedure.
2204 * The user data is reserved for use by the application which created
2207 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2208 * instead, call the EnableWindow() function to change the window's
2211 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2212 * SetParent() instead.
2215 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2216 * it sends WM_STYLECHANGING before changing the settings
2217 * and WM_STYLECHANGED afterwards.
2218 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2220 LONG WINAPI SetWindowLongW(
2221 HWND hwnd, /* [in] window to alter */
2222 INT offset, /* [in] offset, in bytes, of location to alter */
2223 LONG newval /* [in] new value of location */
2225 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2229 /*******************************************************************
2230 * GetWindowTextA (USER32.@)
2232 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2236 if (WIN_IsCurrentProcess( hwnd ))
2237 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2239 /* when window belongs to other process, don't send a message */
2240 if (nMaxCount <= 0) return 0;
2241 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2242 get_server_window_text( hwnd, buffer, nMaxCount );
2243 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2244 lpString[nMaxCount-1] = 0;
2245 HeapFree( GetProcessHeap(), 0, buffer );
2246 return strlen(lpString);
2250 /*******************************************************************
2251 * InternalGetWindowText (USER32.@)
2253 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2257 if (nMaxCount <= 0) return 0;
2258 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2259 if (win != WND_OTHER_PROCESS)
2261 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2262 else lpString[0] = 0;
2263 WIN_ReleasePtr( win );
2267 get_server_window_text( hwnd, lpString, nMaxCount );
2269 return strlenW(lpString);
2273 /*******************************************************************
2274 * GetWindowTextW (USER32.@)
2276 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2278 if (WIN_IsCurrentProcess( hwnd ))
2279 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2281 /* when window belongs to other process, don't send a message */
2282 if (nMaxCount <= 0) return 0;
2283 get_server_window_text( hwnd, lpString, nMaxCount );
2284 return strlenW(lpString);
2288 /*******************************************************************
2289 * SetWindowText (USER32.@)
2290 * SetWindowTextA (USER32.@)
2292 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2294 if (!WIN_IsCurrentProcess( hwnd ))
2296 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2297 SetLastError( ERROR_ACCESS_DENIED );
2300 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2304 /*******************************************************************
2305 * SetWindowTextW (USER32.@)
2307 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2309 if (!WIN_IsCurrentProcess( hwnd ))
2311 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2312 SetLastError( ERROR_ACCESS_DENIED );
2315 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2319 /*******************************************************************
2320 * GetWindowTextLengthA (USER32.@)
2322 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2324 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2327 /*******************************************************************
2328 * GetWindowTextLengthW (USER32.@)
2330 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2332 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2336 /*******************************************************************
2337 * IsWindow (USER32.@)
2339 BOOL WINAPI IsWindow( HWND hwnd )
2344 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2346 if (ptr != WND_OTHER_PROCESS)
2348 WIN_ReleasePtr( ptr );
2352 /* check other processes */
2353 SERVER_START_REQ( get_window_info )
2356 ret = !wine_server_call_err( req );
2363 /***********************************************************************
2364 * GetWindowThreadProcessId (USER32.@)
2366 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2371 if (!(ptr = WIN_GetPtr( hwnd )))
2373 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2377 if (ptr != WND_OTHER_PROCESS)
2379 /* got a valid window */
2381 if (process) *process = GetCurrentProcessId();
2382 WIN_ReleasePtr( ptr );
2386 /* check other processes */
2387 SERVER_START_REQ( get_window_info )
2390 if (!wine_server_call_err( req ))
2392 tid = (DWORD)reply->tid;
2393 if (process) *process = (DWORD)reply->pid;
2401 /*****************************************************************
2402 * GetParent (USER32.@)
2404 HWND WINAPI GetParent( HWND hwnd )
2409 if (!(wndPtr = WIN_GetPtr( hwnd )))
2411 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2414 if (wndPtr == WND_OTHER_PROCESS)
2416 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2417 if (style & (WS_POPUP | WS_CHILD))
2419 SERVER_START_REQ( get_window_tree )
2422 if (!wine_server_call_err( req ))
2424 if (style & WS_CHILD) retvalue = reply->parent;
2425 else retvalue = reply->owner;
2433 if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2434 else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2435 WIN_ReleasePtr( wndPtr );
2441 /*****************************************************************
2442 * GetAncestor (USER32.@)
2444 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2447 HWND *list, ret = 0;
2449 if (type == GA_PARENT)
2451 if (!(win = WIN_GetPtr( hwnd )))
2453 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2456 if (win != WND_OTHER_PROCESS)
2459 WIN_ReleasePtr( win );
2461 else /* need to query the server */
2463 SERVER_START_REQ( get_window_tree )
2466 if (!wine_server_call_err( req )) ret = reply->parent;
2473 if (!(list = WIN_ListParents( hwnd ))) return 0;
2475 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2479 while (list[count]) count++;
2480 ret = list[count - 2]; /* get the one before the desktop */
2482 HeapFree( GetProcessHeap(), 0, list );
2484 if (ret && type == GA_ROOTOWNER)
2488 HWND owner = GetWindow( ret, GW_OWNER );
2497 /*****************************************************************
2498 * SetParent (USER32.@)
2500 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2503 HWND retvalue, full_handle;
2506 if (!parent) parent = GetDesktopWindow();
2507 else parent = WIN_GetFullHandle( parent );
2509 if (!IsWindow( parent ))
2511 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2515 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2516 return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2520 if (USER_Driver.pSetParent)
2521 return USER_Driver.pSetParent( hwnd, parent );
2523 /* Windows hides the window first, then shows it again
2524 * including the WM_SHOWWINDOW messages and all */
2525 was_visible = ShowWindow( hwnd, SW_HIDE );
2527 if (!IsWindow( parent )) return 0;
2528 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2530 retvalue = wndPtr->parent; /* old parent */
2531 if (parent != retvalue)
2533 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2535 if (parent != GetDesktopWindow()) /* a child window */
2537 if (!(wndPtr->dwStyle & WS_CHILD))
2539 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2540 if (menu) DestroyMenu( menu );
2544 WIN_ReleasePtr( wndPtr );
2546 /* SetParent additionally needs to make hwnd the topmost window
2547 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2548 WM_WINDOWPOSCHANGED notification messages.
2550 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2551 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2552 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2553 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2558 /*******************************************************************
2559 * IsChild (USER32.@)
2561 BOOL WINAPI IsChild( HWND parent, HWND child )
2563 HWND *list = WIN_ListParents( child );
2567 if (!list) return FALSE;
2568 parent = WIN_GetFullHandle( parent );
2569 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2570 ret = (list[i] != 0);
2571 HeapFree( GetProcessHeap(), 0, list );
2576 /***********************************************************************
2577 * IsWindowVisible (USER32.@)
2579 BOOL WINAPI IsWindowVisible( HWND hwnd )
2585 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2586 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2587 for (i = 0; list[i]; i++)
2588 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2590 HeapFree( GetProcessHeap(), 0, list );
2595 /***********************************************************************
2596 * WIN_IsWindowDrawable
2598 * hwnd is drawable when it is visible, all parents are not
2599 * minimized, and it is itself not minimized unless we are
2600 * trying to draw its default class icon.
2602 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2607 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2609 if (!(style & WS_VISIBLE)) return FALSE;
2610 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2612 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2613 for (i = 0; list[i]; i++)
2614 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2617 HeapFree( GetProcessHeap(), 0, list );
2622 /*******************************************************************
2623 * GetTopWindow (USER32.@)
2625 HWND WINAPI GetTopWindow( HWND hwnd )
2627 if (!hwnd) hwnd = GetDesktopWindow();
2628 return GetWindow( hwnd, GW_CHILD );
2632 /*******************************************************************
2633 * GetWindow (USER32.@)
2635 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2639 if (rel == GW_OWNER) /* this one may be available locally */
2641 WND *wndPtr = WIN_GetPtr( hwnd );
2644 SetLastError( ERROR_INVALID_HANDLE );
2647 if (wndPtr != WND_OTHER_PROCESS)
2649 retval = wndPtr->owner;
2650 WIN_ReleasePtr( wndPtr );
2653 /* else fall through to server call */
2656 SERVER_START_REQ( get_window_tree )
2659 if (!wine_server_call_err( req ))
2664 retval = reply->first_sibling;
2667 retval = reply->last_sibling;
2670 retval = reply->next_sibling;
2673 retval = reply->prev_sibling;
2676 retval = reply->owner;
2679 retval = reply->first_child;
2689 /***********************************************************************
2690 * WIN_InternalShowOwnedPopups
2692 * Internal version of ShowOwnedPopups; Wine functions should use this
2693 * to avoid interfering with application calls to ShowOwnedPopups
2694 * and to make sure the application can't prevent showing/hiding.
2696 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2700 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2704 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2706 if (!win_array) return TRUE;
2709 * Show windows Lowest first, Highest last to preserve Z-Order
2711 while (win_array[count]) count++;
2712 while (--count >= 0)
2714 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2715 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2717 if (pWnd->dwStyle & WS_POPUP)
2721 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2722 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2725 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2727 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2728 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2733 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2734 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2735 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2738 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2740 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2741 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2742 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2746 WIN_ReleaseWndPtr( pWnd );
2748 HeapFree( GetProcessHeap(), 0, win_array );
2753 /*******************************************************************
2754 * ShowOwnedPopups (USER32.@)
2756 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2760 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2762 if (!win_array) return TRUE;
2764 while (win_array[count]) count++;
2765 while (--count >= 0)
2767 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2768 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2770 if (pWnd->dwStyle & WS_POPUP)
2774 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2776 /* In Windows, ShowOwnedPopups(TRUE) generates
2777 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2778 * regardless of the state of the owner
2780 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2781 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2786 if (IsWindowVisible(pWnd->hwndSelf))
2788 /* In Windows, ShowOwnedPopups(FALSE) generates
2789 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2790 * regardless of the state of the owner
2792 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2793 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2797 WIN_ReleaseWndPtr( pWnd );
2799 HeapFree( GetProcessHeap(), 0, win_array );
2804 /*******************************************************************
2805 * GetLastActivePopup (USER32.@)
2807 HWND WINAPI GetLastActivePopup( HWND hwnd )
2810 WND *wndPtr =WIN_FindWndPtr(hwnd);
2811 if (!wndPtr) return hwnd;
2812 retval = wndPtr->hwndLastActive;
2813 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2814 WIN_ReleaseWndPtr(wndPtr);
2819 /*******************************************************************
2822 * Build an array of all parents of a given window, starting with
2823 * the immediate parent. The array must be freed with HeapFree.
2824 * Returns NULL if window is a top-level window.
2826 HWND *WIN_ListParents( HWND hwnd )
2829 HWND current, *list;
2830 int pos = 0, size = 16, count = 0;
2832 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2837 if (!(win = WIN_GetPtr( current ))) goto empty;
2838 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2839 list[pos] = win->parent;
2840 WIN_ReleasePtr( win );
2841 if (!(current = list[pos]))
2843 if (!pos) goto empty;
2846 if (++pos == size - 1)
2848 /* need to grow the list */
2849 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2850 if (!new_list) goto empty;
2856 /* at least one parent belongs to another process, have to query the server */
2861 SERVER_START_REQ( get_window_parents )
2864 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2865 if (!wine_server_call( req )) count = reply->count;
2868 if (!count) goto empty;
2874 HeapFree( GetProcessHeap(), 0, list );
2876 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2880 HeapFree( GetProcessHeap(), 0, list );
2885 /*******************************************************************
2888 * Build an array of the children of a given window. The array must be
2889 * freed with HeapFree. Returns NULL when no windows are found.
2891 HWND *WIN_ListChildren( HWND hwnd )
2893 return list_window_children( hwnd, 0, 0 );
2897 /*******************************************************************
2898 * EnumWindows (USER32.@)
2900 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2906 /* We have to build a list of all windows first, to avoid */
2907 /* unpleasant side-effects, for instance if the callback */
2908 /* function changes the Z-order of the windows. */
2910 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2912 /* Now call the callback function for every window */
2914 iWndsLocks = WIN_SuspendWndsLock();
2915 for (i = 0; list[i]; i++)
2917 /* Make sure that the window still exists */
2918 if (!IsWindow( list[i] )) continue;
2919 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2921 WIN_RestoreWndsLock(iWndsLocks);
2922 HeapFree( GetProcessHeap(), 0, list );
2927 /**********************************************************************
2928 * EnumThreadWindows (USER32.@)
2930 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2935 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2938 /* Now call the callback function for every window */
2940 iWndsLocks = WIN_SuspendWndsLock();
2941 for (i = 0; list[i]; i++)
2942 if (!func( list[i], lParam )) break;
2943 WIN_RestoreWndsLock(iWndsLocks);
2944 HeapFree( GetProcessHeap(), 0, list );
2949 /**********************************************************************
2950 * WIN_EnumChildWindows
2952 * Helper function for EnumChildWindows().
2954 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2959 for ( ; *list; list++)
2961 /* Make sure that the window still exists */
2962 if (!IsWindow( *list )) continue;
2963 /* skip owned windows */
2964 if (GetWindow( *list, GW_OWNER )) continue;
2965 /* Build children list first */
2966 childList = WIN_ListChildren( *list );
2968 ret = func( *list, lParam );
2972 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2973 HeapFree( GetProcessHeap(), 0, childList );
2975 if (!ret) return FALSE;
2981 /**********************************************************************
2982 * EnumChildWindows (USER32.@)
2984 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2989 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2990 iWndsLocks = WIN_SuspendWndsLock();
2991 WIN_EnumChildWindows( list, func, lParam );
2992 WIN_RestoreWndsLock(iWndsLocks);
2993 HeapFree( GetProcessHeap(), 0, list );
2998 /*******************************************************************
2999 * AnyPopup (USER.52)
3001 BOOL16 WINAPI AnyPopup16(void)
3007 /*******************************************************************
3008 * AnyPopup (USER32.@)
3010 BOOL WINAPI AnyPopup(void)
3014 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3016 if (!list) return FALSE;
3017 for (i = 0; list[i]; i++)
3019 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3021 retvalue = (list[i] != 0);
3022 HeapFree( GetProcessHeap(), 0, list );
3027 /*******************************************************************
3028 * FlashWindow (USER32.@)
3030 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3032 WND *wndPtr = WIN_FindWndPtr(hWnd);
3034 TRACE("%04x\n", hWnd);
3036 if (!wndPtr) return FALSE;
3037 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3039 if (wndPtr->dwStyle & WS_MINIMIZE)
3041 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3043 HDC hDC = GetDC(hWnd);
3045 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3046 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3048 ReleaseDC( hWnd, hDC );
3049 wndPtr->flags |= WIN_NCACTIVATED;
3053 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3054 wndPtr->flags &= ~WIN_NCACTIVATED;
3056 WIN_ReleaseWndPtr(wndPtr);
3062 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3063 else wparam = (hWnd == GetActiveWindow());
3065 WIN_ReleaseWndPtr(wndPtr);
3066 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3072 /*******************************************************************
3073 * GetWindowContextHelpId (USER32.@)
3075 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3078 WND *wnd = WIN_FindWndPtr( hwnd );
3080 retval = wnd->helpContext;
3081 WIN_ReleaseWndPtr(wnd);
3086 /*******************************************************************
3087 * SetWindowContextHelpId (USER32.@)
3089 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3091 WND *wnd = WIN_FindWndPtr( hwnd );
3092 if (!wnd) return FALSE;
3093 wnd->helpContext = id;
3094 WIN_ReleaseWndPtr(wnd);
3099 /*******************************************************************
3102 * recursively find a child that contains spDragInfo->pt point
3103 * and send WM_QUERYDROPOBJECT
3105 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3107 BOOL16 wParam, bResult = 0;
3109 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3112 if (!ptrDragInfo) return FALSE;
3114 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3116 GetWindowRect(hQueryWnd,&tempRect);
3118 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3120 if (!IsIconic( hQueryWnd ))
3122 GetClientRect( hQueryWnd, &tempRect );
3123 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3125 if (PtInRect( &tempRect, pt))
3128 HWND *list = WIN_ListChildren( hQueryWnd );
3134 for (i = 0; list[i]; i++)
3136 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3138 GetWindowRect( list[i], &tempRect );
3139 if (PtInRect( &tempRect, pt )) break;
3144 if (IsWindowEnabled( list[i] ))
3145 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3147 HeapFree( GetProcessHeap(), 0, list );
3149 if(bResult) return bResult;
3155 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3157 ptrDragInfo->hScope = hQueryWnd;
3159 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3160 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3162 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3168 /*******************************************************************
3169 * DragDetect (USER32.@)
3171 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3176 rect.left = pt.x - wDragWidth;
3177 rect.right = pt.x + wDragWidth;
3179 rect.top = pt.y - wDragHeight;
3180 rect.bottom = pt.y + wDragHeight;
3186 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3188 if( msg.message == WM_LBUTTONUP )
3193 if( msg.message == WM_MOUSEMOVE )
3196 tmp.x = LOWORD(msg.lParam);
3197 tmp.y = HIWORD(msg.lParam);
3198 if( !PtInRect( &rect, tmp ))
3210 /******************************************************************************
3211 * DragObject (USER.464)
3213 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3214 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3217 LPDRAGINFO16 lpDragInfo;
3219 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
3220 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3221 HCURSOR16 hCurrentCursor = 0;
3222 HWND16 hCurrentWnd = 0;
3224 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3225 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3227 if( !lpDragInfo || !spDragInfo ) return 0L;
3229 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3231 GlobalFree16(hDragInfo);
3237 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3239 GlobalFree16(hDragInfo);
3243 if( hDragCursor == hCursor ) hDragCursor = 0;
3244 else hCursor = hDragCursor;
3246 hOldCursor = SetCursor(hDragCursor);
3249 lpDragInfo->hWnd = hWnd;
3250 lpDragInfo->hScope = 0;
3251 lpDragInfo->wFlags = wObj;
3252 lpDragInfo->hList = szList; /* near pointer! */
3253 lpDragInfo->hOfStruct = hOfStruct;
3261 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3263 *(lpDragInfo+1) = *lpDragInfo;
3265 lpDragInfo->pt.x = msg.pt.x;
3266 lpDragInfo->pt.y = msg.pt.y;
3268 /* update DRAGINFO struct */
3269 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3271 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3272 hCurrentCursor = hCursor;
3275 hCurrentCursor = hBummer;
3276 lpDragInfo->hScope = 0;
3278 if( hCurrentCursor )
3279 SetCursor(hCurrentCursor);
3281 /* send WM_DRAGLOOP */
3282 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3283 (LPARAM) spDragInfo );
3284 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3285 if( hCurrentWnd != lpDragInfo->hScope )
3288 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3289 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3290 HIWORD(spDragInfo)) );
3291 hCurrentWnd = lpDragInfo->hScope;
3293 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3297 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3299 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3302 ShowCursor( FALSE );
3306 SetCursor( hOldCursor );
3307 if (hDragCursor) DestroyCursor( hDragCursor );
3310 if( hCurrentCursor != hBummer )
3311 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3312 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3315 GlobalFree16(hDragInfo);
3317 return (DWORD)(msg.lParam);
3321 /******************************************************************************
3322 * GetWindowModuleFileNameA (USER32.@)
3324 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3326 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3327 hwnd, lpszFileName, cchFileNameMax);
3331 /******************************************************************************
3332 * GetWindowModuleFileNameW (USER32.@)
3334 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3336 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3337 hwnd, lpszFileName, cchFileNameMax);