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"
28 #include "wine/winbase16.h"
29 #include "wine/winuser16.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
36 #include "cursoricon.h"
43 #include "stackframe.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(win);
47 WINE_DECLARE_DEBUG_CHANNEL(msg);
49 #define NB_USER_HANDLES (LAST_USER_HANDLE - 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];
62 extern SYSLEVEL USER_SysLevel; /* FIXME */
64 /***********************************************************************
67 * Suspend the lock on WND structures.
68 * Returns the number of locks suspended
70 int WIN_SuspendWndsLock( void )
72 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
73 int count = isuspendedLocks;
76 _LeaveSysLevel( &USER_SysLevel );
78 return isuspendedLocks;
81 /***********************************************************************
84 * Restore the suspended locks on WND structures
86 void WIN_RestoreWndsLock( int ipreviousLocks )
88 while ( ipreviousLocks-- > 0 )
89 _EnterSysLevel( &USER_SysLevel );
92 /***********************************************************************
93 * create_window_handle
95 * Create a window handle with the server.
97 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
100 user_handle_t handle = 0;
102 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
104 if (!win) return NULL;
108 SERVER_START_REQ( create_window )
110 req->parent = parent;
113 if ((res = !wine_server_call_err( req ))) handle = reply->handle;
120 HeapFree( GetProcessHeap(), 0, win );
123 index = LOWORD(handle) - FIRST_USER_HANDLE;
124 assert( index < NB_USER_HANDLES );
125 user_handles[index] = win;
126 win->hwndSelf = handle;
127 win->dwMagic = WND_MAGIC;
133 /***********************************************************************
136 * Free a window handle.
138 static WND *free_window_handle( HWND hwnd )
141 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
143 if (index >= NB_USER_HANDLES) return NULL;
145 if ((ptr = user_handles[index]))
147 SERVER_START_REQ( destroy_window )
150 if (!wine_server_call_err( req ))
151 user_handles[index] = NULL;
158 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
163 /*******************************************************************
164 * list_window_children
166 * Build an array of the children of a given window. The array must be
167 * freed with HeapFree. Returns NULL when no windows are found.
169 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
178 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
180 SERVER_START_REQ( get_window_children )
185 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
186 if (!wine_server_call( req )) count = reply->count;
189 if (count && count < size)
194 HeapFree( GetProcessHeap(), 0, list );
196 size = count + 1; /* restart with a large enough buffer */
202 /*******************************************************************
205 static void send_parent_notify( HWND hwnd, UINT msg )
207 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
208 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
209 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
210 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
214 /*******************************************************************
215 * get_server_window_text
217 * Retrieve the window text from the server.
219 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
223 SERVER_START_REQ( get_window_text )
226 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
227 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
230 text[len / sizeof(WCHAR)] = 0;
234 /***********************************************************************
237 * Return a pointer to the WND structure if local to the process,
238 * or WND_OTHER_PROCESS if handle may be valid in other process.
239 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
241 WND *WIN_GetPtr( HWND hwnd )
244 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
246 if (index >= NB_USER_HANDLES) return NULL;
249 if ((ptr = user_handles[index]))
251 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
255 else ptr = WND_OTHER_PROCESS;
261 /***********************************************************************
262 * WIN_IsCurrentProcess
264 * Check whether a given window belongs to the current process (and return the full handle).
266 HWND WIN_IsCurrentProcess( HWND hwnd )
271 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
273 WIN_ReleasePtr( ptr );
278 /***********************************************************************
279 * WIN_IsCurrentThread
281 * Check whether a given window belongs to the current thread (and return the full handle).
283 HWND WIN_IsCurrentThread( HWND hwnd )
288 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
290 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
291 WIN_ReleasePtr( ptr );
297 /***********************************************************************
300 * Convert a 16-bit window handle to a full 32-bit handle.
302 HWND WIN_Handle32( HWND16 hwnd16 )
305 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
307 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
308 /* do sign extension for -2 and -3 */
309 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
311 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
313 if (ptr != WND_OTHER_PROCESS)
315 hwnd = ptr->hwndSelf;
316 WIN_ReleasePtr( ptr );
318 else /* may belong to another process */
320 SERVER_START_REQ( get_window_info )
323 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
331 /***********************************************************************
334 * Return a pointer to the WND structure corresponding to a HWND.
336 WND * WIN_FindWndPtr( HWND hwnd )
340 if (!hwnd) return NULL;
342 if ((ptr = WIN_GetPtr( hwnd )))
344 if (ptr != WND_OTHER_PROCESS)
346 /* increment destruction monitoring */
350 if (IsWindow( hwnd )) /* check other processes */
352 ERR( "window %04x belongs to other process\n", hwnd );
353 /* DbgBreakPoint(); */
356 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
361 /***********************************************************************
364 * Release the pointer to the WND structure.
366 void WIN_ReleaseWndPtr(WND *wndPtr)
370 /* Decrement destruction monitoring value */
372 /* Check if it's time to release the memory */
373 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
376 free_window_handle( wndPtr->hwndSelf );
378 else if(wndPtr->irefCount < 0)
380 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
381 ERR("forgot a Lock on %p somewhere\n",wndPtr);
383 /* unlock all WND structures for thread safeness */
388 /***********************************************************************
391 * Remove a window from the siblings linked list.
393 void WIN_UnlinkWindow( HWND hwnd )
395 WIN_LinkWindow( hwnd, 0, 0 );
399 /***********************************************************************
402 * Insert a window into the siblings linked list.
403 * The window is inserted after the specified window, which can also
404 * be specified as HWND_TOP or HWND_BOTTOM.
405 * If parent is 0, window is unlinked from the tree.
407 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
409 WND *wndPtr = WIN_GetPtr( hwnd );
412 if (wndPtr == WND_OTHER_PROCESS)
414 if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
418 SERVER_START_REQ( link_window )
421 req->parent = parent;
422 req->previous = hwndInsertAfter;
423 if (!wine_server_call( req ))
425 if (reply->full_parent) wndPtr->parent = reply->full_parent;
430 WIN_ReleasePtr( wndPtr );
434 /***********************************************************************
437 * Change the owner of a window.
439 HWND WIN_SetOwner( HWND hwnd, HWND owner )
441 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 ))
456 win->owner = reply->full_owner;
457 ret = reply->prev_owner;
461 WIN_ReleasePtr( win );
466 /***********************************************************************
469 * Change the style of a window.
471 LONG WIN_SetStyle( HWND hwnd, LONG style )
475 WND *win = WIN_GetPtr( hwnd );
478 if (win == WND_OTHER_PROCESS)
481 ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
484 if (style == win->dwStyle)
486 WIN_ReleasePtr( win );
489 SERVER_START_REQ( set_window_info )
492 req->flags = SET_WIN_STYLE;
494 if ((ok = !wine_server_call( req )))
496 ret = reply->old_style;
497 win->dwStyle = style;
501 WIN_ReleasePtr( win );
502 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
507 /***********************************************************************
510 * Change the extended style of a window.
512 LONG WIN_SetExStyle( HWND hwnd, LONG style )
515 WND *win = WIN_GetPtr( hwnd );
518 if (win == WND_OTHER_PROCESS)
521 ERR( "cannot set exstyle %lx on other process window %x\n", style, hwnd );
524 if (style == win->dwExStyle)
526 WIN_ReleasePtr( win );
529 SERVER_START_REQ( set_window_info )
532 req->flags = SET_WIN_EXSTYLE;
533 req->ex_style = style;
534 if (!wine_server_call( req ))
536 ret = reply->old_ex_style;
537 win->dwExStyle = style;
541 WIN_ReleasePtr( win );
546 /***********************************************************************
549 * Set the window and client rectangles.
551 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
553 WND *win = WIN_GetPtr( hwnd );
557 if (win == WND_OTHER_PROCESS)
559 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %x\n", hwnd );
562 SERVER_START_REQ( set_window_rectangles )
565 req->window.left = rectWindow->left;
566 req->window.top = rectWindow->top;
567 req->window.right = rectWindow->right;
568 req->window.bottom = rectWindow->bottom;
569 req->client.left = rectClient->left;
570 req->client.top = rectClient->top;
571 req->client.right = rectClient->right;
572 req->client.bottom = rectClient->bottom;
573 ret = !wine_server_call( req );
578 win->rectWindow = *rectWindow;
579 win->rectClient = *rectClient;
581 TRACE( "win %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
582 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
583 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
585 WIN_ReleasePtr( win );
589 /***********************************************************************
592 * Get the window and client rectangles.
594 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
596 WND *win = WIN_GetPtr( hwnd );
599 if (!win) return FALSE;
600 if (win == WND_OTHER_PROCESS)
602 SERVER_START_REQ( get_window_rectangles )
605 if ((ret = !wine_server_call( req )))
609 rectWindow->left = reply->window.left;
610 rectWindow->top = reply->window.top;
611 rectWindow->right = reply->window.right;
612 rectWindow->bottom = reply->window.bottom;
616 rectClient->left = reply->client.left;
617 rectClient->top = reply->client.top;
618 rectClient->right = reply->client.right;
619 rectClient->bottom = reply->client.bottom;
627 if (rectWindow) *rectWindow = win->rectWindow;
628 if (rectClient) *rectClient = win->rectClient;
629 WIN_ReleasePtr( win );
635 /***********************************************************************
638 * Destroy storage associated to a window. "Internals" p.358
640 LRESULT WIN_DestroyWindow( HWND hwnd )
645 TRACE("%04x\n", hwnd );
647 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
649 ERR( "window doesn't belong to current thread\n" );
653 /* free child windows */
654 if ((list = WIN_ListChildren( hwnd )))
657 for (i = 0; list[i]; i++)
659 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
660 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
662 HeapFree( GetProcessHeap(), 0, list );
666 * Clear the update region to make sure no WM_PAINT messages will be
667 * generated for this window while processing the WM_NCDESTROY.
669 RedrawWindow( hwnd, NULL, 0,
670 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
673 * Send the WM_NCDESTROY to the window being destroyed.
675 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
677 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
679 WINPOS_CheckInternalPos( hwnd );
680 if( hwnd == GetCapture()) ReleaseCapture();
682 /* free resources associated with the window */
684 TIMER_RemoveWindowTimers( hwnd );
686 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
687 wndPtr->hmemTaskQ = 0;
689 if (!(wndPtr->dwStyle & WS_CHILD))
691 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
692 if (menu) DestroyMenu( menu );
694 if (wndPtr->hSysMenu)
696 DestroyMenu( wndPtr->hSysMenu );
697 wndPtr->hSysMenu = 0;
699 USER_Driver.pDestroyWindow( hwnd );
700 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
701 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
702 CLASS_RemoveWindow( wndPtr->class );
703 wndPtr->class = NULL;
704 wndPtr->dwMagic = 0; /* Mark it as invalid */
705 WIN_ReleaseWndPtr( wndPtr );
709 /***********************************************************************
710 * WIN_DestroyThreadWindows
712 * Destroy all children of 'wnd' owned by the current thread.
713 * Return TRUE if something was done.
715 void WIN_DestroyThreadWindows( HWND hwnd )
720 if (!(list = WIN_ListChildren( hwnd ))) return;
721 for (i = 0; list[i]; i++)
723 if (WIN_IsCurrentThread( list[i] ))
724 DestroyWindow( list[i] );
726 WIN_DestroyThreadWindows( list[i] );
728 HeapFree( GetProcessHeap(), 0, list );
731 /***********************************************************************
732 * WIN_CreateDesktopWindow
734 * Create the desktop window.
736 BOOL WIN_CreateDesktopWindow(void)
738 struct tagCLASS *class;
747 TRACE("Creating desktop window\n");
749 if (!WINPOS_CreateInternalPosAtom() ||
750 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
751 &wndExtra, &winproc, &clsStyle, &dce )))
754 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
755 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
756 if (!pWndDesktop) return FALSE;
757 hwndDesktop = pWndDesktop->hwndSelf;
759 pWndDesktop->tid = 0; /* nobody owns the desktop */
760 pWndDesktop->parent = 0;
761 pWndDesktop->owner = 0;
762 pWndDesktop->class = class;
763 pWndDesktop->text = NULL;
764 pWndDesktop->hmemTaskQ = 0;
765 pWndDesktop->hrgnUpdate = 0;
766 pWndDesktop->clsStyle = clsStyle;
767 pWndDesktop->dce = NULL;
768 pWndDesktop->pVScroll = NULL;
769 pWndDesktop->pHScroll = NULL;
770 pWndDesktop->helpContext = 0;
771 pWndDesktop->flags = 0;
772 pWndDesktop->hSysMenu = 0;
773 pWndDesktop->winproc = winproc;
774 pWndDesktop->cbWndExtra = wndExtra;
776 cs.lpCreateParams = NULL;
782 cs.cx = GetSystemMetrics( SM_CXSCREEN );
783 cs.cy = GetSystemMetrics( SM_CYSCREEN );
784 cs.style = pWndDesktop->dwStyle;
785 cs.dwExStyle = pWndDesktop->dwExStyle;
787 cs.lpszClass = DESKTOP_CLASS_ATOM;
789 SetRect( &rect, 0, 0, cs.cx, cs.cy );
790 WIN_SetRectangles( hwndDesktop, &rect, &rect );
792 SERVER_START_REQ( set_window_info )
794 req->handle = hwndDesktop;
795 req->flags = 0; /* don't set anything, just retrieve */
796 wine_server_call( req );
797 pWndDesktop->dwStyle = reply->old_style;
798 pWndDesktop->dwExStyle = reply->old_ex_style;
799 pWndDesktop->hInstance = (ULONG_PTR)reply->old_instance;
800 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
801 pWndDesktop->wIDmenu = reply->old_id;
805 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
807 WIN_ReleaseWndPtr( pWndDesktop );
811 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
812 WIN_ReleaseWndPtr( pWndDesktop );
817 /***********************************************************************
820 * Fix the coordinates - Helper for WIN_CreateWindowEx.
821 * returns default show mode in sw.
822 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
824 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
826 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
827 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
829 if (cs->style & (WS_CHILD | WS_POPUP))
831 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
832 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
834 else /* overlapped window */
838 GetStartupInfoA( &info );
840 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
842 /* Never believe Microsoft's documentation... CreateWindowEx doc says
843 * that if an overlapped window is created with WS_VISIBLE style bit
844 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
845 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
848 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
849 * 2) it does not ignore the y parameter as the docs claim; instead, it
850 * uses it as second parameter to ShowWindow() unless y is either
851 * CW_USEDEFAULT or CW_USEDEFAULT16.
853 * The fact that we didn't do 2) caused bogus windows pop up when wine
854 * was running apps that were using this obscure feature. Example -
855 * calc.exe that comes with Win98 (only Win98, it's different from
856 * the one that comes with Win95 and NT)
858 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
859 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
860 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
863 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
865 if (info.dwFlags & STARTF_USESIZE)
867 cs->cx = info.dwXSize;
868 cs->cy = info.dwYSize;
870 else /* if no other hint from the app, pick 3/4 of the screen real estate */
873 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
874 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
875 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
882 /* neither x nor cx are default. Check the y values .
883 * In the trace we see Outlook and Outlook Express using
884 * cy set to CW_USEDEFAULT when opening the address book.
886 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
888 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
889 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
890 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
895 /***********************************************************************
898 static void dump_window_styles( DWORD style, DWORD exstyle )
901 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
902 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
903 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
904 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
905 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
906 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
907 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
908 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
909 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
912 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
913 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
915 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
916 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
917 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
918 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
919 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
920 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
921 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
922 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
924 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
925 #define DUMPED_STYLES \
945 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
950 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
951 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
952 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
953 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
954 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
955 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
956 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
957 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
958 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
959 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
960 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
961 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
962 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
963 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
964 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
965 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
966 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
967 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
969 #define DUMPED_EX_STYLES \
970 (WS_EX_DLGMODALFRAME | \
972 WS_EX_NOPARENTNOTIFY | \
974 WS_EX_ACCEPTFILES | \
975 WS_EX_TRANSPARENT | \
980 WS_EX_CONTEXTHELP | \
983 WS_EX_LEFTSCROLLBAR | \
984 WS_EX_CONTROLPARENT | \
989 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
991 #undef DUMPED_EX_STYLES
995 /***********************************************************************
998 * Implementation of CreateWindowEx().
1000 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
1001 WINDOWPROCTYPE type )
1004 struct tagCLASS *classPtr;
1006 HWND hwnd, parent, owner;
1011 BOOL unicode = (type == WIN_PROC_32W);
1013 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
1014 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1015 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1016 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1017 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1019 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1021 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1022 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1024 /* Find the parent window */
1026 parent = GetDesktopWindow();
1029 if (cs->hwndParent == HWND_MESSAGE)
1031 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1032 * message window (style: WS_POPUP|WS_DISABLED)
1034 FIXME("Parent is HWND_MESSAGE\n");
1036 else if (cs->hwndParent)
1038 /* Make sure parent is valid */
1039 if (!IsWindow( cs->hwndParent ))
1041 WARN("Bad parent %04x\n", cs->hwndParent );
1044 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1045 parent = WIN_GetFullHandle(cs->hwndParent);
1047 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1049 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1051 WARN("No parent for child window\n" );
1052 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1055 /* Find the window class */
1056 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1057 &wndExtra, &winproc, &clsStyle, &dce )))
1059 WARN("Bad class '%s'\n", cs->lpszClass );
1063 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1065 /* Correct the window style - stage 1
1067 * These are patches that appear to affect both the style loaded into the
1068 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1070 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1071 * why does the user get to set it?
1074 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1075 * tested for WS_POPUP
1077 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1078 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1079 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1080 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1082 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1084 /* Create the window structure */
1086 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1087 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1089 TRACE("out of memory\n" );
1092 hwnd = wndPtr->hwndSelf;
1094 /* Fill the window structure */
1096 wndPtr->tid = GetCurrentThreadId();
1097 wndPtr->owner = owner;
1098 wndPtr->parent = parent;
1099 wndPtr->class = classPtr;
1100 wndPtr->winproc = winproc;
1101 wndPtr->hInstance = cs->hInstance;
1102 wndPtr->text = NULL;
1103 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1104 wndPtr->hrgnUpdate = 0;
1105 wndPtr->hrgnWnd = 0;
1106 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1107 wndPtr->dwExStyle = cs->dwExStyle;
1108 wndPtr->clsStyle = clsStyle;
1109 wndPtr->wIDmenu = 0;
1110 wndPtr->helpContext = 0;
1111 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1112 wndPtr->pVScroll = NULL;
1113 wndPtr->pHScroll = NULL;
1114 wndPtr->userdata = 0;
1115 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1116 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1117 wndPtr->cbWndExtra = wndExtra;
1119 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1121 /* Correct the window style - stage 2 */
1123 if (!(cs->style & WS_CHILD))
1125 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1126 if (!(cs->style & WS_POPUP))
1128 wndPtr->dwStyle |= WS_CAPTION;
1129 wndPtr->flags |= WIN_NEED_SIZE;
1132 SERVER_START_REQ( set_window_info )
1135 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1136 req->style = wndPtr->dwStyle;
1137 req->ex_style = wndPtr->dwExStyle;
1138 req->instance = (void *)wndPtr->hInstance;
1139 wine_server_call( req );
1143 /* Get class or window DC if needed */
1145 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1146 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1147 else wndPtr->dce = NULL;
1149 /* Set the window menu */
1151 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1153 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1156 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1159 if (HIWORD(cs->hInstance))
1160 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1162 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1164 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1168 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1169 WIN_ReleaseWndPtr( wndPtr );
1171 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1173 WIN_DestroyWindow( hwnd );
1177 /* Notify the parent window only */
1179 send_parent_notify( hwnd, WM_CREATE );
1180 if (!IsWindow( hwnd )) return 0;
1182 if (cs->style & WS_VISIBLE)
1184 /* in case WS_VISIBLE got set in the meantime */
1185 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1186 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1187 WIN_ReleasePtr( wndPtr );
1188 ShowWindow( hwnd, sw );
1191 /* Call WH_SHELL hook */
1193 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1194 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1196 TRACE("created window %04x\n", hwnd);
1201 /***********************************************************************
1202 * CreateWindow (USER.41)
1204 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1205 DWORD style, INT16 x, INT16 y, INT16 width,
1206 INT16 height, HWND16 parent, HMENU16 menu,
1207 HINSTANCE16 instance, LPVOID data )
1209 return CreateWindowEx16( 0, className, windowName, style,
1210 x, y, width, height, parent, menu, instance, data );
1214 /***********************************************************************
1215 * CreateWindowEx (USER.452)
1217 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1218 LPCSTR windowName, DWORD style, INT16 x,
1219 INT16 y, INT16 width, INT16 height,
1220 HWND16 parent, HMENU16 menu,
1221 HINSTANCE16 instance, LPVOID data )
1227 /* Find the class atom */
1229 if (HIWORD(className))
1231 if (!(classAtom = GlobalFindAtomA( className )))
1233 ERR( "bad class name %s\n", debugstr_a(className) );
1239 classAtom = LOWORD(className);
1240 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1242 ERR( "bad atom %x\n", classAtom);
1248 /* Fix the coordinates */
1250 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1251 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1252 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1253 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1255 /* Create the window */
1257 cs.lpCreateParams = data;
1258 cs.hInstance = (HINSTANCE)instance;
1259 cs.hMenu = (HMENU)menu;
1260 cs.hwndParent = WIN_Handle32( parent );
1262 cs.lpszName = windowName;
1263 cs.lpszClass = className;
1264 cs.dwExStyle = exStyle;
1266 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1270 /***********************************************************************
1271 * CreateWindowExA (USER32.@)
1273 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1274 LPCSTR windowName, DWORD style, INT x,
1275 INT y, INT width, INT height,
1276 HWND parent, HMENU menu,
1277 HINSTANCE instance, LPVOID data )
1284 instance=GetModuleHandleA(NULL);
1286 if(exStyle & WS_EX_MDICHILD)
1287 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1289 /* Find the class atom */
1291 if (HIWORD(className))
1293 if (!(classAtom = GlobalFindAtomA( className )))
1295 ERR( "bad class name %s\n", debugstr_a(className) );
1301 classAtom = LOWORD(className);
1302 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1304 ERR( "bad atom %x\n", classAtom);
1310 /* Create the window */
1312 cs.lpCreateParams = data;
1313 cs.hInstance = instance;
1315 cs.hwndParent = parent;
1321 cs.lpszName = windowName;
1322 cs.lpszClass = className;
1323 cs.dwExStyle = exStyle;
1325 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1329 /***********************************************************************
1330 * CreateWindowExW (USER32.@)
1332 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1333 LPCWSTR windowName, DWORD style, INT x,
1334 INT y, INT width, INT height,
1335 HWND parent, HMENU menu,
1336 HINSTANCE instance, LPVOID data )
1343 instance=GetModuleHandleA(NULL);
1345 if(exStyle & WS_EX_MDICHILD)
1346 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1348 /* Find the class atom */
1350 if (HIWORD(className))
1352 if (!(classAtom = GlobalFindAtomW( className )))
1354 ERR( "bad class name %s\n", debugstr_w(className) );
1360 classAtom = LOWORD(className);
1361 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1363 ERR( "bad atom %x\n", classAtom);
1369 /* Create the window */
1371 cs.lpCreateParams = data;
1372 cs.hInstance = instance;
1374 cs.hwndParent = parent;
1380 cs.lpszName = windowName;
1381 cs.lpszClass = className;
1382 cs.dwExStyle = exStyle;
1384 /* Note: we rely on the fact that CREATESTRUCTA and */
1385 /* CREATESTRUCTW have the same layout. */
1386 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1390 /***********************************************************************
1391 * WIN_SendDestroyMsg
1393 static void WIN_SendDestroyMsg( HWND hwnd )
1395 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1396 if (USER_Driver.pResetSelectionOwner)
1397 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1400 * Send the WM_DESTROY to the window.
1402 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1405 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1406 * make sure that the window still exists when we come back.
1413 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1415 /* start from the end (FIXME: is this needed?) */
1416 for (i = 0; pWndArray[i]; i++) ;
1420 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1422 HeapFree( GetProcessHeap(), 0, pWndArray );
1425 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1429 /***********************************************************************
1430 * DestroyWindow (USER32.@)
1432 BOOL WINAPI DestroyWindow( HWND hwnd )
1437 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1439 SetLastError( ERROR_ACCESS_DENIED );
1443 TRACE("(%04x)\n", hwnd);
1445 /* Look whether the focus is within the tree of windows we will
1449 if (h == hwnd || IsChild( hwnd, h ))
1451 HWND parent = GetAncestor( hwnd, GA_PARENT );
1452 if (parent == GetDesktopWindow()) parent = 0;
1458 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1460 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1464 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1465 send_parent_notify( hwnd, WM_DESTROY );
1467 else if (!GetWindow( hwnd, GW_OWNER ))
1469 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1470 /* FIXME: clean up palette - see "Internals" p.352 */
1473 if (!IsWindow(hwnd)) return TRUE;
1475 if (USER_Driver.pResetSelectionOwner)
1476 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1478 /* Hide the window */
1480 if (!ShowWindow( hwnd, SW_HIDE ))
1482 if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1484 if (!IsWindow(hwnd)) return TRUE;
1486 /* Recursively destroy owned windows */
1493 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1496 for (i = 0; list[i]; i++)
1498 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1499 if (WIN_IsCurrentThread( list[i] ))
1501 DestroyWindow( list[i] );
1505 WIN_SetOwner( list[i], 0 );
1507 HeapFree( GetProcessHeap(), 0, list );
1509 if (!got_one) break;
1513 /* Send destroy messages */
1515 WIN_SendDestroyMsg( hwnd );
1516 if (!IsWindow( hwnd )) return TRUE;
1518 /* Unlink now so we won't bother with the children later on */
1520 WIN_UnlinkWindow( hwnd );
1522 /* Destroy the window storage */
1524 WIN_DestroyWindow( hwnd );
1529 /***********************************************************************
1530 * CloseWindow (USER32.@)
1532 BOOL WINAPI CloseWindow( HWND hwnd )
1534 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1535 ShowWindow( hwnd, SW_MINIMIZE );
1540 /***********************************************************************
1541 * OpenIcon (USER32.@)
1543 BOOL WINAPI OpenIcon( HWND hwnd )
1545 if (!IsIconic( hwnd )) return FALSE;
1546 ShowWindow( hwnd, SW_SHOWNORMAL );
1551 /***********************************************************************
1554 * Implementation of FindWindow() and FindWindowEx().
1556 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1561 WCHAR *buffer = NULL;
1563 if (!parent) parent = GetDesktopWindow();
1566 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1567 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1570 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1574 child = WIN_GetFullHandle( child );
1575 while (list[i] && list[i] != child) i++;
1576 if (!list[i]) goto done;
1577 i++; /* start from next window */
1584 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1591 if (list) HeapFree( GetProcessHeap(), 0, list );
1592 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1598 /***********************************************************************
1599 * FindWindowA (USER32.@)
1601 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1603 HWND ret = FindWindowExA( 0, 0, className, title );
1604 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1609 /***********************************************************************
1610 * FindWindowExA (USER32.@)
1612 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1613 LPCSTR className, LPCSTR title )
1622 /* If the atom doesn't exist, then no class */
1623 /* with this name exists either. */
1624 if (!(atom = GlobalFindAtomA( className )))
1626 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1630 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1632 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1633 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1634 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1635 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1636 HeapFree( GetProcessHeap(), 0, buffer );
1641 /***********************************************************************
1642 * FindWindowExW (USER32.@)
1644 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1645 LPCWSTR className, LPCWSTR title )
1651 /* If the atom doesn't exist, then no class */
1652 /* with this name exists either. */
1653 if (!(atom = GlobalFindAtomW( className )))
1655 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1659 return WIN_FindWindow( parent, child, atom, title );
1663 /***********************************************************************
1664 * FindWindowW (USER32.@)
1666 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1668 return FindWindowExW( 0, 0, className, title );
1672 /**********************************************************************
1673 * GetDesktopWindow (USER32.@)
1675 HWND WINAPI GetDesktopWindow(void)
1677 if (pWndDesktop) return pWndDesktop->hwndSelf;
1678 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" );
1684 /*******************************************************************
1685 * EnableWindow (USER32.@)
1687 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1694 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1695 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1699 TRACE("( %x, %d )\n", hwnd, enable);
1701 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1702 style = wndPtr->dwStyle;
1703 retvalue = ((style & WS_DISABLED) != 0);
1704 WIN_ReleasePtr( wndPtr );
1706 if (enable && retvalue)
1708 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1709 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1711 else if (!enable && !retvalue)
1713 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1715 WIN_SetStyle( hwnd, style | WS_DISABLED );
1717 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1718 SetFocus( 0 ); /* A disabled window can't have the focus */
1720 if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1721 ReleaseCapture(); /* A disabled window can't capture the mouse */
1723 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1729 /***********************************************************************
1730 * IsWindowEnabled (USER32.@)
1732 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1734 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1738 /***********************************************************************
1739 * IsWindowUnicode (USER32.@)
1741 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1746 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1747 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1748 WIN_ReleaseWndPtr(wndPtr);
1753 /**********************************************************************
1754 * GetWindowWord (USER32.@)
1756 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1761 WND *wndPtr = WIN_GetPtr( hwnd );
1764 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1767 if (wndPtr == WND_OTHER_PROCESS)
1769 if (IsWindow( hwnd ))
1770 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1771 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1774 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1776 WARN("Invalid offset %d\n", offset );
1777 SetLastError( ERROR_INVALID_INDEX );
1779 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1780 WIN_ReleasePtr( wndPtr );
1786 case GWL_HWNDPARENT:
1787 return GetWindowLongW( hwnd, offset );
1791 LONG ret = GetWindowLongW( hwnd, offset );
1793 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1797 WARN("Invalid offset %d\n", offset );
1803 /**********************************************************************
1804 * SetWindowWord (USER32.@)
1806 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1815 case GWL_HWNDPARENT:
1816 return SetWindowLongW( hwnd, offset, (UINT)newval );
1820 WARN("Invalid offset %d\n", offset );
1821 SetLastError( ERROR_INVALID_INDEX );
1826 wndPtr = WIN_GetPtr( hwnd );
1827 if (wndPtr == WND_OTHER_PROCESS)
1830 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1831 offset, newval, hwnd );
1836 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1840 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1842 WARN("Invalid offset %d\n", offset );
1843 WIN_ReleasePtr(wndPtr);
1844 SetLastError( ERROR_INVALID_INDEX );
1847 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1850 WIN_ReleasePtr(wndPtr);
1855 /**********************************************************************
1858 * Helper function for GetWindowLong().
1860 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1865 if (offset == GWL_HWNDPARENT)
1867 HWND parent = GetAncestor( hwnd, GA_PARENT );
1868 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1869 return (LONG)parent;
1872 if (!(wndPtr = WIN_GetPtr( hwnd )))
1874 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1878 if (wndPtr == WND_OTHER_PROCESS)
1883 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1884 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1887 if (offset == GWL_WNDPROC)
1889 SetLastError( ERROR_ACCESS_DENIED );
1892 SERVER_START_REQ( set_window_info )
1895 req->flags = 0; /* don't set anything, just retrieve */
1896 if (!wine_server_call_err( req ))
1900 case GWL_STYLE: retvalue = reply->old_style; break;
1901 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1902 case GWL_ID: retvalue = reply->old_id; break;
1903 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1904 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1906 SetLastError( ERROR_INVALID_INDEX );
1915 /* now we have a valid wndPtr */
1919 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1922 * Some programs try to access last element from 16 bit
1923 * code using illegal offset value. Hopefully this is
1924 * what those programs really expect.
1926 if (type == WIN_PROC_16 &&
1927 wndPtr->cbWndExtra >= 4 &&
1928 offset == wndPtr->cbWndExtra - sizeof(WORD))
1930 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1932 ERR( "- replaced invalid offset %d with %d\n",
1935 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1936 WIN_ReleasePtr( wndPtr );
1939 WARN("Invalid offset %d\n", offset );
1940 WIN_ReleasePtr( wndPtr );
1941 SetLastError( ERROR_INVALID_INDEX );
1944 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1945 /* Special case for dialog window procedure */
1946 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1947 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1948 WIN_ReleasePtr( wndPtr );
1954 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1955 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1956 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1957 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1958 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1959 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1961 WARN("Unknown offset %d\n", offset );
1962 SetLastError( ERROR_INVALID_INDEX );
1965 WIN_ReleasePtr(wndPtr);
1970 /**********************************************************************
1973 * Helper function for SetWindowLong().
1975 * 0 is the failure code. However, in the case of failure SetLastError
1976 * must be set to distinguish between a 0 return value and a failure.
1978 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1979 WINDOWPROCTYPE type )
1984 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1986 if (!WIN_IsCurrentProcess( hwnd ))
1988 if (offset == GWL_WNDPROC)
1990 SetLastError( ERROR_ACCESS_DENIED );
1993 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1996 wndPtr = WIN_GetPtr( hwnd );
1997 if (wndPtr->hwndSelf == GetDesktopWindow())
1999 /* can't change anything on the desktop window */
2000 WIN_ReleasePtr( wndPtr );
2001 SetLastError( ERROR_ACCESS_DENIED );
2007 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
2008 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
2010 WARN("Invalid offset %d\n", offset );
2011 WIN_ReleasePtr( wndPtr );
2012 SetLastError( ERROR_INVALID_INDEX );
2015 /* Special case for dialog window procedure */
2016 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2018 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
2019 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
2020 type, WIN_PROC_WINDOW );
2021 WIN_ReleasePtr( wndPtr );
2026 WIN_ReleasePtr( wndPtr );
2033 /* first some special cases */
2038 style.styleOld = wndPtr->dwStyle;
2039 style.styleNew = newval;
2040 WIN_ReleasePtr( wndPtr );
2041 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2042 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2043 newval = style.styleNew;
2045 case GWL_HWNDPARENT:
2046 if (wndPtr->parent == GetDesktopWindow())
2048 WIN_ReleasePtr( wndPtr );
2049 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2053 WIN_ReleasePtr( wndPtr );
2054 return (LONG)SetParent( hwnd, (HWND)newval );
2057 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2058 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2059 type, WIN_PROC_WINDOW );
2060 WIN_ReleasePtr( wndPtr );
2067 WIN_ReleasePtr( wndPtr );
2068 WARN("Invalid offset %d\n", offset );
2069 SetLastError( ERROR_INVALID_INDEX );
2073 SERVER_START_REQ( set_window_info )
2079 req->flags = SET_WIN_STYLE;
2080 req->style = newval;
2083 req->flags = SET_WIN_EXSTYLE;
2084 req->ex_style = newval;
2087 req->flags = SET_WIN_ID;
2091 req->flags = SET_WIN_INSTANCE;
2092 req->instance = (void *)newval;
2095 req->flags = SET_WIN_USERDATA;
2096 req->user_data = (void *)newval;
2099 if ((ok = !wine_server_call_err( req )))
2104 wndPtr->dwStyle = newval;
2105 retval = reply->old_style;
2108 wndPtr->dwExStyle = newval;
2109 retval = reply->old_ex_style;
2112 wndPtr->wIDmenu = newval;
2113 retval = reply->old_id;
2116 wndPtr->hInstance = newval;
2117 retval = (HINSTANCE)reply->old_instance;
2120 wndPtr->userdata = newval;
2121 retval = (ULONG_PTR)reply->old_user_data;
2127 WIN_ReleasePtr( wndPtr );
2131 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2132 USER_Driver.pSetWindowStyle( hwnd, retval );
2134 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2135 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2142 /**********************************************************************
2143 * GetWindowLong (USER.135)
2145 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2147 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2151 /**********************************************************************
2152 * GetWindowLongA (USER32.@)
2154 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2156 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2160 /**********************************************************************
2161 * GetWindowLongW (USER32.@)
2163 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2165 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2169 /**********************************************************************
2170 * SetWindowLong (USER.136)
2172 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2174 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2178 /**********************************************************************
2179 * SetWindowLongA (USER32.@)
2181 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2183 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2187 /**********************************************************************
2188 * SetWindowLongW (USER32.@) Set window attribute
2190 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2191 * value in a window's extra memory.
2193 * The _hwnd_ parameter specifies the window. is the handle to a
2194 * window that has extra memory. The _newval_ parameter contains the
2195 * new attribute or extra memory value. If positive, the _offset_
2196 * parameter is the byte-addressed location in the window's extra
2197 * memory to set. If negative, _offset_ specifies the window
2198 * attribute to set, and should be one of the following values:
2200 * GWL_EXSTYLE The window's extended window style
2202 * GWL_STYLE The window's window style.
2204 * GWL_WNDPROC Pointer to the window's window procedure.
2206 * GWL_HINSTANCE The window's pplication instance handle.
2208 * GWL_ID The window's identifier.
2210 * GWL_USERDATA The window's user-specified data.
2212 * If the window is a dialog box, the _offset_ parameter can be one of
2213 * the following values:
2215 * DWL_DLGPROC The address of the window's dialog box procedure.
2217 * DWL_MSGRESULT The return value of a message
2218 * that the dialog box procedure processed.
2220 * DWL_USER Application specific information.
2224 * If successful, returns the previous value located at _offset_. Otherwise,
2229 * Extra memory for a window class is specified by a nonzero cbWndExtra
2230 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2231 * time of class creation.
2233 * Using GWL_WNDPROC to set a new window procedure effectively creates
2234 * a window subclass. Use CallWindowProc() in the new windows procedure
2235 * to pass messages to the superclass's window procedure.
2237 * The user data is reserved for use by the application which created
2240 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2241 * instead, call the EnableWindow() function to change the window's
2244 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2245 * SetParent() instead.
2248 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2249 * it sends WM_STYLECHANGING before changing the settings
2250 * and WM_STYLECHANGED afterwards.
2251 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2253 LONG WINAPI SetWindowLongW(
2254 HWND hwnd, /* [in] window to alter */
2255 INT offset, /* [in] offset, in bytes, of location to alter */
2256 LONG newval /* [in] new value of location */
2258 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2262 /*******************************************************************
2263 * GetWindowTextA (USER32.@)
2265 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2269 if (WIN_IsCurrentProcess( hwnd ))
2270 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2272 /* when window belongs to other process, don't send a message */
2273 if (nMaxCount <= 0) return 0;
2274 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2275 get_server_window_text( hwnd, buffer, nMaxCount );
2276 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2277 lpString[nMaxCount-1] = 0;
2278 HeapFree( GetProcessHeap(), 0, buffer );
2279 return strlen(lpString);
2283 /*******************************************************************
2284 * InternalGetWindowText (USER32.@)
2286 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2290 if (nMaxCount <= 0) return 0;
2291 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2292 if (win != WND_OTHER_PROCESS)
2294 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2295 else lpString[0] = 0;
2296 WIN_ReleasePtr( win );
2300 get_server_window_text( hwnd, lpString, nMaxCount );
2302 return strlenW(lpString);
2306 /*******************************************************************
2307 * GetWindowTextW (USER32.@)
2309 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2311 if (WIN_IsCurrentProcess( hwnd ))
2312 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2314 /* when window belongs to other process, don't send a message */
2315 if (nMaxCount <= 0) return 0;
2316 get_server_window_text( hwnd, lpString, nMaxCount );
2317 return strlenW(lpString);
2321 /*******************************************************************
2322 * SetWindowText (USER32.@)
2323 * SetWindowTextA (USER32.@)
2325 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2327 if (!WIN_IsCurrentProcess( hwnd ))
2329 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2330 SetLastError( ERROR_ACCESS_DENIED );
2333 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2337 /*******************************************************************
2338 * SetWindowTextW (USER32.@)
2340 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2342 if (!WIN_IsCurrentProcess( hwnd ))
2344 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2345 SetLastError( ERROR_ACCESS_DENIED );
2348 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2352 /*******************************************************************
2353 * GetWindowTextLengthA (USER32.@)
2355 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2357 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2360 /*******************************************************************
2361 * GetWindowTextLengthW (USER32.@)
2363 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2365 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2369 /*******************************************************************
2370 * IsWindow (USER32.@)
2372 BOOL WINAPI IsWindow( HWND hwnd )
2377 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2379 if (ptr != WND_OTHER_PROCESS)
2381 WIN_ReleasePtr( ptr );
2385 /* check other processes */
2386 SERVER_START_REQ( get_window_info )
2389 ret = !wine_server_call_err( req );
2396 /***********************************************************************
2397 * GetWindowThreadProcessId (USER32.@)
2399 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2404 if (!(ptr = WIN_GetPtr( hwnd )))
2406 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2410 if (ptr != WND_OTHER_PROCESS)
2412 /* got a valid window */
2414 if (process) *process = GetCurrentProcessId();
2415 WIN_ReleasePtr( ptr );
2419 /* check other processes */
2420 SERVER_START_REQ( get_window_info )
2423 if (!wine_server_call_err( req ))
2425 tid = (DWORD)reply->tid;
2426 if (process) *process = (DWORD)reply->pid;
2434 /*****************************************************************
2435 * GetParent (USER32.@)
2437 HWND WINAPI GetParent( HWND hwnd )
2442 if (!(wndPtr = WIN_GetPtr( hwnd )))
2444 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2447 if (wndPtr == WND_OTHER_PROCESS)
2449 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2450 if (style & (WS_POPUP | WS_CHILD))
2452 SERVER_START_REQ( get_window_tree )
2455 if (!wine_server_call_err( req ))
2457 if (style & WS_POPUP) retvalue = reply->owner;
2458 else if (style & WS_CHILD) retvalue = reply->parent;
2466 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2467 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2468 WIN_ReleasePtr( wndPtr );
2474 /*****************************************************************
2475 * GetAncestor (USER32.@)
2477 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2480 HWND *list, ret = 0;
2485 if (!(win = WIN_GetPtr( hwnd )))
2487 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2490 if (win != WND_OTHER_PROCESS)
2493 WIN_ReleasePtr( win );
2495 else /* need to query the server */
2497 SERVER_START_REQ( get_window_tree )
2500 if (!wine_server_call_err( req )) ret = reply->parent;
2507 if (!(list = WIN_ListParents( hwnd ))) return 0;
2509 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2513 while (list[count]) count++;
2514 ret = list[count - 2]; /* get the one before the desktop */
2516 HeapFree( GetProcessHeap(), 0, list );
2520 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2523 HWND parent = GetParent( ret );
2533 /*****************************************************************
2534 * SetParent (USER32.@)
2536 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2539 HWND retvalue, full_handle;
2542 if (!parent) parent = GetDesktopWindow();
2543 else parent = WIN_GetFullHandle( parent );
2545 if (!IsWindow( parent ))
2547 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2551 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2552 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2556 if (USER_Driver.pSetParent)
2557 return USER_Driver.pSetParent( hwnd, parent );
2559 /* Windows hides the window first, then shows it again
2560 * including the WM_SHOWWINDOW messages and all */
2561 was_visible = ShowWindow( hwnd, SW_HIDE );
2563 if (!IsWindow( parent )) return 0;
2564 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2566 retvalue = wndPtr->parent; /* old parent */
2567 if (parent != retvalue)
2569 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2571 if (parent != GetDesktopWindow()) /* a child window */
2573 if (!(wndPtr->dwStyle & WS_CHILD))
2575 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2576 if (menu) DestroyMenu( menu );
2580 WIN_ReleasePtr( wndPtr );
2582 /* SetParent additionally needs to make hwnd the topmost window
2583 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2584 WM_WINDOWPOSCHANGED notification messages.
2586 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2587 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2588 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2589 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2594 /*******************************************************************
2595 * IsChild (USER32.@)
2597 BOOL WINAPI IsChild( HWND parent, HWND child )
2599 HWND *list = WIN_ListParents( child );
2603 if (!list) return FALSE;
2604 parent = WIN_GetFullHandle( parent );
2605 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2606 ret = (list[i] != 0);
2607 HeapFree( GetProcessHeap(), 0, list );
2612 /***********************************************************************
2613 * IsWindowVisible (USER32.@)
2615 BOOL WINAPI IsWindowVisible( HWND hwnd )
2621 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2622 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2623 for (i = 0; list[i]; i++)
2624 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2626 HeapFree( GetProcessHeap(), 0, list );
2631 /***********************************************************************
2632 * WIN_IsWindowDrawable
2634 * hwnd is drawable when it is visible, all parents are not
2635 * minimized, and it is itself not minimized unless we are
2636 * trying to draw its default class icon.
2638 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2643 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2645 if (!(style & WS_VISIBLE)) return FALSE;
2646 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2648 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2649 for (i = 0; list[i]; i++)
2650 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2653 HeapFree( GetProcessHeap(), 0, list );
2658 /*******************************************************************
2659 * GetTopWindow (USER32.@)
2661 HWND WINAPI GetTopWindow( HWND hwnd )
2663 if (!hwnd) hwnd = GetDesktopWindow();
2664 return GetWindow( hwnd, GW_CHILD );
2668 /*******************************************************************
2669 * GetWindow (USER32.@)
2671 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2675 if (rel == GW_OWNER) /* this one may be available locally */
2677 WND *wndPtr = WIN_GetPtr( hwnd );
2680 SetLastError( ERROR_INVALID_HANDLE );
2683 if (wndPtr != WND_OTHER_PROCESS)
2685 retval = wndPtr->owner;
2686 WIN_ReleasePtr( wndPtr );
2689 /* else fall through to server call */
2692 SERVER_START_REQ( get_window_tree )
2695 if (!wine_server_call_err( req ))
2700 retval = reply->first_sibling;
2703 retval = reply->last_sibling;
2706 retval = reply->next_sibling;
2709 retval = reply->prev_sibling;
2712 retval = reply->owner;
2715 retval = reply->first_child;
2725 /***********************************************************************
2726 * WIN_InternalShowOwnedPopups
2728 * Internal version of ShowOwnedPopups; Wine functions should use this
2729 * to avoid interfering with application calls to ShowOwnedPopups
2730 * and to make sure the application can't prevent showing/hiding.
2732 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2736 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2740 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2742 if (!win_array) return TRUE;
2745 * Show windows Lowest first, Highest last to preserve Z-Order
2747 while (win_array[count]) count++;
2748 while (--count >= 0)
2750 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2751 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2753 if (pWnd->dwStyle & WS_POPUP)
2757 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2758 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2761 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2763 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2764 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2769 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2770 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2771 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2774 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2776 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2777 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2778 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2782 WIN_ReleaseWndPtr( pWnd );
2784 HeapFree( GetProcessHeap(), 0, win_array );
2789 /*******************************************************************
2790 * ShowOwnedPopups (USER32.@)
2792 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2796 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2798 if (!win_array) return TRUE;
2800 while (win_array[count]) count++;
2801 while (--count >= 0)
2803 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2804 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2806 if (pWnd->dwStyle & WS_POPUP)
2810 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2812 /* In Windows, ShowOwnedPopups(TRUE) generates
2813 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2814 * regardless of the state of the owner
2816 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2817 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2822 if (IsWindowVisible(pWnd->hwndSelf))
2824 /* In Windows, ShowOwnedPopups(FALSE) generates
2825 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2826 * regardless of the state of the owner
2828 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2829 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2833 WIN_ReleaseWndPtr( pWnd );
2835 HeapFree( GetProcessHeap(), 0, win_array );
2840 /*******************************************************************
2841 * GetLastActivePopup (USER32.@)
2843 HWND WINAPI GetLastActivePopup( HWND hwnd )
2847 SERVER_START_REQ( get_window_info )
2850 if (!wine_server_call_err( req )) retval = reply->last_active;
2857 /*******************************************************************
2860 * Build an array of all parents of a given window, starting with
2861 * the immediate parent. The array must be freed with HeapFree.
2862 * Returns NULL if window is a top-level window.
2864 HWND *WIN_ListParents( HWND hwnd )
2867 HWND current, *list;
2868 int pos = 0, size = 16, count = 0;
2870 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2875 if (!(win = WIN_GetPtr( current ))) goto empty;
2876 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2877 list[pos] = win->parent;
2878 WIN_ReleasePtr( win );
2879 if (!(current = list[pos]))
2881 if (!pos) goto empty;
2884 if (++pos == size - 1)
2886 /* need to grow the list */
2887 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2888 if (!new_list) goto empty;
2894 /* at least one parent belongs to another process, have to query the server */
2899 SERVER_START_REQ( get_window_parents )
2902 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2903 if (!wine_server_call( req )) count = reply->count;
2906 if (!count) goto empty;
2912 HeapFree( GetProcessHeap(), 0, list );
2914 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2918 HeapFree( GetProcessHeap(), 0, list );
2923 /*******************************************************************
2926 * Build an array of the children of a given window. The array must be
2927 * freed with HeapFree. Returns NULL when no windows are found.
2929 HWND *WIN_ListChildren( HWND hwnd )
2931 return list_window_children( hwnd, 0, 0 );
2935 /*******************************************************************
2936 * EnumWindows (USER32.@)
2938 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2944 /* We have to build a list of all windows first, to avoid */
2945 /* unpleasant side-effects, for instance if the callback */
2946 /* function changes the Z-order of the windows. */
2948 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2950 /* Now call the callback function for every window */
2952 iWndsLocks = WIN_SuspendWndsLock();
2953 for (i = 0; list[i]; i++)
2955 /* Make sure that the window still exists */
2956 if (!IsWindow( list[i] )) continue;
2957 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2959 WIN_RestoreWndsLock(iWndsLocks);
2960 HeapFree( GetProcessHeap(), 0, list );
2965 /**********************************************************************
2966 * EnumThreadWindows (USER32.@)
2968 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2973 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2976 /* Now call the callback function for every window */
2978 iWndsLocks = WIN_SuspendWndsLock();
2979 for (i = 0; list[i]; i++)
2980 if (!func( list[i], lParam )) break;
2981 WIN_RestoreWndsLock(iWndsLocks);
2982 HeapFree( GetProcessHeap(), 0, list );
2987 /**********************************************************************
2988 * WIN_EnumChildWindows
2990 * Helper function for EnumChildWindows().
2992 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2997 for ( ; *list; list++)
2999 /* Make sure that the window still exists */
3000 if (!IsWindow( *list )) continue;
3001 /* skip owned windows */
3002 if (GetWindow( *list, GW_OWNER )) continue;
3003 /* Build children list first */
3004 childList = WIN_ListChildren( *list );
3006 ret = func( *list, lParam );
3010 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3011 HeapFree( GetProcessHeap(), 0, childList );
3013 if (!ret) return FALSE;
3019 /**********************************************************************
3020 * EnumChildWindows (USER32.@)
3022 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3027 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3028 iWndsLocks = WIN_SuspendWndsLock();
3029 WIN_EnumChildWindows( list, func, lParam );
3030 WIN_RestoreWndsLock(iWndsLocks);
3031 HeapFree( GetProcessHeap(), 0, list );
3036 /*******************************************************************
3037 * AnyPopup (USER.52)
3039 BOOL16 WINAPI AnyPopup16(void)
3045 /*******************************************************************
3046 * AnyPopup (USER32.@)
3048 BOOL WINAPI AnyPopup(void)
3052 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3054 if (!list) return FALSE;
3055 for (i = 0; list[i]; i++)
3057 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3059 retvalue = (list[i] != 0);
3060 HeapFree( GetProcessHeap(), 0, list );
3065 /*******************************************************************
3066 * FlashWindow (USER32.@)
3068 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3070 WND *wndPtr = WIN_FindWndPtr(hWnd);
3072 TRACE("%04x\n", hWnd);
3074 if (!wndPtr) return FALSE;
3075 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3077 if (wndPtr->dwStyle & WS_MINIMIZE)
3079 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3081 HDC hDC = GetDC(hWnd);
3083 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3084 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3086 ReleaseDC( hWnd, hDC );
3087 wndPtr->flags |= WIN_NCACTIVATED;
3091 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3092 wndPtr->flags &= ~WIN_NCACTIVATED;
3094 WIN_ReleaseWndPtr(wndPtr);
3100 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3101 else wparam = (hWnd == GetForegroundWindow());
3103 WIN_ReleaseWndPtr(wndPtr);
3104 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3110 /*******************************************************************
3111 * GetWindowContextHelpId (USER32.@)
3113 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3116 WND *wnd = WIN_FindWndPtr( hwnd );
3118 retval = wnd->helpContext;
3119 WIN_ReleaseWndPtr(wnd);
3124 /*******************************************************************
3125 * SetWindowContextHelpId (USER32.@)
3127 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3129 WND *wnd = WIN_FindWndPtr( hwnd );
3130 if (!wnd) return FALSE;
3131 wnd->helpContext = id;
3132 WIN_ReleaseWndPtr(wnd);
3137 /*******************************************************************
3138 * DRAG_QueryUpdate16
3140 * recursively find a child that contains spDragInfo->pt point
3141 * and send WM_QUERYDROPOBJECT
3143 static BOOL16 DRAG_QueryUpdate16( HWND hQueryWnd, SEGPTR spDragInfo )
3145 BOOL16 wParam, bResult = 0;
3147 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3150 if (!ptrDragInfo) return FALSE;
3152 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3154 GetWindowRect(hQueryWnd,&tempRect);
3156 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3158 if (!IsIconic( hQueryWnd ))
3160 GetClientRect( hQueryWnd, &tempRect );
3161 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3163 if (PtInRect( &tempRect, pt))
3166 HWND *list = WIN_ListChildren( hQueryWnd );
3172 for (i = 0; list[i]; i++)
3174 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3176 GetWindowRect( list[i], &tempRect );
3177 if (PtInRect( &tempRect, pt )) break;
3182 if (IsWindowEnabled( list[i] ))
3183 bResult = DRAG_QueryUpdate16( list[i], spDragInfo );
3185 HeapFree( GetProcessHeap(), 0, list );
3187 if(bResult) return bResult;
3193 ScreenToClient16(HWND_16(hQueryWnd),&ptrDragInfo->pt);
3195 ptrDragInfo->hScope = HWND_16(hQueryWnd);
3197 bResult = SendMessage16( HWND_16(hQueryWnd), WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3199 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3205 /*******************************************************************
3206 * DragDetect (USER32.@)
3208 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3213 rect.left = pt.x - wDragWidth;
3214 rect.right = pt.x + wDragWidth;
3216 rect.top = pt.y - wDragHeight;
3217 rect.bottom = pt.y + wDragHeight;
3223 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3225 if( msg.message == WM_LBUTTONUP )
3230 if( msg.message == WM_MOUSEMOVE )
3233 tmp.x = LOWORD(msg.lParam);
3234 tmp.y = HIWORD(msg.lParam);
3235 if( !PtInRect( &rect, tmp ))
3247 /******************************************************************************
3248 * DragObject (USER.464)
3250 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3251 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3254 LPDRAGINFO16 lpDragInfo;
3256 HCURSOR hOldCursor=0, hBummer=0;
3257 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3258 HCURSOR hCurrentCursor = 0;
3259 HWND16 hCurrentWnd = 0;
3261 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3262 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3264 if( !lpDragInfo || !spDragInfo ) return 0L;
3266 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3268 GlobalFree16(hDragInfo);
3272 if(hCursor) hOldCursor = SetCursor(HCURSOR_32(hCursor));
3274 lpDragInfo->hWnd = hWnd;
3275 lpDragInfo->hScope = 0;
3276 lpDragInfo->wFlags = wObj;
3277 lpDragInfo->hList = szList; /* near pointer! */
3278 lpDragInfo->hOfStruct = hOfStruct;
3281 SetCapture(WIN_Handle32(hWnd));
3286 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3288 *(lpDragInfo+1) = *lpDragInfo;
3290 lpDragInfo->pt.x = msg.pt.x;
3291 lpDragInfo->pt.y = msg.pt.y;
3293 /* update DRAGINFO struct */
3294 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3296 if( DRAG_QueryUpdate16(WIN_Handle32(hwndScope), spDragInfo) > 0 )
3297 hCurrentCursor = HCURSOR_32(hCursor);
3300 hCurrentCursor = hBummer;
3301 lpDragInfo->hScope = 0;
3303 if( hCurrentCursor )
3304 SetCursor(hCurrentCursor);
3306 /* send WM_DRAGLOOP */
3307 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3308 (LPARAM) spDragInfo );
3309 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3310 if( hCurrentWnd != lpDragInfo->hScope )
3313 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3314 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3315 HIWORD(spDragInfo)) );
3316 hCurrentWnd = lpDragInfo->hScope;
3318 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3322 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3324 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3327 ShowCursor( FALSE );
3329 if( hCursor ) SetCursor(hOldCursor);
3331 if( hCurrentCursor != hBummer )
3332 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3333 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3336 GlobalFree16(hDragInfo);
3338 return (DWORD)(msg.lParam);
3342 /******************************************************************************
3343 * GetWindowModuleFileNameA (USER32.@)
3345 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3347 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3348 hwnd, lpszFileName, cchFileNameMax);
3352 /******************************************************************************
3353 * GetWindowModuleFileNameW (USER32.@)
3355 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3357 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3358 hwnd, lpszFileName, cchFileNameMax);
3362 /******************************************************************************
3363 * GetWindowInfo (USER32.@)
3366 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3367 * this may be because this structure changed over time. If this is the
3368 * the case, then please: FIXME.
3369 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3371 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3373 WND *wndInfo = NULL;
3374 if (!pwi) return FALSE;
3375 if (pwi->cbSize != sizeof(WINDOWINFO))
3377 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3380 wndInfo = WIN_GetPtr(hwnd);
3381 if (!wndInfo) return FALSE;
3382 if (wndInfo == WND_OTHER_PROCESS)
3384 FIXME("window belong to other process\n");
3388 pwi->rcWindow = wndInfo->rectWindow;
3389 pwi->rcClient = wndInfo->rectClient;
3390 pwi->dwStyle = wndInfo->dwStyle;
3391 pwi->dwExStyle = wndInfo->dwExStyle;
3392 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3393 /* if active WS_ACTIVECAPTION, else 0 */
3395 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3396 GetSystemMetrics(SM_CXBORDER) : 0);
3397 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3398 GetSystemMetrics(SM_CYBORDER) : 0);
3399 /* above two: I'm presuming that borders widths are the same
3400 * for each window - so long as its actually using a border.. */
3402 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3403 pwi->wCreatorVersion = GetVersion();
3404 /* Docs say this should be the version that
3405 * CREATED the window. But eh?.. Isn't that just the
3406 * version we are running.. Unless ofcourse its some wacky
3407 * RPC stuff or something */
3409 WIN_ReleasePtr(wndInfo);