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"
31 #include "wine/server.h"
32 #include "wine/unicode.h"
37 #include "cursoricon.h"
41 #include "stackframe.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(win);
45 WINE_DECLARE_DEBUG_CHANNEL(msg);
47 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
49 /**********************************************************************/
52 static WND *pWndDesktop = NULL;
54 static WORD wDragWidth = 4;
55 static WORD wDragHeight= 3;
57 static void *user_handles[NB_USER_HANDLES];
60 extern SYSLEVEL USER_SysLevel; /* FIXME */
62 /***********************************************************************
65 * Suspend the lock on WND structures.
66 * Returns the number of locks suspended
68 int WIN_SuspendWndsLock( void )
70 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
71 int count = isuspendedLocks;
74 _LeaveSysLevel( &USER_SysLevel );
76 return isuspendedLocks;
79 /***********************************************************************
82 * Restore the suspended locks on WND structures
84 void WIN_RestoreWndsLock( int ipreviousLocks )
86 while ( ipreviousLocks-- > 0 )
87 _EnterSysLevel( &USER_SysLevel );
90 /***********************************************************************
91 * create_window_handle
93 * Create a window handle with the server.
95 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
98 user_handle_t handle = 0;
100 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
102 if (!win) return NULL;
106 SERVER_START_REQ( create_window )
108 req->parent = parent;
111 if ((res = !wine_server_call_err( req ))) handle = reply->handle;
118 HeapFree( GetProcessHeap(), 0, win );
121 index = LOWORD(handle) - FIRST_USER_HANDLE;
122 assert( index < NB_USER_HANDLES );
123 user_handles[index] = win;
124 win->hwndSelf = handle;
125 win->dwMagic = WND_MAGIC;
131 /***********************************************************************
134 * Free a window handle.
136 static WND *free_window_handle( HWND hwnd )
139 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
141 if (index >= NB_USER_HANDLES) return NULL;
143 if ((ptr = user_handles[index]))
145 SERVER_START_REQ( destroy_window )
148 if (!wine_server_call_err( req ))
149 user_handles[index] = NULL;
156 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
161 /*******************************************************************
162 * list_window_children
164 * Build an array of the children of a given window. The array must be
165 * freed with HeapFree. Returns NULL when no windows are found.
167 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
176 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
178 SERVER_START_REQ( get_window_children )
183 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
184 if (!wine_server_call( req )) count = reply->count;
187 if (count && count < size)
192 HeapFree( GetProcessHeap(), 0, list );
194 size = count + 1; /* restart with a large enough buffer */
200 /*******************************************************************
203 static void send_parent_notify( HWND hwnd, UINT msg )
205 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
206 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
207 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
208 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
212 /*******************************************************************
213 * get_server_window_text
215 * Retrieve the window text from the server.
217 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
221 SERVER_START_REQ( get_window_text )
224 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
225 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
228 text[len / sizeof(WCHAR)] = 0;
232 /***********************************************************************
235 * Return a pointer to the WND structure if local to the process,
236 * or WND_OTHER_PROCESS if handle may be valid in other process.
237 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
239 WND *WIN_GetPtr( HWND hwnd )
242 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
244 if (index >= NB_USER_HANDLES) return NULL;
247 if ((ptr = user_handles[index]))
249 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
253 else ptr = WND_OTHER_PROCESS;
259 /***********************************************************************
260 * WIN_IsCurrentProcess
262 * Check whether a given window belongs to the current process (and return the full handle).
264 HWND WIN_IsCurrentProcess( HWND hwnd )
269 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
271 WIN_ReleasePtr( ptr );
276 /***********************************************************************
277 * WIN_IsCurrentThread
279 * Check whether a given window belongs to the current thread (and return the full handle).
281 HWND WIN_IsCurrentThread( HWND hwnd )
286 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
288 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
289 WIN_ReleasePtr( ptr );
295 /***********************************************************************
298 * Convert a 16-bit window handle to a full 32-bit handle.
300 HWND WIN_Handle32( HWND16 hwnd16 )
303 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
305 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
306 /* do sign extension for -2 and -3 */
307 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
309 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
311 if (ptr != WND_OTHER_PROCESS)
313 hwnd = ptr->hwndSelf;
314 WIN_ReleasePtr( ptr );
316 else /* may belong to another process */
318 SERVER_START_REQ( get_window_info )
321 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
329 /***********************************************************************
332 * Return a pointer to the WND structure corresponding to a HWND.
334 WND * WIN_FindWndPtr( HWND hwnd )
338 if (!hwnd) return NULL;
340 if ((ptr = WIN_GetPtr( hwnd )))
342 if (ptr != WND_OTHER_PROCESS)
344 /* increment destruction monitoring */
348 if (IsWindow( hwnd )) /* check other processes */
350 ERR( "window %p belongs to other process\n", hwnd );
351 /* DbgBreakPoint(); */
354 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
359 /***********************************************************************
362 * Release the pointer to the WND structure.
364 void WIN_ReleaseWndPtr(WND *wndPtr)
368 /* Decrement destruction monitoring value */
370 /* Check if it's time to release the memory */
371 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
374 free_window_handle( wndPtr->hwndSelf );
376 else if(wndPtr->irefCount < 0)
378 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
379 ERR("forgot a Lock on %p somewhere\n",wndPtr);
381 /* unlock all WND structures for thread safeness */
386 /***********************************************************************
389 * Remove a window from the siblings linked list.
391 void WIN_UnlinkWindow( HWND hwnd )
393 WIN_LinkWindow( hwnd, 0, 0 );
397 /***********************************************************************
400 * Insert a window into the siblings linked list.
401 * The window is inserted after the specified window, which can also
402 * be specified as HWND_TOP or HWND_BOTTOM.
403 * If parent is 0, window is unlinked from the tree.
405 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
407 WND *wndPtr = WIN_GetPtr( hwnd );
410 if (wndPtr == WND_OTHER_PROCESS)
412 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
416 SERVER_START_REQ( link_window )
419 req->parent = parent;
420 req->previous = hwndInsertAfter;
421 if (!wine_server_call( req ))
423 if (reply->full_parent) wndPtr->parent = reply->full_parent;
428 WIN_ReleasePtr( wndPtr );
432 /***********************************************************************
435 * Change the owner of a window.
437 HWND WIN_SetOwner( HWND hwnd, HWND owner )
439 WND *win = WIN_GetPtr( hwnd );
443 if (win == WND_OTHER_PROCESS)
445 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
448 SERVER_START_REQ( set_window_owner )
452 if (!wine_server_call( req ))
454 win->owner = reply->full_owner;
455 ret = reply->prev_owner;
459 WIN_ReleasePtr( win );
464 /***********************************************************************
467 * Change the style of a window.
469 LONG WIN_SetStyle( HWND hwnd, LONG style )
473 WND *win = WIN_GetPtr( hwnd );
476 if (win == WND_OTHER_PROCESS)
479 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
482 if (style == win->dwStyle)
484 WIN_ReleasePtr( win );
487 SERVER_START_REQ( set_window_info )
490 req->flags = SET_WIN_STYLE;
492 if ((ok = !wine_server_call( req )))
494 ret = reply->old_style;
495 win->dwStyle = style;
499 WIN_ReleasePtr( win );
500 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
505 /***********************************************************************
508 * Change the extended style of a window.
510 LONG WIN_SetExStyle( HWND hwnd, LONG style )
513 WND *win = WIN_GetPtr( hwnd );
516 if (win == WND_OTHER_PROCESS)
519 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
522 if (style == win->dwExStyle)
524 WIN_ReleasePtr( win );
527 SERVER_START_REQ( set_window_info )
530 req->flags = SET_WIN_EXSTYLE;
531 req->ex_style = style;
532 if (!wine_server_call( req ))
534 ret = reply->old_ex_style;
535 win->dwExStyle = style;
539 WIN_ReleasePtr( win );
544 /***********************************************************************
547 * Set the window and client rectangles.
549 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
551 WND *win = WIN_GetPtr( hwnd );
555 if (win == WND_OTHER_PROCESS)
557 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
560 SERVER_START_REQ( set_window_rectangles )
563 req->window.left = rectWindow->left;
564 req->window.top = rectWindow->top;
565 req->window.right = rectWindow->right;
566 req->window.bottom = rectWindow->bottom;
567 req->client.left = rectClient->left;
568 req->client.top = rectClient->top;
569 req->client.right = rectClient->right;
570 req->client.bottom = rectClient->bottom;
571 ret = !wine_server_call( req );
576 win->rectWindow = *rectWindow;
577 win->rectClient = *rectClient;
579 TRACE( "win %p window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
580 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
581 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
583 WIN_ReleasePtr( win );
587 /***********************************************************************
590 * Get the window and client rectangles.
592 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
594 WND *win = WIN_GetPtr( hwnd );
597 if (!win) return FALSE;
598 if (win == WND_OTHER_PROCESS)
600 SERVER_START_REQ( get_window_rectangles )
603 if ((ret = !wine_server_call( req )))
607 rectWindow->left = reply->window.left;
608 rectWindow->top = reply->window.top;
609 rectWindow->right = reply->window.right;
610 rectWindow->bottom = reply->window.bottom;
614 rectClient->left = reply->client.left;
615 rectClient->top = reply->client.top;
616 rectClient->right = reply->client.right;
617 rectClient->bottom = reply->client.bottom;
625 if (rectWindow) *rectWindow = win->rectWindow;
626 if (rectClient) *rectClient = win->rectClient;
627 WIN_ReleasePtr( win );
633 /***********************************************************************
636 * Destroy storage associated to a window. "Internals" p.358
638 LRESULT WIN_DestroyWindow( HWND hwnd )
643 TRACE("%p\n", hwnd );
645 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
647 ERR( "window doesn't belong to current thread\n" );
651 /* free child windows */
652 if ((list = WIN_ListChildren( hwnd )))
655 for (i = 0; list[i]; i++)
657 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
658 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
660 HeapFree( GetProcessHeap(), 0, list );
664 * Clear the update region to make sure no WM_PAINT messages will be
665 * generated for this window while processing the WM_NCDESTROY.
667 RedrawWindow( hwnd, NULL, 0,
668 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
671 * Send the WM_NCDESTROY to the window being destroyed.
673 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
675 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
677 WINPOS_CheckInternalPos( hwnd );
678 if( hwnd == GetCapture()) ReleaseCapture();
680 /* free resources associated with the window */
682 TIMER_RemoveWindowTimers( hwnd );
684 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
686 if (!(wndPtr->dwStyle & WS_CHILD))
688 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
689 if (menu) DestroyMenu( menu );
691 if (wndPtr->hSysMenu)
693 DestroyMenu( wndPtr->hSysMenu );
694 wndPtr->hSysMenu = 0;
696 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
697 USER_Driver.pDestroyWindow( hwnd );
698 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
699 CLASS_RemoveWindow( wndPtr->class );
700 wndPtr->class = NULL;
701 wndPtr->dwMagic = 0; /* Mark it as invalid */
702 WIN_ReleaseWndPtr( wndPtr );
706 /***********************************************************************
707 * WIN_DestroyThreadWindows
709 * Destroy all children of 'wnd' owned by the current thread.
710 * Return TRUE if something was done.
712 void WIN_DestroyThreadWindows( HWND hwnd )
717 if (!(list = WIN_ListChildren( hwnd ))) return;
718 for (i = 0; list[i]; i++)
720 if (WIN_IsCurrentThread( list[i] ))
721 DestroyWindow( list[i] );
723 WIN_DestroyThreadWindows( list[i] );
725 HeapFree( GetProcessHeap(), 0, list );
728 /***********************************************************************
729 * WIN_CreateDesktopWindow
731 * Create the desktop window.
733 BOOL WIN_CreateDesktopWindow(void)
735 struct tagCLASS *class;
744 TRACE("Creating desktop window\n");
746 if (!WINPOS_CreateInternalPosAtom() ||
747 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
748 &wndExtra, &winproc, &clsStyle, &dce )))
751 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
752 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
753 if (!pWndDesktop) return FALSE;
754 hwndDesktop = pWndDesktop->hwndSelf;
756 pWndDesktop->tid = 0; /* nobody owns the desktop */
757 pWndDesktop->parent = 0;
758 pWndDesktop->owner = 0;
759 pWndDesktop->class = class;
760 pWndDesktop->text = NULL;
761 pWndDesktop->hrgnUpdate = 0;
762 pWndDesktop->clsStyle = clsStyle;
763 pWndDesktop->dce = NULL;
764 pWndDesktop->pVScroll = NULL;
765 pWndDesktop->pHScroll = NULL;
766 pWndDesktop->helpContext = 0;
767 pWndDesktop->flags = 0;
768 pWndDesktop->hSysMenu = 0;
769 pWndDesktop->winproc = winproc;
770 pWndDesktop->cbWndExtra = wndExtra;
772 cs.lpCreateParams = NULL;
778 cs.cx = GetSystemMetrics( SM_CXSCREEN );
779 cs.cy = GetSystemMetrics( SM_CYSCREEN );
780 cs.style = pWndDesktop->dwStyle;
781 cs.dwExStyle = pWndDesktop->dwExStyle;
783 cs.lpszClass = DESKTOP_CLASS_ATOM;
785 SetRect( &rect, 0, 0, cs.cx, cs.cy );
786 WIN_SetRectangles( hwndDesktop, &rect, &rect );
788 SERVER_START_REQ( set_window_info )
790 req->handle = hwndDesktop;
791 req->flags = 0; /* don't set anything, just retrieve */
792 wine_server_call( req );
793 pWndDesktop->dwStyle = reply->old_style;
794 pWndDesktop->dwExStyle = reply->old_ex_style;
795 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
796 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
797 pWndDesktop->wIDmenu = reply->old_id;
801 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
803 WIN_ReleaseWndPtr( pWndDesktop );
807 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
808 WIN_ReleaseWndPtr( pWndDesktop );
813 /***********************************************************************
816 * Fix the coordinates - Helper for WIN_CreateWindowEx.
817 * returns default show mode in sw.
818 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
820 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
822 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
823 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
825 if (cs->style & (WS_CHILD | WS_POPUP))
827 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
828 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
830 else /* overlapped window */
834 GetStartupInfoA( &info );
836 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
838 /* Never believe Microsoft's documentation... CreateWindowEx doc says
839 * that if an overlapped window is created with WS_VISIBLE style bit
840 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
841 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
844 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
845 * 2) it does not ignore the y parameter as the docs claim; instead, it
846 * uses it as second parameter to ShowWindow() unless y is either
847 * CW_USEDEFAULT or CW_USEDEFAULT16.
849 * The fact that we didn't do 2) caused bogus windows pop up when wine
850 * was running apps that were using this obscure feature. Example -
851 * calc.exe that comes with Win98 (only Win98, it's different from
852 * the one that comes with Win95 and NT)
854 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
855 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
856 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
859 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
861 if (info.dwFlags & STARTF_USESIZE)
863 cs->cx = info.dwXSize;
864 cs->cy = info.dwYSize;
866 else /* if no other hint from the app, pick 3/4 of the screen real estate */
869 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
870 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
871 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
878 /* neither x nor cx are default. Check the y values .
879 * In the trace we see Outlook and Outlook Express using
880 * cy set to CW_USEDEFAULT when opening the address book.
882 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
884 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
885 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
886 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
891 /***********************************************************************
894 static void dump_window_styles( DWORD style, DWORD exstyle )
897 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
898 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
899 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
900 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
901 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
902 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
903 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
904 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
905 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
908 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
909 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
911 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
912 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
913 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
914 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
915 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
916 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
917 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
918 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
920 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
921 #define DUMPED_STYLES \
941 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
946 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
947 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
948 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
949 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
950 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
951 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
952 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
953 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
954 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
955 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
956 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
957 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
958 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
959 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
960 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
961 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
962 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
963 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
965 #define DUMPED_EX_STYLES \
966 (WS_EX_DLGMODALFRAME | \
968 WS_EX_NOPARENTNOTIFY | \
970 WS_EX_ACCEPTFILES | \
971 WS_EX_TRANSPARENT | \
976 WS_EX_CONTEXTHELP | \
979 WS_EX_LEFTSCROLLBAR | \
980 WS_EX_CONTROLPARENT | \
985 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
987 #undef DUMPED_EX_STYLES
991 /***********************************************************************
994 * Implementation of CreateWindowEx().
996 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
997 WINDOWPROCTYPE type )
1000 struct tagCLASS *classPtr;
1002 HWND hwnd, parent, owner;
1007 BOOL unicode = (type == WIN_PROC_32W);
1009 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1010 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1011 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1012 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1013 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1015 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1017 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1018 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1020 /* Find the parent window */
1022 parent = GetDesktopWindow();
1025 if (cs->hwndParent == HWND_MESSAGE)
1027 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1028 * message window (style: WS_POPUP|WS_DISABLED)
1030 FIXME("Parent is HWND_MESSAGE\n");
1032 else if (cs->hwndParent)
1034 /* Make sure parent is valid */
1035 if (!IsWindow( cs->hwndParent ))
1037 WARN("Bad parent %p\n", cs->hwndParent );
1040 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1041 parent = WIN_GetFullHandle(cs->hwndParent);
1043 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1045 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1047 WARN("No parent for child window\n" );
1048 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1051 /* Find the window class */
1052 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1053 &wndExtra, &winproc, &clsStyle, &dce )))
1055 WARN("Bad class '%s'\n", cs->lpszClass );
1059 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1061 /* Correct the window style - stage 1
1063 * These are patches that appear to affect both the style loaded into the
1064 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1066 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1067 * why does the user get to set it?
1070 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1071 * tested for WS_POPUP
1073 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1074 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1075 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1076 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1078 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1080 /* Create the window structure */
1082 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1083 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1085 TRACE("out of memory\n" );
1088 hwnd = wndPtr->hwndSelf;
1090 /* Fill the window structure */
1092 wndPtr->tid = GetCurrentThreadId();
1093 wndPtr->owner = owner;
1094 wndPtr->parent = parent;
1095 wndPtr->class = classPtr;
1096 wndPtr->winproc = winproc;
1097 wndPtr->hInstance = cs->hInstance;
1098 wndPtr->text = NULL;
1099 wndPtr->hrgnUpdate = 0;
1100 wndPtr->hrgnWnd = 0;
1101 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1102 wndPtr->dwExStyle = cs->dwExStyle;
1103 wndPtr->clsStyle = clsStyle;
1104 wndPtr->wIDmenu = 0;
1105 wndPtr->helpContext = 0;
1106 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1107 wndPtr->pVScroll = NULL;
1108 wndPtr->pHScroll = NULL;
1109 wndPtr->userdata = 0;
1110 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1111 wndPtr->cbWndExtra = wndExtra;
1113 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1115 /* Correct the window style - stage 2 */
1117 if (!(cs->style & WS_CHILD))
1119 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1120 if (!(cs->style & WS_POPUP))
1122 wndPtr->dwStyle |= WS_CAPTION;
1123 wndPtr->flags |= WIN_NEED_SIZE;
1126 SERVER_START_REQ( set_window_info )
1129 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1130 req->style = wndPtr->dwStyle;
1131 req->ex_style = wndPtr->dwExStyle;
1132 req->instance = (void *)wndPtr->hInstance;
1133 wine_server_call( req );
1137 /* Get class or window DC if needed */
1139 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1140 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1141 else wndPtr->dce = NULL;
1143 /* Set the window menu */
1145 if ((wndPtr->dwStyle & WS_CAPTION || wndPtr->dwExStyle & WS_EX_APPWINDOW)
1146 && !( wndPtr->dwStyle & WS_CHILD) )
1148 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1151 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1154 if (HIWORD(cs->hInstance))
1155 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1157 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1159 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1163 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1164 WIN_ReleaseWndPtr( wndPtr );
1166 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1168 WIN_DestroyWindow( hwnd );
1172 /* Notify the parent window only */
1174 send_parent_notify( hwnd, WM_CREATE );
1175 if (!IsWindow( hwnd )) return 0;
1177 if (cs->style & WS_VISIBLE)
1179 /* in case WS_VISIBLE got set in the meantime */
1180 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1181 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1182 WIN_ReleasePtr( wndPtr );
1183 ShowWindow( hwnd, sw );
1186 /* Call WH_SHELL hook */
1188 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1189 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1191 TRACE("created window %p\n", hwnd);
1196 /***********************************************************************
1197 * CreateWindow (USER.41)
1199 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1200 DWORD style, INT16 x, INT16 y, INT16 width,
1201 INT16 height, HWND16 parent, HMENU16 menu,
1202 HINSTANCE16 instance, LPVOID data )
1204 return CreateWindowEx16( 0, className, windowName, style,
1205 x, y, width, height, parent, menu, instance, data );
1209 /***********************************************************************
1210 * CreateWindowEx (USER.452)
1212 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1213 LPCSTR windowName, DWORD style, INT16 x,
1214 INT16 y, INT16 width, INT16 height,
1215 HWND16 parent, HMENU16 menu,
1216 HINSTANCE16 instance, LPVOID data )
1222 /* Find the class atom */
1224 if (HIWORD(className))
1226 if (!(classAtom = GlobalFindAtomA( className )))
1228 ERR( "bad class name %s\n", debugstr_a(className) );
1234 classAtom = LOWORD(className);
1235 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1237 ERR( "bad atom %x\n", classAtom);
1243 /* Fix the coordinates */
1245 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1246 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1247 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1248 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1250 /* Create the window */
1252 cs.lpCreateParams = data;
1253 cs.hInstance = HINSTANCE_32(instance);
1254 cs.hMenu = HMENU_32(menu);
1255 cs.hwndParent = WIN_Handle32( parent );
1257 cs.lpszName = windowName;
1258 cs.lpszClass = className;
1259 cs.dwExStyle = exStyle;
1261 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1265 /***********************************************************************
1266 * CreateWindowExA (USER32.@)
1268 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1269 LPCSTR windowName, DWORD style, INT x,
1270 INT y, INT width, INT height,
1271 HWND parent, HMENU menu,
1272 HINSTANCE instance, LPVOID data )
1279 instance=GetModuleHandleA(NULL);
1281 if(exStyle & WS_EX_MDICHILD)
1282 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1284 /* Find the class atom */
1286 if (HIWORD(className))
1288 if (!(classAtom = GlobalFindAtomA( className )))
1290 ERR( "bad class name %s\n", debugstr_a(className) );
1296 classAtom = LOWORD(className);
1297 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1299 ERR( "bad atom %x\n", classAtom);
1305 /* Create the window */
1307 cs.lpCreateParams = data;
1308 cs.hInstance = instance;
1310 cs.hwndParent = parent;
1316 cs.lpszName = windowName;
1317 cs.lpszClass = className;
1318 cs.dwExStyle = exStyle;
1320 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1324 /***********************************************************************
1325 * CreateWindowExW (USER32.@)
1327 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1328 LPCWSTR windowName, DWORD style, INT x,
1329 INT y, INT width, INT height,
1330 HWND parent, HMENU menu,
1331 HINSTANCE instance, LPVOID data )
1338 instance=GetModuleHandleW(NULL);
1340 if(exStyle & WS_EX_MDICHILD)
1341 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1343 /* Find the class atom */
1345 if (HIWORD(className))
1347 if (!(classAtom = GlobalFindAtomW( className )))
1349 ERR( "bad class name %s\n", debugstr_w(className) );
1355 classAtom = LOWORD(className);
1356 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1358 ERR( "bad atom %x\n", classAtom);
1364 /* Create the window */
1366 cs.lpCreateParams = data;
1367 cs.hInstance = instance;
1369 cs.hwndParent = parent;
1375 cs.lpszName = windowName;
1376 cs.lpszClass = className;
1377 cs.dwExStyle = exStyle;
1379 /* Note: we rely on the fact that CREATESTRUCTA and */
1380 /* CREATESTRUCTW have the same layout. */
1381 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1385 /***********************************************************************
1386 * WIN_SendDestroyMsg
1388 static void WIN_SendDestroyMsg( HWND hwnd )
1392 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1394 if (hwnd == info.hwndCaret) 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("(%p)\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_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) 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_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
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("( %p, %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 %p\n", offset, hwnd );
1771 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1774 if (offset > (int)(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 %p\n",
1831 offset, newval, hwnd );
1836 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1840 if (offset > (int)(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 %p\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 > (int)(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( (WNDPROC)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 = (LONG)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( "%p %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 > (int)(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( (WNDPROC)*ptr, type );
2019 WINPROC_SetProc( (WNDPROC *)ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2020 WIN_ReleasePtr( wndPtr );
2025 WIN_ReleasePtr( wndPtr );
2032 /* first some special cases */
2037 style.styleOld = wndPtr->dwStyle;
2038 style.styleNew = newval;
2039 WIN_ReleasePtr( wndPtr );
2040 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2041 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2042 newval = style.styleNew;
2044 case GWL_HWNDPARENT:
2045 if (wndPtr->parent == GetDesktopWindow())
2047 WIN_ReleasePtr( wndPtr );
2048 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2052 WIN_ReleasePtr( wndPtr );
2053 return (LONG)SetParent( hwnd, (HWND)newval );
2056 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2057 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2058 WIN_ReleasePtr( wndPtr );
2065 WIN_ReleasePtr( wndPtr );
2066 WARN("Invalid offset %d\n", offset );
2067 SetLastError( ERROR_INVALID_INDEX );
2071 SERVER_START_REQ( set_window_info )
2077 req->flags = SET_WIN_STYLE;
2078 req->style = newval;
2081 req->flags = SET_WIN_EXSTYLE;
2082 req->ex_style = newval;
2085 req->flags = SET_WIN_ID;
2089 req->flags = SET_WIN_INSTANCE;
2090 req->instance = (void *)newval;
2093 req->flags = SET_WIN_USERDATA;
2094 req->user_data = (void *)newval;
2097 if ((ok = !wine_server_call_err( req )))
2102 wndPtr->dwStyle = newval;
2103 retval = reply->old_style;
2106 wndPtr->dwExStyle = newval;
2107 retval = reply->old_ex_style;
2110 wndPtr->wIDmenu = newval;
2111 retval = reply->old_id;
2114 wndPtr->hInstance = (HINSTANCE)newval;
2115 retval = (ULONG_PTR)reply->old_instance;
2118 wndPtr->userdata = newval;
2119 retval = (ULONG_PTR)reply->old_user_data;
2125 WIN_ReleasePtr( wndPtr );
2129 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2130 USER_Driver.pSetWindowStyle( hwnd, retval );
2132 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2133 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2140 /**********************************************************************
2141 * GetWindowLong (USER.135)
2143 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2145 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2149 /**********************************************************************
2150 * GetWindowLongA (USER32.@)
2152 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2154 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2158 /**********************************************************************
2159 * GetWindowLongW (USER32.@)
2161 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2163 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2167 /**********************************************************************
2168 * SetWindowLong (USER.136)
2170 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2172 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2176 /**********************************************************************
2177 * SetWindowLongA (USER32.@)
2179 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2181 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2185 /**********************************************************************
2186 * SetWindowLongW (USER32.@) Set window attribute
2188 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2189 * value in a window's extra memory.
2191 * The _hwnd_ parameter specifies the window. is the handle to a
2192 * window that has extra memory. The _newval_ parameter contains the
2193 * new attribute or extra memory value. If positive, the _offset_
2194 * parameter is the byte-addressed location in the window's extra
2195 * memory to set. If negative, _offset_ specifies the window
2196 * attribute to set, and should be one of the following values:
2198 * GWL_EXSTYLE The window's extended window style
2200 * GWL_STYLE The window's window style.
2202 * GWL_WNDPROC Pointer to the window's window procedure.
2204 * GWL_HINSTANCE The window's pplication instance handle.
2206 * GWL_ID The window's identifier.
2208 * GWL_USERDATA The window's user-specified data.
2210 * If the window is a dialog box, the _offset_ parameter can be one of
2211 * the following values:
2213 * DWL_DLGPROC The address of the window's dialog box procedure.
2215 * DWL_MSGRESULT The return value of a message
2216 * that the dialog box procedure processed.
2218 * DWL_USER Application specific information.
2222 * If successful, returns the previous value located at _offset_. Otherwise,
2227 * Extra memory for a window class is specified by a nonzero cbWndExtra
2228 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2229 * time of class creation.
2231 * Using GWL_WNDPROC to set a new window procedure effectively creates
2232 * a window subclass. Use CallWindowProc() in the new windows procedure
2233 * to pass messages to the superclass's window procedure.
2235 * The user data is reserved for use by the application which created
2238 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2239 * instead, call the EnableWindow() function to change the window's
2242 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2243 * SetParent() instead.
2246 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2247 * it sends WM_STYLECHANGING before changing the settings
2248 * and WM_STYLECHANGED afterwards.
2249 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2251 LONG WINAPI SetWindowLongW(
2252 HWND hwnd, /* [in] window to alter */
2253 INT offset, /* [in] offset, in bytes, of location to alter */
2254 LONG newval /* [in] new value of location */
2256 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2260 /*******************************************************************
2261 * GetWindowTextA (USER32.@)
2263 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2267 if (WIN_IsCurrentProcess( hwnd ))
2268 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2270 /* when window belongs to other process, don't send a message */
2271 if (nMaxCount <= 0) return 0;
2272 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2273 get_server_window_text( hwnd, buffer, nMaxCount );
2274 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2275 lpString[nMaxCount-1] = 0;
2276 HeapFree( GetProcessHeap(), 0, buffer );
2277 return strlen(lpString);
2281 /*******************************************************************
2282 * InternalGetWindowText (USER32.@)
2284 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2288 if (nMaxCount <= 0) return 0;
2289 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2290 if (win != WND_OTHER_PROCESS)
2292 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2293 else lpString[0] = 0;
2294 WIN_ReleasePtr( win );
2298 get_server_window_text( hwnd, lpString, nMaxCount );
2300 return strlenW(lpString);
2304 /*******************************************************************
2305 * GetWindowTextW (USER32.@)
2307 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2309 if (WIN_IsCurrentProcess( hwnd ))
2310 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2312 /* when window belongs to other process, don't send a message */
2313 if (nMaxCount <= 0) return 0;
2314 get_server_window_text( hwnd, lpString, nMaxCount );
2315 return strlenW(lpString);
2319 /*******************************************************************
2320 * SetWindowText (USER32.@)
2321 * SetWindowTextA (USER32.@)
2323 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2325 if (!WIN_IsCurrentProcess( hwnd ))
2327 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2328 SetLastError( ERROR_ACCESS_DENIED );
2331 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2335 /*******************************************************************
2336 * SetWindowTextW (USER32.@)
2338 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2340 if (!WIN_IsCurrentProcess( hwnd ))
2342 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2343 SetLastError( ERROR_ACCESS_DENIED );
2346 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2350 /*******************************************************************
2351 * GetWindowTextLengthA (USER32.@)
2353 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2355 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2358 /*******************************************************************
2359 * GetWindowTextLengthW (USER32.@)
2361 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2363 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2367 /*******************************************************************
2368 * IsWindow (USER32.@)
2370 BOOL WINAPI IsWindow( HWND hwnd )
2375 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2377 if (ptr != WND_OTHER_PROCESS)
2379 WIN_ReleasePtr( ptr );
2383 /* check other processes */
2384 SERVER_START_REQ( get_window_info )
2387 ret = !wine_server_call_err( req );
2394 /***********************************************************************
2395 * GetWindowThreadProcessId (USER32.@)
2397 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2402 if (!(ptr = WIN_GetPtr( hwnd )))
2404 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2408 if (ptr != WND_OTHER_PROCESS)
2410 /* got a valid window */
2412 if (process) *process = GetCurrentProcessId();
2413 WIN_ReleasePtr( ptr );
2417 /* check other processes */
2418 SERVER_START_REQ( get_window_info )
2421 if (!wine_server_call_err( req ))
2423 tid = (DWORD)reply->tid;
2424 if (process) *process = (DWORD)reply->pid;
2432 /*****************************************************************
2433 * GetParent (USER32.@)
2435 HWND WINAPI GetParent( HWND hwnd )
2440 if (!(wndPtr = WIN_GetPtr( hwnd )))
2442 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2445 if (wndPtr == WND_OTHER_PROCESS)
2447 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2448 if (style & (WS_POPUP | WS_CHILD))
2450 SERVER_START_REQ( get_window_tree )
2453 if (!wine_server_call_err( req ))
2455 if (style & WS_POPUP) retvalue = reply->owner;
2456 else if (style & WS_CHILD) retvalue = reply->parent;
2464 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2465 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2466 WIN_ReleasePtr( wndPtr );
2472 /*****************************************************************
2473 * GetAncestor (USER32.@)
2475 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2478 HWND *list, ret = 0;
2483 if (!(win = WIN_GetPtr( hwnd )))
2485 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2488 if (win != WND_OTHER_PROCESS)
2491 WIN_ReleasePtr( win );
2493 else /* need to query the server */
2495 SERVER_START_REQ( get_window_tree )
2498 if (!wine_server_call_err( req )) ret = reply->parent;
2505 if (!(list = WIN_ListParents( hwnd ))) return 0;
2507 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2511 while (list[count]) count++;
2512 ret = list[count - 2]; /* get the one before the desktop */
2514 HeapFree( GetProcessHeap(), 0, list );
2518 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2521 HWND parent = GetParent( ret );
2531 /*****************************************************************
2532 * SetParent (USER32.@)
2534 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2537 HWND retvalue, full_handle;
2540 if (!parent) parent = GetDesktopWindow();
2541 else parent = WIN_GetFullHandle( parent );
2543 if (!IsWindow( parent ))
2545 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2549 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2550 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2554 if (USER_Driver.pSetParent)
2555 return USER_Driver.pSetParent( hwnd, parent );
2557 /* Windows hides the window first, then shows it again
2558 * including the WM_SHOWWINDOW messages and all */
2559 was_visible = ShowWindow( hwnd, SW_HIDE );
2561 if (!IsWindow( parent )) return 0;
2562 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2564 retvalue = wndPtr->parent; /* old parent */
2565 if (parent != retvalue)
2567 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2569 if (parent != GetDesktopWindow()) /* a child window */
2571 if (!(wndPtr->dwStyle & WS_CHILD))
2573 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2574 if (menu) DestroyMenu( menu );
2578 WIN_ReleasePtr( wndPtr );
2580 /* SetParent additionally needs to make hwnd the topmost window
2581 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2582 WM_WINDOWPOSCHANGED notification messages.
2584 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2585 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2586 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2587 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2592 /*******************************************************************
2593 * IsChild (USER32.@)
2595 BOOL WINAPI IsChild( HWND parent, HWND child )
2597 HWND *list = WIN_ListParents( child );
2601 if (!list) return FALSE;
2602 parent = WIN_GetFullHandle( parent );
2603 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2604 ret = (list[i] != 0);
2605 HeapFree( GetProcessHeap(), 0, list );
2610 /***********************************************************************
2611 * IsWindowVisible (USER32.@)
2613 BOOL WINAPI IsWindowVisible( HWND hwnd )
2619 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2620 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2621 for (i = 0; list[i]; i++)
2622 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2624 HeapFree( GetProcessHeap(), 0, list );
2629 /***********************************************************************
2630 * WIN_IsWindowDrawable
2632 * hwnd is drawable when it is visible, all parents are not
2633 * minimized, and it is itself not minimized unless we are
2634 * trying to draw its default class icon.
2636 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2641 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2643 if (!(style & WS_VISIBLE)) return FALSE;
2644 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2646 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2647 for (i = 0; list[i]; i++)
2648 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2651 HeapFree( GetProcessHeap(), 0, list );
2656 /*******************************************************************
2657 * GetTopWindow (USER32.@)
2659 HWND WINAPI GetTopWindow( HWND hwnd )
2661 if (!hwnd) hwnd = GetDesktopWindow();
2662 return GetWindow( hwnd, GW_CHILD );
2666 /*******************************************************************
2667 * GetWindow (USER32.@)
2669 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2673 if (rel == GW_OWNER) /* this one may be available locally */
2675 WND *wndPtr = WIN_GetPtr( hwnd );
2678 SetLastError( ERROR_INVALID_HANDLE );
2681 if (wndPtr != WND_OTHER_PROCESS)
2683 retval = wndPtr->owner;
2684 WIN_ReleasePtr( wndPtr );
2687 /* else fall through to server call */
2690 SERVER_START_REQ( get_window_tree )
2693 if (!wine_server_call_err( req ))
2698 retval = reply->first_sibling;
2701 retval = reply->last_sibling;
2704 retval = reply->next_sibling;
2707 retval = reply->prev_sibling;
2710 retval = reply->owner;
2713 retval = reply->first_child;
2723 /***********************************************************************
2724 * WIN_InternalShowOwnedPopups
2726 * Internal version of ShowOwnedPopups; Wine functions should use this
2727 * to avoid interfering with application calls to ShowOwnedPopups
2728 * and to make sure the application can't prevent showing/hiding.
2730 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2734 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2738 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2740 if (!win_array) return TRUE;
2743 * Show windows Lowest first, Highest last to preserve Z-Order
2745 while (win_array[count]) count++;
2746 while (--count >= 0)
2748 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2749 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2751 if (pWnd->dwStyle & WS_POPUP)
2755 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2756 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2759 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2761 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2762 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2767 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2768 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2769 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2772 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2774 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2775 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2776 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2780 WIN_ReleaseWndPtr( pWnd );
2782 HeapFree( GetProcessHeap(), 0, win_array );
2787 /*******************************************************************
2788 * ShowOwnedPopups (USER32.@)
2790 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2794 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2796 if (!win_array) return TRUE;
2798 while (win_array[count]) count++;
2799 while (--count >= 0)
2801 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2802 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2804 if (pWnd->dwStyle & WS_POPUP)
2808 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2810 /* In Windows, ShowOwnedPopups(TRUE) generates
2811 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2812 * regardless of the state of the owner
2814 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2815 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2820 if (IsWindowVisible(pWnd->hwndSelf))
2822 /* In Windows, ShowOwnedPopups(FALSE) generates
2823 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2824 * regardless of the state of the owner
2826 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2827 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2831 WIN_ReleaseWndPtr( pWnd );
2833 HeapFree( GetProcessHeap(), 0, win_array );
2838 /*******************************************************************
2839 * GetLastActivePopup (USER32.@)
2841 HWND WINAPI GetLastActivePopup( HWND hwnd )
2845 SERVER_START_REQ( get_window_info )
2848 if (!wine_server_call_err( req )) retval = reply->last_active;
2855 /*******************************************************************
2858 * Build an array of all parents of a given window, starting with
2859 * the immediate parent. The array must be freed with HeapFree.
2860 * Returns NULL if window is a top-level window.
2862 HWND *WIN_ListParents( HWND hwnd )
2865 HWND current, *list;
2866 int pos = 0, size = 16, count = 0;
2868 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2873 if (!(win = WIN_GetPtr( current ))) goto empty;
2874 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2875 list[pos] = win->parent;
2876 WIN_ReleasePtr( win );
2877 if (!(current = list[pos]))
2879 if (!pos) goto empty;
2882 if (++pos == size - 1)
2884 /* need to grow the list */
2885 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2886 if (!new_list) goto empty;
2892 /* at least one parent belongs to another process, have to query the server */
2897 SERVER_START_REQ( get_window_parents )
2900 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2901 if (!wine_server_call( req )) count = reply->count;
2904 if (!count) goto empty;
2910 HeapFree( GetProcessHeap(), 0, list );
2912 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2916 HeapFree( GetProcessHeap(), 0, list );
2921 /*******************************************************************
2924 * Build an array of the children of a given window. The array must be
2925 * freed with HeapFree. Returns NULL when no windows are found.
2927 HWND *WIN_ListChildren( HWND hwnd )
2929 return list_window_children( hwnd, 0, 0 );
2933 /*******************************************************************
2934 * EnumWindows (USER32.@)
2936 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2942 /* We have to build a list of all windows first, to avoid */
2943 /* unpleasant side-effects, for instance if the callback */
2944 /* function changes the Z-order of the windows. */
2946 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2948 /* Now call the callback function for every window */
2950 iWndsLocks = WIN_SuspendWndsLock();
2951 for (i = 0; list[i]; i++)
2953 /* Make sure that the window still exists */
2954 if (!IsWindow( list[i] )) continue;
2955 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2957 WIN_RestoreWndsLock(iWndsLocks);
2958 HeapFree( GetProcessHeap(), 0, list );
2963 /**********************************************************************
2964 * EnumThreadWindows (USER32.@)
2966 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2971 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2973 /* Now call the callback function for every window */
2975 iWndsLocks = WIN_SuspendWndsLock();
2976 for (i = 0; list[i]; i++)
2977 if (!func( list[i], lParam )) break;
2978 WIN_RestoreWndsLock(iWndsLocks);
2979 HeapFree( GetProcessHeap(), 0, list );
2984 /**********************************************************************
2985 * WIN_EnumChildWindows
2987 * Helper function for EnumChildWindows().
2989 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2994 for ( ; *list; list++)
2996 /* Make sure that the window still exists */
2997 if (!IsWindow( *list )) continue;
2998 /* skip owned windows */
2999 if (GetWindow( *list, GW_OWNER )) continue;
3000 /* Build children list first */
3001 childList = WIN_ListChildren( *list );
3003 ret = func( *list, lParam );
3007 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3008 HeapFree( GetProcessHeap(), 0, childList );
3010 if (!ret) return FALSE;
3016 /**********************************************************************
3017 * EnumChildWindows (USER32.@)
3019 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3024 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3025 iWndsLocks = WIN_SuspendWndsLock();
3026 WIN_EnumChildWindows( list, func, lParam );
3027 WIN_RestoreWndsLock(iWndsLocks);
3028 HeapFree( GetProcessHeap(), 0, list );
3033 /*******************************************************************
3034 * AnyPopup (USER.52)
3036 BOOL16 WINAPI AnyPopup16(void)
3042 /*******************************************************************
3043 * AnyPopup (USER32.@)
3045 BOOL WINAPI AnyPopup(void)
3049 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3051 if (!list) return FALSE;
3052 for (i = 0; list[i]; i++)
3054 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3056 retvalue = (list[i] != 0);
3057 HeapFree( GetProcessHeap(), 0, list );
3062 /*******************************************************************
3063 * FlashWindow (USER32.@)
3065 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3067 WND *wndPtr = WIN_FindWndPtr(hWnd);
3069 TRACE("%p\n", hWnd);
3071 if (!wndPtr) return FALSE;
3072 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3074 if (wndPtr->dwStyle & WS_MINIMIZE)
3076 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3078 HDC hDC = GetDC(hWnd);
3080 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3081 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3083 ReleaseDC( hWnd, hDC );
3084 wndPtr->flags |= WIN_NCACTIVATED;
3088 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3089 wndPtr->flags &= ~WIN_NCACTIVATED;
3091 WIN_ReleaseWndPtr(wndPtr);
3097 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3098 else wparam = (hWnd == GetForegroundWindow());
3100 WIN_ReleaseWndPtr(wndPtr);
3101 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3107 /*******************************************************************
3108 * GetWindowContextHelpId (USER32.@)
3110 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3113 WND *wnd = WIN_FindWndPtr( hwnd );
3115 retval = wnd->helpContext;
3116 WIN_ReleaseWndPtr(wnd);
3121 /*******************************************************************
3122 * SetWindowContextHelpId (USER32.@)
3124 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3126 WND *wnd = WIN_FindWndPtr( hwnd );
3127 if (!wnd) return FALSE;
3128 wnd->helpContext = id;
3129 WIN_ReleaseWndPtr(wnd);
3134 /*******************************************************************
3135 * DragDetect (USER32.@)
3137 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3142 rect.left = pt.x - wDragWidth;
3143 rect.right = pt.x + wDragWidth;
3145 rect.top = pt.y - wDragHeight;
3146 rect.bottom = pt.y + wDragHeight;
3152 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3154 if( msg.message == WM_LBUTTONUP )
3159 if( msg.message == WM_MOUSEMOVE )
3162 tmp.x = LOWORD(msg.lParam);
3163 tmp.y = HIWORD(msg.lParam);
3164 if( !PtInRect( &rect, tmp ))
3176 /******************************************************************************
3177 * GetWindowModuleFileNameA (USER32.@)
3179 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3181 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3182 hwnd, lpszFileName, cchFileNameMax);
3186 /******************************************************************************
3187 * GetWindowModuleFileNameW (USER32.@)
3189 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3191 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3192 hwnd, lpszFileName, cchFileNameMax);
3196 /******************************************************************************
3197 * GetWindowInfo (USER32.@)
3200 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3201 * this may be because this structure changed over time. If this is the
3202 * the case, then please: FIXME.
3203 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3205 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3207 WND *wndInfo = NULL;
3208 if (!pwi) return FALSE;
3209 if (pwi->cbSize != sizeof(WINDOWINFO))
3211 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3214 wndInfo = WIN_GetPtr(hwnd);
3215 if (!wndInfo) return FALSE;
3216 if (wndInfo == WND_OTHER_PROCESS)
3218 FIXME("window belong to other process\n");
3222 pwi->rcWindow = wndInfo->rectWindow;
3223 pwi->rcClient = wndInfo->rectClient;
3224 pwi->dwStyle = wndInfo->dwStyle;
3225 pwi->dwExStyle = wndInfo->dwExStyle;
3226 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3227 /* if active WS_ACTIVECAPTION, else 0 */
3229 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3230 GetSystemMetrics(SM_CXBORDER) : 0);
3231 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3232 GetSystemMetrics(SM_CYBORDER) : 0);
3233 /* above two: I'm presuming that borders widths are the same
3234 * for each window - so long as its actually using a border.. */
3236 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3237 pwi->wCreatorVersion = GetVersion();
3238 /* Docs say this should be the version that
3239 * CREATED the window. But eh?.. Isn't that just the
3240 * version we are running.. Unless ofcourse its some wacky
3241 * RPC stuff or something */
3243 WIN_ReleasePtr(wndInfo);